From 6e4437255b603b5b25360481507099dd9b92f942 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 6 Sep 2013 12:29:06 +1000 Subject: [PATCH 001/160] GDISP revamp - stage 1 New low level driver interface: Only Win32 ported currently Significant reduction in GDISP stack usage Improved performance particularly for native streaming drivers New circle, ellipse, arc routines (draw and fill) that are significantly more efficient and don't overdraw New arc draw algorithm that measures angles correctly. New arc fill algorithm for that actually works without overdrawing or gaps. Much more to come... --- drivers/multiple/Win32/gdisp_lld.c | 346 ++-- drivers/multiple/Win32/gdisp_lld_config.h | 20 +- include/gdisp/gdisp.h | 552 +++--- include/gdisp/lld/emulation.c | 558 ------ include/gdisp/lld/gdisp_lld.h | 204 +- include/gmisc/gmisc.h | 1 + src/gdisp/gdisp.c | 2149 ++++++++++++++++----- 7 files changed, 2130 insertions(+), 1700 deletions(-) delete mode 100644 include/gdisp/lld/emulation.c diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 0bac0fde..91b86616 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -17,6 +17,13 @@ #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#include "gdisp/lld/gdisp_lld.h" + +// Declare our driver object +GDISPDriver GDISP_Win32; + +#define GC (&GDISP_Win32) + #include #include #include @@ -45,9 +52,6 @@ #include "ginput/lld/mouse.h" #endif -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" - /*===========================================================================*/ /* Driver local routines . */ /*===========================================================================*/ @@ -329,86 +333,59 @@ bool_t gdisp_lld_init(void) { Sleep(1); /* Initialise the GDISP structure to match */ - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = 100; - GDISP.Contrast = 50; - GDISP.Width = wWidth; - GDISP.Height = wHeight; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + GC->g.Orientation = GDISP_ROTATE_0; + GC->g.Powermode = powerOn; + GC->g.Backlight = 100; + GC->g.Contrast = 50; + GC->g.Width = wWidth; + GC->g.Height = wHeight; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - HDC dc; - #if WIN32_USE_MSG_REDRAW - RECT rect; - #endif - #if GDISP_NEED_CONTROL - coord_t t; - #endif - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - // Clip pre orientation change - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - break; - case GDISP_ROTATE_90: - t = GDISP.Height - 1 - y; - y = x; - x = t; - break; - case GDISP_ROTATE_180: - x = GDISP.Width - 1 - x; - y = GDISP.Height - 1 - y; - break; - case GDISP_ROTATE_270: - t = GDISP.Width - 1 - x; - x = y; - y = t; - break; - } - #endif +#if GDISP_HARDWARE_DRAWPIXEL + void gdisp_lld_draw_pixel(void) { + HDC dcScreen; + int x, y; + COLORREF color; - // Draw the pixel in the buffer - color = COLOR2BGR(color); - SetPixel(dcBuffer, x, y, color); + color = COLOR2BGR(GC->p.color); - #if WIN32_USE_MSG_REDRAW - rect.left = x; rect.right = x+1; - rect.top = y; rect.bottom = y+1; - InvalidateRect(winRootWindow, &rect, FALSE); - UpdateWindow(winRootWindow); - #else - // Draw the pixel again directly on the screen. - // This is cheaper than invalidating a single pixel in the window - dc = GetDC(winRootWindow); - SetPixel(dc, x, y, color); - ReleaseDC(winRootWindow, dc); - #endif -} + #if GDISP_NEED_CONTROL + switch(GC->g.Orientation) { + case GDISP_ROTATE_0: + x = GC->p.x; + y = GC->p.y; + break; + case GDISP_ROTATE_90: + x = GC->g.Height - 1 - GC->p.y; + y = GC->p.x; + break; + case GDISP_ROTATE_180: + x = GC->g.Width - 1 - GC->p.x; + y = GC->g.Height - 1 - GC->p.y; + break; + case GDISP_ROTATE_270: + x = GC->p.y; + y = GC->g.Width - 1 - GC->p.x; + break; + } + #else + x = GC->p.x; + y = GC->p.y; + #endif + + // Draw the pixel on the screen and in the buffer. + dcScreen = GetDC(winRootWindow); + SetPixel(dcScreen, x, y, color); + SetPixel(dcBuffer, x, y, color); + ReleaseDC(winRootWindow, dcScreen); + } +#endif /* ---- Optional Routines ---- */ -#if GDISP_HARDWARE_LINES || defined(__DOXYGEN__) +#if 0 +#if GDISP_HARDWARE_LINES /** * @brief Draw a line. * @note Optional - The high level driver can emulate using software. @@ -439,57 +416,57 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { #endif #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: #if GDISP_NEED_CLIP // Clip post orientation change - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.clipx0, GDISP.clipy0, GDISP.clipx1, GDISP.clipy1); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.clipx0, GC->g.clipy0, GC->g.clipx1, GC->g.clipy1); #endif break; case GDISP_ROTATE_90: - t = GDISP.Height - 1 - y0; + t = GC->g.Height - 1 - y0; y0 = x0; x0 = t; - t = GDISP.Height - 1 - y1; + t = GC->g.Height - 1 - y1; y1 = x1; x1 = t; #if GDISP_NEED_CLIP // Clip post orientation change - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.Height-1-GDISP.clipy1, GDISP.clipx0, GDISP.Height-1-GDISP.clipy0, GDISP.clipx1); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.Height-1-GC->g.clipy1, GC->g.clipx0, GC->g.Height-1-GC->g.clipy0, GC->g.clipx1); #endif break; case GDISP_ROTATE_180: - x0 = GDISP.Width - 1 - x0; - y0 = GDISP.Height - 1 - y0; - x1 = GDISP.Width - 1 - x1; - y1 = GDISP.Height - 1 - y1; + x0 = GC->g.Width - 1 - x0; + y0 = GC->g.Height - 1 - y0; + x1 = GC->g.Width - 1 - x1; + y1 = GC->g.Height - 1 - y1; #if GDISP_NEED_CLIP // Clip post orientation change - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.Width-1-GDISP.clipx1, GDISP.Height-1-GDISP.clipy1, GDISP.Width-1-GDISP.clipx0, GDISP.Height-1-GDISP.clipy0); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.Width-1-GC->g.clipx1, GC->g.Height-1-GC->g.clipy1, GC->g.Width-1-GC->g.clipx0, GC->g.Height-1-GC->g.clipy0); #endif break; case GDISP_ROTATE_270: - t = GDISP.Width - 1 - x0; + t = GC->g.Width - 1 - x0; x0 = y0; y0 = t; - t = GDISP.Width - 1 - x1; + t = GC->g.Width - 1 - x1; x1 = y1; y1 = t; #if GDISP_NEED_CLIP // Clip post orientation change - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.clipy0, GDISP.Width-1-GDISP.clipx1, GDISP.clipy1, GDISP.Width-1-GDISP.clipx0); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.clipy0, GC->g.Width-1-GC->g.clipx1, GC->g.clipy1, GC->g.Width-1-GC->g.clipx0); #endif break; } #else #if GDISP_NEED_CLIP clip = NULL; - if (GDISP.clipx0 != 0 || GDISP.clipy0 != 0 || GDISP.clipx1 != GDISP.Width || GDISP.clipy1 != GDISP.Height) - clip = CreateRectRgn(GDISP.clipx0, GDISP.clipy0, GDISP.clipx1, GDISP.clipy1); + if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) + clip = CreateRectRgn(GC->g.clipx0, GC->g.clipy0, GC->g.clipx1, GC->g.clipy1); #endif #endif @@ -535,85 +512,58 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { } } #endif +#endif -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - HDC dc; - RECT rect; - HBRUSH hbr; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - // Clip pre orientation change - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif +#if GDISP_HARDWARE_FILLS + void gdisp_lld_fill_area(void) { + HDC dcScreen; + RECT rect; + HBRUSH hbr; + COLORREF color; + color = COLOR2BGR(GC->p.color); #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: - rect.top = y; - rect.bottom = rect.top+cy; - rect.left = x; - rect.right = rect.left+cx; + rect.top = GC->p.y; + rect.bottom = rect.top + GC->p.cy; + rect.left = GC->p.x; + rect.right = rect.left + GC->p.cx; break; case GDISP_ROTATE_90: - rect.top = x; - rect.bottom = rect.top+cx; - rect.right = GDISP.Height - y; - rect.left = rect.right-cy; + rect.top = GC->p.x; + rect.bottom = rect.top + GC->p.cx; + rect.right = GC->g.Height - GC->p.y; + rect.left = rect.right - GC->p.cy; break; case GDISP_ROTATE_180: - rect.bottom = GDISP.Height - y; - rect.top = rect.bottom-cy; - rect.right = GDISP.Width - x; - rect.left = rect.right-cx; + rect.bottom = GC->g.Height - GC->p.y; + rect.top = rect.bottom - GC->p.cy; + rect.right = GC->g.Width - GC->p.x; + rect.left = rect.right - GC->p.cx; break; case GDISP_ROTATE_270: - rect.bottom = GDISP.Width - x; - rect.top = rect.bottom-cx; - rect.left = y; - rect.right = rect.left+cy; + rect.bottom = GC->g.Width - GC->p.x; + rect.top = rect.bottom - GC->p.cx; + rect.left = GC->p.y; + rect.right = rect.left + GC->p.cy; break; } #else - rect.top = y; - rect.bottom = rect.top+cy; - rect.left = x; - rect.right = rect.left+cx; + rect.top = GC->p.y; + rect.bottom = rect.top + GC->p.cy; + rect.left = GC->p.x; + rect.right = rect.left + GC->p.cx; #endif - color = COLOR2BGR(color); hbr = CreateSolidBrush(color); - if (hbr) { - // Fill the area - FillRect(dcBuffer, &rect, hbr); + dcScreen = GetDC(winRootWindow); + FillRect(dcScreen, &rect, hbr); + FillRect(dcBuffer, &rect, hbr); + ReleaseDC(winRootWindow, dcScreen); - #if WIN32_USE_MSG_REDRAW - InvalidateRect(winRootWindow, &rect, FALSE); - UpdateWindow(winRootWindow); - #else - // Filling the area directly on the screen is likely to be cheaper than invalidating it - dc = GetDC(winRootWindow); - FillRect(dc, &rect, hbr); - ReleaseDC(winRootWindow, dc); - #endif - - DeleteObject(hbr); - } + DeleteObject(hbr); } #endif @@ -626,7 +576,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { coord_t i, j; // Shortcut. - if (GDISP.Orientation == GDISP_ROTATE_0 && srcx == 0 && cx == srccx) + if (GC->g.Orientation == GDISP_ROTATE_0 && srcx == 0 && cx == srccx) return (pixel_t *)buffer; // Allocate the destination buffer @@ -635,7 +585,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { return 0; // Copy the bits we need - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: for(dst = dstbuf, src = buffer+srcx, j = 0; j < cy; j++) for(i = 0; i < cx; i++, src += srccx - cx) @@ -665,7 +615,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { } #endif -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) +#if GDISP_HARDWARE_BITFILLS /** * @brief Fill an area with a bitmap. * @note Optional - The high level driver can emulate using software. @@ -687,12 +637,12 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP // Clip pre orientation change - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } + if (x < GC->g.clipx0) { cx -= GC->g.clipx0 - x; srcx += GC->g.clipx0 - x; x = GC->g.clipx0; } + if (y < GC->g.clipy0) { cy -= GC->g.clipy0 - y; srcy += GC->g.clipy0 - y; y = GC->g.clipy0; } if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; + if (cx <= 0 || cy <= 0 || x >= GC->g.clipx1 || y >= GC->g.clipy1) return; + if (x+cx > GC->g.clipx1) cx = GC->g.clipx1 - x; + if (y+cy > GC->g.clipy1) cy = GC->g.clipy1 - y; #endif // Make everything relative to the start of the line @@ -719,7 +669,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { srcimg = rotateimg(cx, cy, srcx, srccx, buffer); if (!srcimg) return; - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: bmpInfo.bV4Width = cx; bmpInfo.bV4Height = -cy; /* top-down image */ @@ -733,21 +683,21 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { bmpInfo.bV4Height = -cx; /* top-down image */ rect.top = x; rect.bottom = rect.top+cx; - rect.right = GDISP.Height - y; + rect.right = GC->g.Height - y; rect.left = rect.right-cy; break; case GDISP_ROTATE_180: bmpInfo.bV4Width = cx; bmpInfo.bV4Height = -cy; /* top-down image */ - rect.bottom = GDISP.Height - y; + rect.bottom = GC->g.Height - y; rect.top = rect.bottom-cy; - rect.right = GDISP.Width - x; + rect.right = GC->g.Width - x; rect.left = rect.right-cx; break; case GDISP_ROTATE_270: bmpInfo.bV4Width = cy; bmpInfo.bV4Height = -cx; /* top-down image */ - rect.bottom = GDISP.Width - x; + rect.bottom = GC->g.Width - x; rect.top = rect.bottom-cx; rect.left = y; rect.right = rect.left+cy; @@ -793,24 +743,24 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP // Clip pre orientation change - if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; + if (x < 0 || x >= GC->g.Width || y < 0 || y >= GC->g.Height) return 0; #endif #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: break; case GDISP_ROTATE_90: - t = GDISP.Height - 1 - y; + t = GC->g.Height - 1 - y; y = x; x = t; break; case GDISP_ROTATE_180: - x = GDISP.Width - 1 - x; - y = GDISP.Height - 1 - y; + x = GC->g.Width - 1 - x; + y = GC->g.Height - 1 - y; break; case GDISP_ROTATE_270: - t = GDISP.Width - 1 - x; + t = GC->g.Width - 1 - x; x = y; y = t; break; @@ -842,11 +792,11 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP // Clip pre orientation change - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; + if (x < GC->g.clipx0) { cx -= GC->g.clipx0 - x; x = GC->g.clipx0; } + if (y < GC->g.clipy0) { cy -= GC->g.clipy0 - y; y = GC->g.clipy0; } + if (!lines || cx <= 0 || cy <= 0 || x >= GC->g.clipx1 || y >= GC->g.clipy1) return; + if (x+cx > GC->g.clipx1) cx = GC->g.clipx1 - x; + if (y+cy > GC->g.clipy1) cy = GC->g.clipy1 - y; #endif if (lines > cy) lines = cy; @@ -856,7 +806,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { hbr = CreateSolidBrush(bgcolor); #if GDISP_NEED_CONTROL - switch(GDISP.Orientation) { + switch(GC->g.Orientation) { case GDISP_ROTATE_0: rect.top = y; rect.bottom = rect.top+cy; @@ -867,13 +817,13 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { case GDISP_ROTATE_90: rect.top = x; rect.bottom = rect.top+cx; - rect.right = GDISP.Height - y; + rect.right = GC->g.Height - y; rect.left = rect.right-cy; goto horizontal_scroll; case GDISP_ROTATE_180: - rect.bottom = GDISP.Height - y; + rect.bottom = GC->g.Height - y; rect.top = rect.bottom-cy; - rect.right = GDISP.Width - x; + rect.right = GC->g.Width - x; rect.left = rect.right-cx; vertical_scroll: srect.left = frect.left = rect.left; @@ -891,7 +841,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { ScrollDC(dcBuffer, 0, lines, &srect, 0, 0, 0); break; case GDISP_ROTATE_270: - rect.bottom = GDISP.Width - x; + rect.bottom = GC->g.Width - x; rect.top = rect.bottom-cx; rect.left = y; rect.right = rect.left+cy; @@ -963,36 +913,36 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { void gdisp_lld_control(unsigned what, void *value) { switch(what) { case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) + if (GC->g.Orientation == (gdisp_orientation_t)value) return; switch((gdisp_orientation_t)value) { case GDISP_ROTATE_0: - GDISP.Width = wWidth; - GDISP.Height = wHeight; + GC->g.Width = wWidth; + GC->g.Height = wHeight; break; case GDISP_ROTATE_90: - GDISP.Height = wWidth; - GDISP.Width = wHeight; + GC->g.Height = wWidth; + GC->g.Width = wHeight; break; case GDISP_ROTATE_180: - GDISP.Width = wWidth; - GDISP.Height = wHeight; + GC->g.Width = wWidth; + GC->g.Height = wHeight; break; case GDISP_ROTATE_270: - GDISP.Height = wWidth; - GDISP.Width = wHeight; + GC->g.Height = wWidth; + GC->g.Width = wHeight; break; default: return; } #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; + GC->g.clipx0 = 0; + GC->g.clipy0 = 0; + GC->g.clipx1 = GC->g.Width; + GC->g.clipy1 = GC->g.Height; #endif - GDISP.Orientation = (gdisp_orientation_t)value; + GC->g.Orientation = (gdisp_orientation_t)value; return; /* case GDISP_CONTROL_POWER: diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h index b6fa874a..357febe4 100644 --- a/drivers/multiple/Win32/gdisp_lld_config.h +++ b/drivers/multiple/Win32/gdisp_lld_config.h @@ -22,14 +22,20 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "Win32" +#define GDISP_DRIVER_NAME "Win32" +#define GDISP_DRIVER_STRUCT GDISP_Win32 -#define GDISP_HARDWARE_LINES TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -#define GDISP_HARDWARE_SCROLL TRUE -#define GDISP_HARDWARE_PIXELREAD TRUE -#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_HARDWARE_STREAM FALSE +#define GDISP_HARDWARE_STREAM_END FALSE +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_CLEARS FALSE +#define GDISP_HARDWARE_FILLS TRUE +//#define GDISP_HARDWARE_BITFILLS TRUE +//#define GDISP_HARDWARE_SCROLL TRUE +//#define GDISP_HARDWARE_PIXELREAD TRUE +//#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_HARDWARE_QUERY FALSE +#define GDISP_HARDWARE_CLIP FALSE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index b82c9f3c..3a1968ed 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -76,20 +76,16 @@ typedef enum powermode {powerOff, powerSleep, powerDeepSleep, powerOn} gdisp_pow * Applications should always use the routines and macros defined * below to access it in case the implementation ever changed. */ -typedef struct GDISPDriver_t { +typedef struct GDISPControl { coord_t Width; coord_t Height; gdisp_orientation_t Orientation; gdisp_powermode_t Powermode; uint8_t Backlight; uint8_t Contrast; - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - coord_t clipx0, clipy0; - coord_t clipx1, clipy1; /* not inclusive */ - #endif - } GDISPDriver; + } GDISPControl; -extern GDISPDriver GDISP; +extern GDISPControl *GDISP; /*===========================================================================*/ /* Constants. */ @@ -129,6 +125,7 @@ extern GDISPDriver GDISP; */ #define GDISP_PIXELFORMAT_MONO 1 #define GDISP_PIXELFORMAT_RGB565 565 +#define GDISP_PIXELFORMAT_BGR565 9565 #define GDISP_PIXELFORMAT_RGB888 888 #define GDISP_PIXELFORMAT_RGB444 444 #define GDISP_PIXELFORMAT_RGB332 332 @@ -219,10 +216,20 @@ extern GDISPDriver GDISP; #define MASKCOLOR FALSE #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xF8)<<8) | (((g) & 0xFC)<<3) | (((b) & 0xF8)>>3))) #define HTML2COLOR(h) ((color_t)((((h) & 0xF80000)>>8) | (((h) & 0x00FC00)>>5) | (((h) & 0x0000F8)>>3))) - #define RED_OF(c) (((c) & 0xF800)>>8) + #define RED_OF(c) (((c)&0xF800)>>8) #define GREEN_OF(c) (((c)&0x07E0)>>3) #define BLUE_OF(c) (((c)&0x001F)<<3) +#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_BGR565 + typedef uint16_t color_t; + #define COLOR(c) ((color_t)(c)) + #define MASKCOLOR FALSE + #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xF8)>>3) | (((g) & 0xFC)<<3) | (((b) & 0xF8)<<8))) + #define HTML2COLOR(h) ((color_t)((((h) & 0x0000F8)>>3) | (((h) & 0x00FC00)>>5) | (((h) & 0xF80000)>>8))) + #define RED_OF(c) (((c)&0x001F)<<3) + #define GREEN_OF(c) (((c)&0x07E0)>>3) + #define BLUE_OF(c) (((c)& 0xF800)>>8) + #elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888 typedef uint32_t color_t; #define COLOR(c) ((color_t)(((c) & 0xFFFFFF))) @@ -296,278 +303,82 @@ typedef color_t pixel_t; extern "C" { #endif -#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC || defined(__DOXYGEN__) - /* These routines can be hardware accelerated - * - Do not add a routine here unless it has also been added to the hardware acceleration layer - */ +/* Base Functions */ - /* Base Functions */ - - /** - * @brief Test if the GDISP engine is currently drawing. - * @note This function will always return FALSE if - * GDISP_NEED_ASYNC is not defined. - * - * @return TRUE if gdisp is busy, FALSE otherwise - * - * @api - */ - bool_t gdispIsBusy(void); - - /* Drawing Functions */ - - /** - * @brief Clear the display to the specified color. - * - * @param[in] color The color to use when clearing the screen - * - * @api - */ - void gdispClear(color_t color); - - /** - * @brief Set a pixel in the specified color. - * - * @param[in] x,y The position to set the pixel. - * @param[in] color The color to use - * - * @api - */ - void gdispDrawPixel(coord_t x, coord_t y, color_t color); - - /** - * @brief Draw a line. - * - * @param[in] x0,y0 The start position - * @param[in] x1,y1 The end position - * @param[in] color The color to use - * - * @api - */ - void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); - - /** - * @brief Fill an area with a color. - * - * @param[in] x,y The start position - * @param[in] cx,cy The size of the box (outside dimensions) - * @param[in] color The color to use - * - * @api - */ - void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); - - /** - * @brief Fill an area using the supplied bitmap. - * @details The bitmap is in the pixel format specified by the low level driver - * @note If a packed pixel format is used and the width doesn't - * match a whole number of bytes, the next line will start on a - * non-byte boundary (no end-of-line padding). - * @note If GDISP_NEED_ASYNC is defined then the buffer must be static - * or at least retained until this call has finished the blit. You can - * tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE. - * - * @param[in] x,y The start position - * @param[in] cx,cy The size of the filled area - * @param[in] srcx,srcy The bitmap position to start the fill form - * @param[in] srccx The width of a line in the bitmap - * @param[in] buffer The bitmap in the driver's pixel format - * - * @api - */ - void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer); - - /* Clipping Functions */ - - #if GDISP_NEED_CLIP || defined(__DOXYGEN__) - /** - * @brief Clip all drawing to the defined area. - * - * @param[in] x,y The start position - * @param[in] cx,cy The size of the clip area - * - * @api - */ - void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy); - #endif - - /* Circle Functions */ - - #if GDISP_NEED_CIRCLE || defined(__DOXYGEN__) - /** - * @brief Draw a circle. - * - * @param[in] x,y The center of the circle - * @param[in] radius The radius of the circle - * @param[in] color The color to use - * - * @api - */ - void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color); - - /** - * @brief Draw a filled circle. - * - * @param[in] x,y The center of the circle - * @param[in] radius The radius of the circle - * @param[in] color The color to use - * - * @api - */ - void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color); - #endif - - /* Ellipse Functions */ - - #if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__) - /** - * @brief Draw an ellipse. - * - * @param[in] x,y The center of the ellipse - * @param[in] a,b The dimensions of the ellipse - * @param[in] color The color to use - * - * @api - */ - void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); - - /** - * @brief Draw a filled ellipse. - * - * @param[in] x,y The center of the ellipse - * @param[in] a,b The dimensions of the ellipse - * @param[in] color The color to use - * - * @api - */ - void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); - #endif - - /* Arc Functions */ - - #if GDISP_NEED_ARC || defined(__DOXYGEN__) - /* - * @brief Draw an arc. - * - * @param[in] x0,y0 The center point - * @param[in] radius The radius of the arc - * @param[in] start The start angle (0 to 360) - * @param[in] end The end angle (0 to 360) - * @param[in] color The color of the arc - * - * @api - */ - void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); - - /* - * @brief Draw a filled arc. - * @note Not very efficient currently - does lots of overdrawing - * - * @param[in] x0,y0 The center point - * @param[in] radius The radius of the arc - * @param[in] start The start angle (0 to 360) - * @param[in] end The end angle (0 to 360) - * @param[in] color The color of the arc - * - * @api - */ - void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); - #endif - - /* Read a pixel Function */ - - #if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__) - /** - * @brief Get the color of a pixel. - * @return The color of the pixel. - * - * @param[in] x,y The position of the pixel - * - * @api - */ - color_t gdispGetPixelColor(coord_t x, coord_t y); - #endif - - /* Scrolling Function - clears the area scrolled out */ - - #if GDISP_NEED_SCROLL || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @pre GDISP_NEED_SCROLL must be set to TRUE in gfxconf.h - * @note Optional. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @api - */ - void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor); - #endif - - /* Set driver specific control */ - - #if GDISP_NEED_CONTROL || defined(__DOXYGEN__) - /** - * @brief Control hardware specific parts of the display. eg powermodes, backlight etc - * @note Depending on the hardware implementation this function may not - * support some codes. They will be ignored. - * - * @param[in] what what you want to control - * @param[in] value The value to be assigned - * - * @api - */ - void gdispControl(unsigned what, void *value); - #endif - - /* Query driver specific data */ - - #if GDISP_NEED_QUERY || defined(__DOXYGEN__) - /** - * @brief Query a property of the display. - * @note The result must be typecast to the correct type. - * @note An unsupported query will return (void *)-1. - * - * @param[in] what What to query - * - * @api - */ - void *gdispQuery(unsigned what); - #endif - -#else - /* Include the low level driver information */ - #include "gdisp/lld/gdisp_lld.h" - - /* The same as above but use the low level driver directly if no multi-thread support is needed */ - #define gdispIsBusy() FALSE - #define gdispClear(color) gdisp_lld_clear(color) - #define gdispDrawPixel(x, y, color) gdisp_lld_draw_pixel(x, y, color) - #define gdispDrawLine(x0, y0, x1, y1, color) gdisp_lld_draw_line(x0, y0, x1, y1, color) - #define gdispFillArea(x, y, cx, cy, color) gdisp_lld_fill_area(x, y, cx, cy, color) - #define gdispBlitAreaEx(x, y, cx, cy, sx, sy, scx, buf) gdisp_lld_blit_area_ex(x, y, cx, cy, sx, sy, scx, buf) - #define gdispSetClip(x, y, cx, cy) gdisp_lld_set_clip(x, y, cx, cy) - #define gdispDrawCircle(x, y, radius, color) gdisp_lld_draw_circle(x, y, radius, color) - #define gdispFillCircle(x, y, radius, color) gdisp_lld_fill_circle(x, y, radius, color) - #define gdispDrawArc(x, y, radius, sangle, eangle, color) gdisp_lld_draw_arc(x, y, radius, sangle, eangle, color) - #define gdispFillArc(x, y, radius, sangle, eangle, color) gdisp_lld_fill_arc(x, y, radius, sangle, eangle, color) - #define gdispDrawEllipse(x, y, a, b, color) gdisp_lld_draw_ellipse(x, y, a, b, color) - #define gdispFillEllipse(x, y, a, b, color) gdisp_lld_fill_ellipse(x, y, a, b, color) - #define gdispGetPixelColor(x, y) gdisp_lld_get_pixel_color(x, y) - #define gdispVerticalScroll(x, y, cx, cy, lines, bgcolor) gdisp_lld_vertical_scroll(x, y, cx, cy, lines, bgcolor) - #define gdispControl(what, value) gdisp_lld_control(what, value) - #define gdispQuery(what) gdisp_lld_query(what) - -#endif - -/* These routines are not hardware accelerated - * - Do not add a hardware accelerated routines here. +/** + * @brief Blend 2 colors according to the alpha + * @return The combined color + * + * @param[in] fg The foreground color + * @param[in] bg The background color + * @param[in] alpha The alpha value (0-255). 0 is all background, 255 is all foreground. + * + * @api */ +color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); -/* Extra drawing functions */ +/* Drawing Functions */ + +/** + * @brief Clear the display to the specified color. + * + * @param[in] color The color to use when clearing the screen + * + * @api + */ +void gdispClear(color_t color); + +/** + * @brief Set a pixel in the specified color. + * + * @param[in] x,y The position to set the pixel. + * @param[in] color The color to use + * + * @api + */ +void gdispDrawPixel(coord_t x, coord_t y, color_t color); + +/** + * @brief Draw a line. + * + * @param[in] x0,y0 The start position + * @param[in] x1,y1 The end position + * @param[in] color The color to use + * + * @api + */ +void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); + +/** + * @brief Fill an area with a color. + * + * @param[in] x,y The start position + * @param[in] cx,cy The size of the box (outside dimensions) + * @param[in] color The color to use + * + * @api + */ +void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); + +/** + * @brief Fill an area using the supplied bitmap. + * @details The bitmap is in the pixel format specified by the low level driver + * @note If a packed pixel format is used and the width doesn't + * match a whole number of bytes, the next line will start on a + * non-byte boundary (no end-of-line padding). + * @note If GDISP_NEED_ASYNC is defined then the buffer must be static + * or at least retained until this call has finished the blit. You can + * tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE. + * + * @param[in] x,y The start position + * @param[in] cx,cy The size of the filled area + * @param[in] srcx,srcy The bitmap position to start the fill form + * @param[in] srccx The width of a line in the bitmap + * @param[in] buffer The bitmap in the driver's pixel format + * + * @api + */ +void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer); /** * @brief Draw a rectangular box. @@ -580,6 +391,167 @@ extern "C" { */ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); +/* Clipping Functions */ + +#if GDISP_NEED_CLIP || defined(__DOXYGEN__) + /** + * @brief Clip all drawing to the defined area. + * + * @param[in] x,y The start position + * @param[in] cx,cy The size of the clip area + * + * @api + */ + void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy); +#endif + +/* Circle Functions */ + +#if GDISP_NEED_CIRCLE || defined(__DOXYGEN__) + /** + * @brief Draw a circle. + * + * @param[in] x,y The center of the circle + * @param[in] radius The radius of the circle + * @param[in] color The color to use + * + * @api + */ + void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color); + + /** + * @brief Draw a filled circle. + * + * @param[in] x,y The center of the circle + * @param[in] radius The radius of the circle + * @param[in] color The color to use + * + * @api + */ + void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color); +#endif + +/* Ellipse Functions */ + +#if GDISP_NEED_ELLIPSE || defined(__DOXYGEN__) + /** + * @brief Draw an ellipse. + * + * @param[in] x,y The center of the ellipse + * @param[in] a,b The dimensions of the ellipse + * @param[in] color The color to use + * + * @api + */ + void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + + /** + * @brief Draw a filled ellipse. + * + * @param[in] x,y The center of the ellipse + * @param[in] a,b The dimensions of the ellipse + * @param[in] color The color to use + * + * @api + */ + void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); +#endif + +/* Arc Functions */ + +#if GDISP_NEED_ARC || defined(__DOXYGEN__) + /* + * @brief Draw an arc. + * + * @param[in] x0,y0 The center point + * @param[in] radius The radius of the arc + * @param[in] start The start angle (0 to 360) + * @param[in] end The end angle (0 to 360) + * @param[in] color The color of the arc + * + * @api + */ + void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + + /* + * @brief Draw a filled arc. + * @note Not very efficient currently - does lots of overdrawing + * + * @param[in] x0,y0 The center point + * @param[in] radius The radius of the arc + * @param[in] start The start angle (0 to 360) + * @param[in] end The end angle (0 to 360) + * @param[in] color The color of the arc + * + * @api + */ + void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); +#endif + +/* Read a pixel Function */ + +#if GDISP_NEED_PIXELREAD || defined(__DOXYGEN__) + /** + * @brief Get the color of a pixel. + * @return The color of the pixel. + * + * @param[in] x,y The position of the pixel + * + * @api + */ + color_t gdispGetPixelColor(coord_t x, coord_t y); +#endif + +/* Scrolling Function - clears the area scrolled out */ + +#if GDISP_NEED_SCROLL || defined(__DOXYGEN__) + /** + * @brief Scroll vertically a section of the screen. + * @pre GDISP_NEED_SCROLL must be set to TRUE in gfxconf.h + * @note Optional. + * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. + * + * @param[in] x, y The start of the area to be scrolled + * @param[in] cx, cy The size of the area to be scrolled + * @param[in] lines The number of lines to scroll (Can be positive or negative) + * @param[in] bgcolor The color to fill the newly exposed area. + * + * @api + */ + void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor); +#endif + +/* Set driver specific control */ + +#if GDISP_NEED_CONTROL || defined(__DOXYGEN__) + /** + * @brief Control hardware specific parts of the display. eg powermodes, backlight etc + * @note Depending on the hardware implementation this function may not + * support some codes. They will be ignored. + * + * @param[in] what what you want to control + * @param[in] value The value to be assigned + * + * @api + */ + void gdispControl(unsigned what, void *value); +#endif + +/* Query driver specific data */ + +#if GDISP_NEED_QUERY || defined(__DOXYGEN__) + /** + * @brief Query a property of the display. + * @note The result must be typecast to the correct type. + * @note An unsupported query will return (void *)-1. + * + * @param[in] what What to query + * + * @api + */ + void *gdispQuery(unsigned what); +#endif + #if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__) /** * @brief Draw an enclosed polygon (convex, non-convex or complex). @@ -803,19 +775,6 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color); #endif - -/** - * @brief Blend 2 colors according to the alpha - * @return The combined color - * - * @param[in] fg The foreground color - * @param[in] bg The background color - * @param[in] alpha The alpha value (0-255). 0 is all background, 255 is all foreground. - * - * @api - */ -color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); - /* Support routine for packed pixel formats */ #if !defined(gdispPackPixels) || defined(__DOXYGEN__) /** @@ -890,42 +849,42 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); * * @api */ -#define gdispGetWidth() (GDISP.Width) +#define gdispGetWidth() (GDISP->Width) /** * @brief Get the display height in pixels. * * @api */ -#define gdispGetHeight() (GDISP.Height) +#define gdispGetHeight() (GDISP->Height) /** * @brief Get the current display power mode. * * @api */ -#define gdispGetPowerMode() (GDISP.Powermode) +#define gdispGetPowerMode() (GDISP->Powermode) /** * @brief Get the current display orientation. * * @api */ -#define gdispGetOrientation() (GDISP.Orientation) +#define gdispGetOrientation() (GDISP->Orientation) /** * @brief Get the current display backlight brightness. * * @api */ -#define gdispGetBacklight() (GDISP.Backlight) +#define gdispGetBacklight() (GDISP->Backlight) /** * @brief Get the current display contrast. * * @api */ -#define gdispGetContrast() (GDISP.Contrast) +#define gdispGetContrast() (GDISP->Contrast) /* More interesting macro's */ @@ -936,7 +895,6 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); */ #define gdispUnsetClip() gdispSetClip(0,0,gdispGetWidth(),gdispGetHeight()) - #ifdef __cplusplus } #endif diff --git a/include/gdisp/lld/emulation.c b/include/gdisp/lld/emulation.c deleted file mode 100644 index cb0c9c4b..00000000 --- a/include/gdisp/lld/emulation.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file include/gdisp/lld/emulation.c - * @brief GDISP emulation routines for stuff the driver dosen't support - * - * @addtogroup GDISP - * - * @details Even though this is a software emulation of a low level driver - * most validation doesn't need to happen here as eventually - * we call a real low level driver routine and if validation is - * required - it will do it. - * - * @{ - */ -#ifndef GDISP_EMULATION_C -#define GDISP_EMULATION_C - -#if GFX_USE_GDISP - -/* Include the low level driver information */ -#include "gdisp/lld/gdisp_lld.h" - -/* Declare the GDISP structure */ -GDISPDriver GDISP; - -#if !GDISP_HARDWARE_CLEARS - void gdisp_lld_clear(color_t color) { - gdisp_lld_fill_area(0, 0, GDISP.Width, GDISP.Height, color); - } -#endif - -#if !GDISP_HARDWARE_LINES - void gdisp_lld_draw_line(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { - int16_t dy, dx; - int16_t addx, addy; - int16_t P, diff, i; - - #if GDISP_HARDWARE_FILLS || GDISP_HARDWARE_SCROLL - // speed improvement if vertical or horizontal - if (x0 == x1) { - if (y1 > y0) - gdisp_lld_fill_area(x0, y0, 1, y1-y0+1, color); - else - gdisp_lld_fill_area(x0, y1, 1, y0-y1+1, color); - return; - } - if (y0 == y1) { - if (x1 > x0) - gdisp_lld_fill_area(x0, y0, x1-x0+1, 1, color); - else - gdisp_lld_fill_area(x1, y0, x0-x1+1, 1, color); - return; - } - #endif - - if (x1 >= x0) { - dx = x1 - x0; - addx = 1; - } else { - dx = x0 - x1; - addx = -1; - } - if (y1 >= y0) { - dy = y1 - y0; - addy = 1; - } else { - dy = y0 - y1; - addy = -1; - } - - if (dx >= dy) { - dy *= 2; - P = dy - dx; - diff = P - dx; - - for(i=0; i<=dx; ++i) { - gdisp_lld_draw_pixel(x0, y0, color); - if (P < 0) { - P += dy; - x0 += addx; - } else { - P += diff; - x0 += addx; - y0 += addy; - } - } - } else { - dx *= 2; - P = dx - dy; - diff = P - dy; - - for(i=0; i<=dy; ++i) { - gdisp_lld_draw_pixel(x0, y0, color); - if (P < 0) { - P += dx; - y0 += addy; - } else { - P += diff; - x0 += addx; - y0 += addy; - } - } - } - } -#endif - -#if !GDISP_HARDWARE_FILLS - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - #if GDISP_HARDWARE_SCROLL - gdisp_lld_vertical_scroll(x, y, cx, cy, cy, color); - #elif GDISP_HARDWARE_LINES - coord_t x1, y1; - - x1 = x + cx - 1; - y1 = y + cy; - for(; y < y1; y++) - gdisp_lld_draw_line(x, y, x1, y, color); - #else - coord_t x0, x1, y1; - - x0 = x; - x1 = x + cx; - y1 = y + cy; - for(; y < y1; y++) - for(x = x0; x < x1; x++) - gdisp_lld_draw_pixel(x, y, color); - #endif - } -#endif - -#if !GDISP_HARDWARE_BITFILLS - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - coord_t x0, x1, y1; - - x0 = x; - x1 = x + cx; - y1 = y + cy; - buffer += srcy*srccx+srcx; - srccx -= cx; - for(; y < y1; y++, buffer += srccx) - for(x=x0; x < x1; x++) - gdisp_lld_draw_pixel(x, y, *buffer++); - } -#endif - -#if GDISP_NEED_CLIP && !GDISP_HARDWARE_CLIP - void gdisp_lld_set_clip(coord_t x, coord_t y, coord_t cx, coord_t cy) { - #if GDISP_NEED_VALIDATION - if (x >= GDISP.Width || y >= GDISP.Height || cx < 0 || cy < 0) - return; - if (x < 0) x = 0; - if (y < 0) y = 0; - if (x+cx > GDISP.Width) cx = GDISP.Width - x; - if (y+cy > GDISP.Height) cy = GDISP.Height - y; - #endif - GDISP.clipx0 = x; - GDISP.clipy0 = y; - GDISP.clipx1 = x+cx; - GDISP.clipy1 = y+cy; - } -#endif - -#if GDISP_NEED_CIRCLE && !GDISP_HARDWARE_CIRCLES - void gdisp_lld_draw_circle(coord_t x, coord_t y, coord_t radius, color_t color) { - coord_t a, b, P; - - a = 0; - b = radius; - P = 1 - radius; - - do { - gdisp_lld_draw_pixel(x+a, y+b, color); - gdisp_lld_draw_pixel(x+b, y+a, color); - gdisp_lld_draw_pixel(x-a, y+b, color); - gdisp_lld_draw_pixel(x-b, y+a, color); - gdisp_lld_draw_pixel(x+b, y-a, color); - gdisp_lld_draw_pixel(x+a, y-b, color); - gdisp_lld_draw_pixel(x-a, y-b, color); - gdisp_lld_draw_pixel(x-b, y-a, color); - if (P < 0) - P += 3 + 2*a++; - else - P += 5 + 2*(a++ - b--); - } while(a <= b); - } -#endif - -#if GDISP_NEED_CIRCLE && !GDISP_HARDWARE_CIRCLEFILLS - void gdisp_lld_fill_circle(coord_t x, coord_t y, coord_t radius, color_t color) { - coord_t a, b, P; - - a = 0; - b = radius; - P = 1 - radius; - - do { - gdisp_lld_draw_line(x-a, y+b, x+a, y+b, color); - gdisp_lld_draw_line(x-a, y-b, x+a, y-b, color); - gdisp_lld_draw_line(x-b, y+a, x+b, y+a, color); - gdisp_lld_draw_line(x-b, y-a, x+b, y-a, color); - if (P < 0) - P += 3 + 2*a++; - else - P += 5 + 2*(a++ - b--); - } while(a <= b); - } -#endif - -#if GDISP_NEED_ELLIPSE && !GDISP_HARDWARE_ELLIPSES - void gdisp_lld_draw_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - int dx = 0, dy = b; /* im I. Quadranten von links oben nach rechts unten */ - long a2 = a*a, b2 = b*b; - long err = b2-(2*b-1)*a2, e2; /* Fehler im 1. Schritt */ - - do { - gdisp_lld_draw_pixel(x+dx, y+dy, color); /* I. Quadrant */ - gdisp_lld_draw_pixel(x-dx, y+dy, color); /* II. Quadrant */ - gdisp_lld_draw_pixel(x-dx, y-dy, color); /* III. Quadrant */ - gdisp_lld_draw_pixel(x+dx, y-dy, color); /* IV. Quadrant */ - - e2 = 2*err; - if(e2 < (2*dx+1)*b2) { - dx++; - err += (2*dx+1)*b2; - } - if(e2 > -(2*dy-1)*a2) { - dy--; - err -= (2*dy-1)*a2; - } - } while(dy >= 0); - - while(dx++ < a) { /* fehlerhafter Abbruch bei flachen Ellipsen (b=1) */ - gdisp_lld_draw_pixel(x+dx, y, color); /* -> Spitze der Ellipse vollenden */ - gdisp_lld_draw_pixel(x-dx, y, color); - } - } -#endif - -#if GDISP_NEED_ELLIPSE && !GDISP_HARDWARE_ELLIPSEFILLS - void gdisp_lld_fill_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - int dx = 0, dy = b; /* im I. Quadranten von links oben nach rechts unten */ - long a2 = a*a, b2 = b*b; - long err = b2-(2*b-1)*a2, e2; /* Fehler im 1. Schritt */ - - do { - gdisp_lld_draw_line(x-dx,y+dy,x+dx,y+dy, color); - gdisp_lld_draw_line(x-dx,y-dy,x+dx,y-dy, color); - - e2 = 2*err; - if(e2 < (2*dx+1)*b2) { - dx++; - err += (2*dx+1)*b2; - } - if(e2 > -(2*dy-1)*a2) { - dy--; - err -= (2*dy-1)*a2; - } - } while(dy >= 0); - - while(dx++ < a) { /* fehlerhafter Abbruch bei flachen Ellipsen (b=1) */ - gdisp_lld_draw_pixel(x+dx, y, color); /* -> Spitze der Ellipse vollenden */ - gdisp_lld_draw_pixel(x-dx, y, color); - } - } -#endif - -#if GDISP_NEED_ARC && !GDISP_HARDWARE_ARCS - - #include - - /* - * @brief Internal helper function for gdispDrawArc() - * - * @note DO NOT USE DIRECTLY! - * - * @param[in] x, y The middle point of the arc - * @param[in] start The start angle of the arc - * @param[in] end The end angle of the arc - * @param[in] radius The radius of the arc - * @param[in] color The color in which the arc will be drawn - * - * @notapi - */ - static void _draw_arc(coord_t x, coord_t y, uint16_t start, uint16_t end, uint16_t radius, color_t color) { - if (/*start >= 0 && */start <= 180) { - float x_maxI = x + radius*cos(start*M_PI/180); - float x_minI; - - if (end > 180) - x_minI = x - radius; - else - x_minI = x + radius*cos(end*M_PI/180); - - int a = 0; - int b = radius; - int P = 1 - radius; - - do { - if(x-a <= x_maxI && x-a >= x_minI) - gdisp_lld_draw_pixel(x-a, y-b, color); - if(x+a <= x_maxI && x+a >= x_minI) - gdisp_lld_draw_pixel(x+a, y-b, color); - if(x-b <= x_maxI && x-b >= x_minI) - gdisp_lld_draw_pixel(x-b, y-a, color); - if(x+b <= x_maxI && x+b >= x_minI) - gdisp_lld_draw_pixel(x+b, y-a, color); - - if (P < 0) { - P = P + 3 + 2*a; - a = a + 1; - } else { - P = P + 5 + 2*(a - b); - a = a + 1; - b = b - 1; - } - } while(a <= b); - } - - if (end > 180 && end <= 360) { - float x_maxII = x+radius*cos(end*M_PI/180); - float x_minII; - - if(start <= 180) - x_minII = x - radius; - else - x_minII = x+radius*cos(start*M_PI/180); - - int a = 0; - int b = radius; - int P = 1 - radius; - - do { - if(x-a <= x_maxII && x-a >= x_minII) - gdisp_lld_draw_pixel(x-a, y+b, color); - if(x+a <= x_maxII && x+a >= x_minII) - gdisp_lld_draw_pixel(x+a, y+b, color); - if(x-b <= x_maxII && x-b >= x_minII) - gdisp_lld_draw_pixel(x-b, y+a, color); - if(x+b <= x_maxII && x+b >= x_minII) - gdisp_lld_draw_pixel(x+b, y+a, color); - - if (P < 0) { - P = P + 3 + 2*a; - a = a + 1; - } else { - P = P + 5 + 2*(a - b); - a = a + 1; - b = b - 1; - } - } while (a <= b); - } - } - - void gdisp_lld_draw_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color) { - if(endangle < startangle) { - _draw_arc(x, y, startangle, 360, radius, color); - _draw_arc(x, y, 0, endangle, radius, color); - } else { - _draw_arc(x, y, startangle, endangle, radius, color); - } - } -#endif - -#if GDISP_NEED_ARC && !GDISP_HARDWARE_ARCFILLS - /* - * @brief Internal helper function for gdispDrawArc() - * - * @note DO NOT USE DIRECTLY! - * - * @param[in] x, y The middle point of the arc - * @param[in] start The start angle of the arc - * @param[in] end The end angle of the arc - * @param[in] radius The radius of the arc - * @param[in] color The color in which the arc will be drawn - * - * @notapi - */ - static void _fill_arc(coord_t x, coord_t y, uint16_t start, uint16_t end, uint16_t radius, color_t color) { - if (/*start >= 0 && */start <= 180) { - float x_maxI = x + radius*cos(start*M_PI/180); - float x_minI; - - if (end > 180) - x_minI = x - radius; - else - x_minI = x + radius*cos(end*M_PI/180); - - int a = 0; - int b = radius; - int P = 1 - radius; - - do { - if(x-a <= x_maxI && x-a >= x_minI) - gdisp_lld_draw_line(x, y, x-a, y-b, color); - if(x+a <= x_maxI && x+a >= x_minI) - gdisp_lld_draw_line(x, y, x+a, y-b, color); - if(x-b <= x_maxI && x-b >= x_minI) - gdisp_lld_draw_line(x, y, x-b, y-a, color); - if(x+b <= x_maxI && x+b >= x_minI) - gdisp_lld_draw_line(x, y, x+b, y-a, color); - - if (P < 0) { - P = P + 3 + 2*a; - a = a + 1; - } else { - P = P + 5 + 2*(a - b); - a = a + 1; - b = b - 1; - } - } while(a <= b); - } - - if (end > 180 && end <= 360) { - float x_maxII = x+radius*cos(end*M_PI/180); - float x_minII; - - if(start <= 180) - x_minII = x - radius; - else - x_minII = x+radius*cos(start*M_PI/180); - - int a = 0; - int b = radius; - int P = 1 - radius; - - do { - if(x-a <= x_maxII && x-a >= x_minII) - gdisp_lld_draw_line(x, y, x-a, y+b, color); - if(x+a <= x_maxII && x+a >= x_minII) - gdisp_lld_draw_line(x, y, x+a, y+b, color); - if(x-b <= x_maxII && x-b >= x_minII) - gdisp_lld_draw_line(x, y, x-b, y+a, color); - if(x+b <= x_maxII && x+b >= x_minII) - gdisp_lld_draw_line(x, y, x+b, y+a, color); - - if (P < 0) { - P = P + 3 + 2*a; - a = a + 1; - } else { - P = P + 5 + 2*(a - b); - a = a + 1; - b = b - 1; - } - } while (a <= b); - } - } - - void gdisp_lld_fill_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color) { - if(endangle < startangle) { - _fill_arc(x, y, startangle, 360, radius, color); - _fill_arc(x, y, 0, endangle, radius, color); - } else { - _fill_arc(x, y, startangle, endangle, radius, color); - } - } -#endif - -#if GDISP_NEED_CONTROL && !GDISP_HARDWARE_CONTROL - void gdisp_lld_control(unsigned what, void *value) { - (void)what; - (void)value; - /* Ignore everything */ - } -#endif - -#if GDISP_NEED_QUERY && !GDISP_HARDWARE_QUERY -void *gdisp_lld_query(unsigned what) { - (void) what; - return (void *)-1; -} -#endif - -#if GDISP_NEED_MSGAPI - void gdisp_lld_msg_dispatch(gdisp_lld_msg_t *msg) { - switch(msg->action) { - case GDISP_LLD_MSG_NOP: - break; - case GDISP_LLD_MSG_INIT: - gdisp_lld_init(); - break; - case GDISP_LLD_MSG_CLEAR: - gdisp_lld_clear(msg->clear.color); - break; - case GDISP_LLD_MSG_DRAWPIXEL: - gdisp_lld_draw_pixel(msg->drawpixel.x, msg->drawpixel.y, msg->drawpixel.color); - break; - case GDISP_LLD_MSG_FILLAREA: - gdisp_lld_fill_area(msg->fillarea.x, msg->fillarea.y, msg->fillarea.cx, msg->fillarea.cy, msg->fillarea.color); - break; - case GDISP_LLD_MSG_BLITAREA: - gdisp_lld_blit_area_ex(msg->blitarea.x, msg->blitarea.y, msg->blitarea.cx, msg->blitarea.cy, msg->blitarea.srcx, msg->blitarea.srcy, msg->blitarea.srccx, msg->blitarea.buffer); - break; - case GDISP_LLD_MSG_DRAWLINE: - gdisp_lld_draw_line(msg->drawline.x0, msg->drawline.y0, msg->drawline.x1, msg->drawline.y1, msg->drawline.color); - break; - #if GDISP_NEED_CLIP - case GDISP_LLD_MSG_SETCLIP: - gdisp_lld_set_clip(msg->setclip.x, msg->setclip.y, msg->setclip.cx, msg->setclip.cy); - break; - #endif - #if GDISP_NEED_CIRCLE - case GDISP_LLD_MSG_DRAWCIRCLE: - gdisp_lld_draw_circle(msg->drawcircle.x, msg->drawcircle.y, msg->drawcircle.radius, msg->drawcircle.color); - break; - case GDISP_LLD_MSG_FILLCIRCLE: - gdisp_lld_fill_circle(msg->fillcircle.x, msg->fillcircle.y, msg->fillcircle.radius, msg->fillcircle.color); - break; - #endif - #if GDISP_NEED_ELLIPSE - case GDISP_LLD_MSG_DRAWELLIPSE: - gdisp_lld_draw_ellipse(msg->drawellipse.x, msg->drawellipse.y, msg->drawellipse.a, msg->drawellipse.b, msg->drawellipse.color); - break; - case GDISP_LLD_MSG_FILLELLIPSE: - gdisp_lld_fill_ellipse(msg->fillellipse.x, msg->fillellipse.y, msg->fillellipse.a, msg->fillellipse.b, msg->fillellipse.color); - break; - #endif - #if GDISP_NEED_ARC - case GDISP_LLD_MSG_DRAWARC: - gdisp_lld_draw_circle(msg->drawarc.x, msg->drawarc.y, msg->drawarc.radius, msg->drawarc.startangle, msg->drawarc.endangle, msg->drawarc.color); - break; - case GDISP_LLD_MSG_FILLARC: - gdisp_lld_fill_circle(msg->fillarc.x, msg->fillarc.y, msg->fillarc.radius, msg->fillarc.startangle, msg->fillarc.endangle, msg->fillarc.color); - break; - #endif - #if GDISP_NEED_PIXELREAD - case GDISP_LLD_MSG_GETPIXELCOLOR: - msg->getpixelcolor.result = gdisp_lld_get_pixel_color(msg->getpixelcolor.x, msg->getpixelcolor.y); - break; - #endif - #if GDISP_NEED_SCROLL - case GDISP_LLD_MSG_VERTICALSCROLL: - gdisp_lld_vertical_scroll(msg->verticalscroll.x, msg->verticalscroll.y, msg->verticalscroll.cx, msg->verticalscroll.cy, msg->verticalscroll.lines, msg->verticalscroll.bgcolor); - break; - #endif - #if GDISP_NEED_CONTROL - case GDISP_LLD_MSG_CONTROL: - gdisp_lld_control(msg->control.what, msg->control.value); - break; - #endif - #if GDISP_NEED_QUERY - case GDISP_LLD_MSG_QUERY: - msg->query.result = gdisp_lld_query(msg->query.what); - break; - #endif - } - } -#endif - -#endif /* GFX_USE_GDISP */ -#endif /* GDISP_EMULATION_C */ -/** @} */ - diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 98c7569c..46d5488a 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -27,16 +27,35 @@ * @{ */ /** - * @brief Hardware accelerated line drawing. + * @brief Hardware streaming interface is supported. * @details If set to @p FALSE software emulation is used. + * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver */ - #ifndef GDISP_HARDWARE_LINES - #define GDISP_HARDWARE_LINES FALSE + #ifndef GDISP_HARDWARE_STREAM + #define GDISP_HARDWARE_STREAM FALSE + #endif + + /** + * @brief Hardware streaming requires an explicit end call. + * @details If set to @p FALSE if an explicit stream end call is not required. + */ + #ifndef GDISP_HARDWARE_STREAM_END + #define GDISP_HARDWARE_STREAM_END FALSE + #endif + + /** + * @brief Hardware accelerated draw pixel. + * @details If set to @p FALSE software emulation is used. + * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver + */ + #ifndef GDISP_HARDWARE_DRAWPIXEL + #define GDISP_HARDWARE_DRAWPIXEL FALSE #endif /** * @brief Hardware accelerated screen clears. * @details If set to @p FALSE software emulation is used. + * @note This clears the entire display surface regardless of the clipping area currently set */ #ifndef GDISP_HARDWARE_CLEARS #define GDISP_HARDWARE_CLEARS FALSE @@ -58,54 +77,6 @@ #define GDISP_HARDWARE_BITFILLS FALSE #endif - /** - * @brief Hardware accelerated circles. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_CIRCLES - #define GDISP_HARDWARE_CIRCLES FALSE - #endif - - /** - * @brief Hardware accelerated filled circles. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_CIRCLEFILLS - #define GDISP_HARDWARE_CIRCLEFILLS FALSE - #endif - - /** - * @brief Hardware accelerated ellipses. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_ELLIPSES - #define GDISP_HARDWARE_ELLIPSES FALSE - #endif - - /** - * @brief Hardware accelerated filled ellipses. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_ELLIPSEFILLS - #define GDISP_HARDWARE_ELLIPSEFILLS FALSE - #endif - - /** - * @brief Hardware accelerated arc's. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_ARCS - #define GDISP_HARDWARE_ARCS FALSE - #endif - - /** - * @brief Hardware accelerated filled arcs. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_ARCFILLS - #define GDISP_HARDWARE_ARCFILLS FALSE - #endif - /** * @brief Hardware accelerated scrolling. * @details If set to @p FALSE there is no support for scrolling. @@ -141,9 +112,14 @@ /** * @brief The driver supports a clipping in hardware. * @details If set to @p FALSE there is no support for non-standard queries. + * @note If this is defined the driver must perform its own clipping on all calls to + * the driver and respond appropriately if a parameter is outside the display area. + * @note If this is not defined then the software ensures that all calls to the + * driver do not exceed the display area (provided GDISP_NEED_CLIP or GDISP_NEED_VALIDATION + * has been set). */ #ifndef GDISP_HARDWARE_CLIP - #define GDISP_HARDWARE_CLIP FALSE + #define GDISP_HARDWARE_CLIP FALSE #endif /** @} */ @@ -161,6 +137,7 @@ * @brief The native pixel format for this device * @note Should be set to one of the following: * GDISP_PIXELFORMAT_RGB565 + * GDISP_PIXELFORMAT_BGR565 * GDISP_PIXELFORMAT_RGB888 * GDISP_PIXELFORMAT_RGB444 * GDISP_PIXELFORMAT_RGB332 @@ -208,76 +185,85 @@ /* External declarations. */ /*===========================================================================*/ +typedef struct GDISPDriver { + GDISPControl g; + + uint16_t flags; + #define GDISP_FLG_INSTREAM 0x0001 + + // Multithread Mutex + #if GDISP_NEED_MULTITHREAD + gfxMutex mutex; + #endif + + // Software clipping + #if !GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + coord_t clipx0, clipy0; + coord_t clipx1, clipy1; /* not inclusive */ + #endif + + // Driver call parameters + struct { + coord_t x, y; + coord_t cx, cy; + coord_t x1, y1; + coord_t x2, y2; + color_t color; + void *ptr; + } p; + + // Text rendering parameters + #if GDISP_NEED_TEXT + struct { + font_t font; + color_t color; + color_t bgcolor; + coord_t clipx0, clipy0; + coord_t clipx1, clipy1; + } t; + #endif +} GDISPDriver; + +extern GDISPDriver GDISP_DRIVER_STRUCT; + #ifdef __cplusplus extern "C" { #endif - /* Core functions */ - extern bool_t gdisp_lld_init(void); - - /* Some of these functions will be implemented in software by the high level driver - depending on the GDISP_HARDWARE_XXX macros defined in gdisp_lld_config.h. - */ - - /* Drawing functions */ - extern void gdisp_lld_clear(color_t color); - extern void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color); - extern void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); - extern void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer); - extern void gdisp_lld_draw_line(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); - - /* Circular Drawing Functions */ - #if GDISP_NEED_CIRCLE - extern void gdisp_lld_draw_circle(coord_t x, coord_t y, coord_t radius, color_t color); - extern void gdisp_lld_fill_circle(coord_t x, coord_t y, coord_t radius, color_t color); + bool_t gdisp_lld_init(void); + #if GDISP_HARDWARE_STREAM + void gdisp_lld_stream_start(void); // Uses p.x,p.y p.cx,p.cy + void gdisp_lld_stream_color(void); // Uses p.color + #if GDISP_HARDWARE_STREAM_END + void gdisp_lld_stream_stop(void); // Uses no parameters + #endif #endif - - #if GDISP_NEED_ELLIPSE - extern void gdisp_lld_draw_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); - extern void gdisp_lld_fill_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + #if GDISP_HARDWARE_DRAWPIXEL + void gdisp_lld_draw_pixel(void); // Uses p.x,p.y p.color #endif - - /* Arc Drawing Functions */ - #if GDISP_NEED_ARC - extern void gdisp_lld_draw_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); - extern void gdisp_lld_fill_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + #if GDISP_HARDWARE_CLEARS + void gdisp_lld_clear(void); // Uses p.color #endif - - /* Text Rendering Functions */ - #if GDISP_NEED_TEXT - extern void gdisp_lld_draw_char(coord_t x, coord_t y, uint16_t c, font_t font, color_t color); - extern void gdisp_lld_fill_char(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor); + #if GDISP_HARDWARE_FILLS + void gdisp_lld_fill_area(void); // Uses p.x,p.y p.cx,p.cy p.color #endif - - /* Pixel readback */ - #if GDISP_NEED_PIXELREAD - extern color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y); + #if GDISP_HARDWARE_BITFILLS + void gdisp_lld_blit_area_ex(void); // Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer) #endif - - /* Scrolling Function - clears the area scrolled out */ - #if GDISP_NEED_SCROLL - extern void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor); + #if GDISP_HARDWARE_PIXELREAD && GDISP_NEED_PIXELREAD + color_t gdisp_lld_get_pixel_color(void); // Uses p.x,p.y #endif - - /* Set driver specific control */ - #if GDISP_NEED_CONTROL - extern void gdisp_lld_control(unsigned what, void *value); + #if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL + void gdisp_lld_vertical_scroll(void); // Uses p.x,p.y p.cx,p.cy, p.y1 (=lines) p.color #endif - - /* Query driver specific data */ - #if GDISP_NEED_QUERY - extern void *gdisp_lld_query(unsigned what); + #if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL + void gdisp_lld_control(void); // Uses p.x (=what) p.ptr (=value) #endif - - /* Clipping Functions */ - #if GDISP_NEED_CLIP - extern void gdisp_lld_set_clip(coord_t x, coord_t y, coord_t cx, coord_t cy); + #if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY + void *gdisp_lld_query(void); // Uses p.x (=what); #endif - - /* Messaging API */ - #if GDISP_NEED_MSGAPI - #include "gdisp_lld_msgs.h" - extern void gdisp_lld_msg_dispatch(gdisp_lld_msg_t *msg); + #if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + void gdisp_lld_set_clip(void); // Uses p.x,p.y p.cx,p.cy #endif #ifdef __cplusplus diff --git a/include/gmisc/gmisc.h b/include/gmisc/gmisc.h index 998dda50..5943e642 100644 --- a/include/gmisc/gmisc.h +++ b/include/gmisc/gmisc.h @@ -51,6 +51,7 @@ typedef int32_t fixed; */ #define FIXED(x) ((fixed)(x)<<16) /* @< integer to fixed */ #define NONFIXED(x) ((x)>>16) /* @< fixed to integer */ +#define FIXED0_5 32768 /* @< 0.5 as a fixed (used for rounding) */ #define FP2FIXED(x) ((fixed)((x)*65536.0)) /* @< floating point to fixed */ #define FIXED2FP(x) ((double)(x)/65536.0) /* @< fixed to floating point */ /* @} */ diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 22773908..1aecd26c 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -19,438 +19,1526 @@ /* Include the low level driver information */ #include "gdisp/lld/gdisp_lld.h" +#if !GDISP_HARDWARE_STREAM && !GDISP_HARDWARE_DRAWPIXEL + #error "GDISP Driver: Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be defined" +#endif + +#if 1 + #undef INLINE + #define INLINE inline +#else + #undef INLINE + #define INLINE +#endif + /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ -#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC - static gfxMutex gdispMutex; +#define GC ((GDISPDriver *)GDISP) +GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; + +#if GDISP_NEED_MULTITHREAD + #define MUTEX_INIT() gfxMutexInit(&GC->mutex) + #define MUTEX_ENTER() gfxMutexEnter(&GC->mutex) + #define MUTEX_EXIT() gfxMutexExit(&GC->mutex) +#else + #define MUTEX_INIT() + #define MUTEX_ENTER() + #define MUTEX_EXIT() #endif -#if GDISP_NEED_ASYNC - #define GDISP_THREAD_STACK_SIZE 256 /* Just a number - not yet a reflection of actual use */ - #define GDISP_QUEUE_SIZE 8 /* We only allow a short queue */ - - static gfxQueue gdispQueue; - static gfxMutex gdispMsgsMutex; - static gfxSem gdispMsgsSem; - static gdisp_lld_msg_t gdispMsgs[GDISP_QUEUE_SIZE]; - static DECLARE_THREAD_STACK(waGDISPThread, GDISP_THREAD_STACK_SIZE); +#if GDISP_HARDWARE_STREAM_END + #define STREAM_CLEAR() if ((GC->flags & GDISP_FLG_INSTREAM)) { \ + gdisp_lld_stream_end(); \ + GC->flags &= ~GDISP_FLG_INSTREAM; \ + } +#else + #define STREAM_CLEAR() GC->flags &= ~GDISP_FLG_INSTREAM #endif -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ +#define NEED_CLIPPING (!GDISP_HARDWARE_CLIP && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP)) -#if GDISP_NEED_ASYNC - static DECLARE_THREAD_FUNCTION(GDISPThreadHandler, arg) { - (void)arg; - gdisp_lld_msg_t *pmsg; +/*==========================================================================*/ +/* Internal functions. */ +/*==========================================================================*/ - while(1) { - /* Wait for msg with work to do. */ - pmsg = (gdisp_lld_msg_t *)gfxQueueGet(&gdispQueue, TIME_INFINITE); - - /* OK - we need to obtain the mutex in case a synchronous operation is occurring */ - gfxMutexEnter(&gdispMutex); - - gdisp_lld_msg_dispatch(pmsg); - - /* Mark the message as free */ - pmsg->action = GDISP_LLD_MSG_NOP; - - gfxMutexExit(&gdispMutex); +// drawpixel_clip() +// Parameters: x,y +// Alters: cx, cy (if using streaming) +#if GDISP_HARDWARE_DRAWPIXEL + // Best is hardware accelerated pixel draw + #if NEED_CLIPPING + static INLINE void drawpixel_clip(void) { + if (GC->p.x >= GC->clipx0 && GC->p.x < GC->clipx1 && GC->p.y >= GC->clipy0 && GC->p.y < GC->clipy1) + gdisp_lld_draw_pixel(); } - return 0; + #else + #define drawpixel_clip() gdisp_lld_draw_pixel() + #endif +#else + // Worst is streaming + static INLINE void drawpixel_clip(void) { + #if NEED_CLIPPING + if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1 || GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1) + return; + #endif + + GC->cx = GC->cy = 1; + gdisp_lld_stream_start(); + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + } +#endif + +// fillarea() +// Parameters: x,y cx,cy and color +// Alters: nothing +// Note: This is not clipped +#if GDISP_HARDWARE_FILLS + // Best is hardware accelerated area fill + #define fillarea() gdisp_lld_fill_area() +#elif GDISP_HARDWARE_STREAM + // Next best is hardware streaming + static INLINE void fillarea(void) { + uint32_t area; + + area = (uint32_t)GC->p.cx * GC->p.cy; + + gdisp_lld_stream_start(); + for(; area; area--) + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(gc); + #endif + } +#else + // Worst is drawing pixels + static INLINE void fillarea(void) { + coord_t x0, y0, x1, y1; + + x0 = GC->p.x; + y0 = GC->p.y; + x1 = GC->p.x + GC->p.cx; + y1 = GC->p.y + GC->p.cy; + for(; GC->p.y < y1; GC->p.y++, GC->p.x = x0) + for(; GC->p.x < x1; GC->p.x++) + gdisp_lld_draw_pixel(); + GC->p.y = y0; + } +#endif + +#if NEED_CLIPPING + #define TEST_CLIP_AREA(x,y,cx,cy) \ + if ((x) < GC->clipx0) { (cx) -= GC->clipx0 - (x); (x) = GC->clipx0; } \ + if ((y) < GC->clipy0) { (cy) -= GC->clipy0 - (y); (y) = GC->clipy0; } \ + if ((x) + (cx) > GC->clipx1) (cx) = GC->clipx1 - (x); \ + if ((y) + (cy) > GC->clipy1) (cy) = GC->clipy1 - (y); \ + if ((cx) > 0 && (cy) > 0) +#else + #define TEST_CLIP_AREA(x,y,cx,cy) +#endif + +// Parameters: x,y and x1 +// Alters: x,y x1,y1 cx,cy +static void hline_clip(void) { + // Swap the points if necessary so it always goes from x to x1 + if (GC->p.x1 < GC->p.x) { + GC->p.cx = GC->p.x; GC->p.x = GC->p.x1; GC->p.x1 = GC->p.cx; } - static gdisp_lld_msg_t *gdispAllocMsg(gdisp_msgaction_t action) { - gdisp_lld_msg_t *p; + // Clipping + #if NEED_CLIPPING + if (GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1) return; + if (GC->p.x < GC->clipx0) GC->p.x = GC->clipx0; + if (GC->p.x1 >= GC->clipx1) GC->p.x1 = GC->clipx1 - 1; + if (GC->p.x1 < GC->p.x) return; + #endif - while(1) { /* To be sure, to be sure */ + // This is an optimization for the point case. It is only worthwhile however if we + // have hardware fills or if we support both hardware pixel drawing and hardware streaming + #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM) + // Is this a point + if (GC->p.x == GC->p.x1) { + #if GDISP_HARDWARE_DRAWPIXEL + // Best is hardware accelerated pixel draw + gdisp_lld_draw_pixel(); + #else + // Worst is streaming + GC->p.cx = GC->p.cy = 1; + gdisp_lld_stream_start(); + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + #endif + return; + } + #endif - /* Wait for a slot */ - gfxSemWait(&gdispMsgsSem, TIME_INFINITE); + #if GDISP_HARDWARE_FILLS + // Best is hardware accelerated area fill + GC->p.cx = GC->p.x1 - GC->p.x + 1; + GC->p.cy = 1; + gdisp_lld_fill_area(); + #elif GDISP_HARDWARE_STREAM + // Next best is streaming + GC->p.cx = GC->p.x1 - GC->p.x; + gdisp_lld_stream_start(); + do { gdisp_lld_stream_color(); } while(GC->p.cx--); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + #else + // Worst is drawing pixels + for(; GC->p.x <= GC->p.x1; GC->p.x++) + gdisp_lld_draw_pixel(); + #endif +} - /* Find the slot */ - gfxMutexEnter(&gdispMsgsMutex); - for(p=gdispMsgs; p < &gdispMsgs[GDISP_QUEUE_SIZE]; p++) { - if (p->action == GDISP_LLD_MSG_NOP) { - /* Allocate it */ - p->action = action; - gfxMutexExit(&gdispMsgsMutex); - return p; - } +// Parameters: x,y and y1 +// Alters: x,y x1,y1 cx,cy +static void vline_clip(void) { + // Swap the points if necessary so it always goes from y to y1 + if (GC->p.y1 < GC->p.y) { + GC->p.cy = GC->p.y; GC->p.y = GC->p.y1; GC->p.y1 = GC->p.cy; + } + + // Clipping + #if NEED_CLIPPING + if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1) return; + if (GC->p.y < GC->clipy0) GC->p.y = GC->clipy0; + if (GC->p.y1 >= GC->clipy1) GC->p.y1 = GC->clipy1 - 1; + if (GC->p.y1 < GC->p.y) return; + #endif + + // This is an optimization for the point case. It is only worthwhile however if we + // have hardware fills or if we support both hardware pixel drawing and hardware streaming + #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM) + // Is this a point + if (GC->p.y == GC->p.y1) { + #if GDISP_HARDWARE_DRAWPIXEL + // Best is hardware accelerated pixel draw + gdisp_lld_draw_pixel(); + #else + // Worst is streaming + GC->p.cx = GC->p.cy = 1; + gdisp_lld_stream_start(); + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + #endif + return; + } + #endif + + #if GDISP_HARDWARE_FILLS + // Best is hardware accelerated area fill + GC->p.cy = GC->p.y1 - GC->p.y + 1; + GC->p.cx = 1; + gdisp_lld_fill_area(); + #elif GDISP_HARDWARE_STREAM + // Next best is streaming + GC->p.cy = GC->p.y1 - GC->p.y; + gdisp_lld_stream_start(); + do { gdisp_lld_stream_color(); } while(GC->p.cy--); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + #else + // Worst is drawing pixels + for(; GC->p.y <= GC->p.y1; GC->p.y++) + gdisp_lld_draw_pixel(); + #endif +} + +// Parameters: x,y and x1,y1 +// Alters: x,y x1,y1 cx,cy +static void line_clip(void) { + int16_t dy, dx; + int16_t addx, addy; + int16_t P, diff, i; + + // Is this a horizontal line (or a point) + if (GC->p.y == GC->p.y1) { + hline_clip(); + return; + } + + // Is this a vertical line (or a point) + if (GC->p.x == GC->p.x1) { + vline_clip(); + return; + } + + // Not horizontal or vertical + + // Use Bresenham's line drawing algorithm. + // This should be replaced with fixed point slope based line drawing + // which is more efficient on modern processors as it branches less. + // When clipping is needed, all the clipping could also be done up front + // instead of on each pixel. + + if (GC->p.x1 >= GC->p.x) { + dx = GC->p.x1 - GC->p.x; + addx = 1; + } else { + dx = GC->p.x - GC->p.x1; + addx = -1; + } + if (GC->p.y1 >= GC->p.y) { + dy = GC->p.y1 - GC->p.y; + addy = 1; + } else { + dy = GC->p.y - GC->p.y1; + addy = -1; + } + + if (dx >= dy) { + dy <<= 1; + P = dy - dx; + diff = P - dx; + + for(i=0; i<=dx; ++i) { + drawpixel_clip(); + if (P < 0) { + P += dy; + GC->p.x += addx; + } else { + P += diff; + GC->p.x += addx; + GC->p.y += addy; } - gfxMutexExit(&gdispMsgsMutex); + } + } else { + dx <<= 1; + P = dx - dy; + diff = P - dy; - /* Oops - none found, try again */ - gfxSemSignal(&gdispMsgsSem); + for(i=0; i<=dy; ++i) { + drawpixel_clip(); + if (P < 0) { + P += dx; + GC->p.y += addy; + } else { + P += diff; + GC->p.x += addx; + GC->p.y += addy; + } } } -#endif +} /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ /* Our module initialiser */ -#if GDISP_NEED_MULTITHREAD - void _gdispInit(void) { - /* Initialise Mutex */ - gfxMutexInit(&gdispMutex); +void _gdispInit(void) { + MUTEX_INIT(); - /* Initialise driver */ - gfxMutexEnter(&gdispMutex); - gdisp_lld_init(); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void _gdispInit(void) { - unsigned i; - gfxThreadHandle hth; + /* Initialise driver */ + MUTEX_ENTER(); + gdisp_lld_init(); + #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + #if GDISP_HARDWARE_CLIP + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + gdisp_lld_set_clip(); + #else + GC->clipx0 = 0; + GC->clipy0 = 0; + GC->clipx1 = GC->g.Width; + GC->clipy1 = GC->g.Height; + #endif + #endif + MUTEX_EXIT(); +} - /* Mark all the Messages as free */ - for(i=0; i < GDISP_QUEUE_SIZE; i++) - gdispMsgs[i].action = GDISP_LLD_MSG_NOP; +void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy) { + MUTEX_ENTER(); - /* Initialise our Queue, Mutex's and Counting Semaphore. - * A Mutex is required as well as the Queue and Thread because some calls have to be synchronous. - * Synchronous calls get handled by the calling thread, asynchronous by our worker thread. - */ - gfxQueueInit(&gdispQueue); - gfxMutexInit(&gdispMutex); - gfxMutexInit(&gdispMsgsMutex); - gfxSemInit(&gdispMsgsSem, GDISP_QUEUE_SIZE, GDISP_QUEUE_SIZE); + #if NEED_CLIPPING + // Test if the area is valid - if not then exit + if (x < GC->clipx0 || x+cx >= GC->clipx1 || y < GC->clipy0 || y+cy >= GC->clipy1) { + MUTEX_EXIT(); + return; + } + #endif - hth = gfxThreadCreate(waGDISPThread, sizeof(waGDISPThread), NORMAL_PRIORITY, GDISPThreadHandler, NULL); - if (hth) gfxThreadClose(hth); + GC->flags |= GDISP_FLG_INSTREAM; - /* Initialise driver - synchronous */ - gfxMutexEnter(&gdispMutex); - gdisp_lld_init(); - gfxMutexExit(&gdispMutex); - } -#else - void _gdispInit(void) { - gdisp_lld_init(); - } -#endif + #if GDISP_HARDWARE_STREAM + // Best is hardware streaming + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + gdisp_lld_stream_start(); + #else + // Worst - save the parameters and use pixel drawing -#if GDISP_NEED_MULTITHREAD - bool_t gdispIsBusy(void) { - return FALSE; - } -#elif GDISP_NEED_ASYNC - bool_t gdispIsBusy(void) { - return !gfxQueueIsEmpty(&gdispQueue); - } -#endif + // Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position + GC->p.x1 = GC->p.x = x; + GC->p.y1 = GC->p.y = y; + GC->p.x2 = GC->p.x + GC->p.cx; + GC->p.x2 = GC->p.x + GC->p.cx; + #endif -#if GDISP_NEED_MULTITHREAD - void gdispClear(color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_clear(color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void gdispClear(color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_CLEAR); - p->clear.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif + // Don't release the mutex as gdispStreamEnd() will do that. +} -#if GDISP_NEED_MULTITHREAD - void gdispDrawPixel(coord_t x, coord_t y, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_pixel(x, y, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void gdispDrawPixel(coord_t x, coord_t y, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWPIXEL); - p->drawpixel.x = x; - p->drawpixel.y = y; - p->drawpixel.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif +void gdispStreamColor(color_t color) { + // Don't touch the mutex as we should already own it + + // Ignore this call if we are not streaming + if (!(GC->flags & GDISP_FLG_INSTREAM)) + return; + + #if GDISP_HARDWARE_STREAM + // Best is hardware streaming + GC->p.color = color; + gdisp_lld_stream_color(); + #else + // Worst is using pixel drawing + GC->p.color = color; + gdisp_lld_draw_pixel(); + + // Just wrap at end-of-line and end-of-buffer + if (++GC->p.x >= GC->p.x2) { + GC->p.x = GC->p.x1; + if (++GC->p.y >= GC->p.x2) + GC->p.y = GC->p.y1; + } + #endif +} + +void gdispStreamEnd(void) { + // Only release the mutex and end the stream if we are actually streaming. + if (!(GC->flags & GDISP_FLG_INSTREAM)) + return; + + #if GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(); + #endif + GC->flags &= ~GDISP_FLG_INSTREAM; + MUTEX_EXIT(); +} + +void gdispDrawPixel(coord_t x, coord_t y, color_t color) { + MUTEX_ENTER(); + GC->p.x = x; + GC->p.y = y; + GC->p.color = color; + drawpixel_clip(); + MUTEX_EXIT(); +} -#if GDISP_NEED_MULTITHREAD - void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_line(x0, y0, x1, y1, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWLINE); - p->drawline.x0 = x0; - p->drawline.y0 = y0; - p->drawline.x1 = x1; - p->drawline.y1 = y1; - p->drawline.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif +void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { + MUTEX_ENTER(); + GC->p.x = x0; + GC->p.y = y0; + GC->p.x1 = x1; + GC->p.y1 = y1; + GC->p.color = color; + line_clip(); + MUTEX_EXIT(); +} -#if GDISP_NEED_MULTITHREAD - void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_fill_area(x, y, cx, cy, color); - gfxMutexExit(&gdispMutex); +void gdispClear(color_t color) { + // Note - clear() ignores the clipping area. It clears the screen. + MUTEX_ENTER(); + + #if GDISP_HARDWARE_CLEARS + // Best is hardware accelerated clear + GC->p.color = color; + gdisp_lld_clear(); + #elif GDISP_HARDWARE_FILLS + // Next best is hardware accelerated area fill + GC->p.x = GC->p.y = 0; + GC->p.cx = GC->g.Width; + GC->p.cy = GC->g.Height; + GC->p.color = color; + gdisp_lld_fill_area(); + #elif GDISP_HARDWARE_STREAM + // Next best is streaming + uint32_t area; + + GC->p.x = GC->p.y = 0; + GC->p.cx = GC->g.Width; + GC->p.cy = GC->g.Height; + GC->p.color = color; + area = (uint32_t)GC->p.cx * GC->p.cy; + + gdisp_lld_stream_start(); + for(; area; area--) + gdisp_lld_stream_color(); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(gc); + #endif + #else + // Worst is drawing pixels + GC->p.color = color; + for(GC->p.y = 0; GC->p.y < GC->g.Height; GC->p.y++) + for(GC->p.x = 0; GC->p.x < GC->g.Width; GC->p.x++) + gdisp_lld_draw_pixel(); + #endif + MUTEX_EXIT(); +} + +void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { + MUTEX_ENTER(); + TEST_CLIP_AREA(x,y,cx,cy) { + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + GC->p.color = color; + fillarea(); } -#elif GDISP_NEED_ASYNC - void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLAREA); - p->fillarea.x = x; - p->fillarea.y = y; - p->fillarea.cx = cx; - p->fillarea.cy = cy; - p->fillarea.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif + MUTEX_EXIT(); +} -#if GDISP_NEED_MULTITHREAD - void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_blit_area_ex(x, y, cx, cy, srcx, srcy, srccx, buffer); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ASYNC - void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_BLITAREA); - p->blitarea.x = x; - p->blitarea.y = y; - p->blitarea.cx = cx; - p->blitarea.cy = cy; - p->blitarea.srcx = srcx; - p->blitarea.srcy = srcy; - p->blitarea.srccx = srccx; - p->blitarea.buffer = buffer; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif +void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { + MUTEX_ENTER(); + + #if NEED_CLIPPING + // This is a different cliping to fillarea() as it needs to take into account srcx,srcy + if (x < GC->clipx0) { cx -= GC->clipx0 - x; srcx += GC->clipx0 - x; x = GC->clipx0; } + if (y < GC->clipy0) { cy -= GC->clipy0 - y; srcy += GC->clipy0 - x; y = GC->clipy0; } + if (x+cx > GC->clipx1) cx = GC->clipx1 - x; + if (y+cy > GC->clipy1) cy = GC->clipy1 - y; + if (srcx+cx > srccx) cx = srccx - srcx; + if (cx <= 0 || cy <= 0) { MUTEX_EXIT(); return; } + #endif + + #if GDISP_HARDWARE_BITFILLS + // Best is hardware bitfills + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + GC->p.x1 = srcx; + GC->p.y1 = srcy; + GC->p.x2 = srccx; + GC->p.ptr = (void *)buffer; + gdisp_lld_blit_area_ex(); + #elif GDISP_HARDWARE_STREAM + // Next best is hardware streaming + + // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap + buffer += srcy*srccx+srcx; + srcx = x + cx; + srcy = y + cy; + srccx -= cx; + + gdisp_lld_stream_start(gc); + for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { + for(GC->p.x = x; GC->p.x < srcx; GC->p.x++) { + GC->p.color = *buffer++; + gdisp_lld_stream_color(); + } + } + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(gc); + #endif + #else + // Worst is drawing pixels + + // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap + buffer += srcy*srccx+srcx; + srcx = x + cx; + srcy = y + cy; + srccx -= cx; + + for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { + for(GC->p.x=x; GC->p.x < srcx; GC->p.x++) { + GC->p.color = *buffer++; + gdisp_lld_draw_pixel(); + } + } + #endif + MUTEX_EXIT(); +} -#if (GDISP_NEED_CLIP && GDISP_NEED_MULTITHREAD) +#if GDISP_NEED_CLIP void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_set_clip(x, y, cx, cy); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_CLIP && GDISP_NEED_ASYNC - void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_SETCLIP); - p->setclip.x = x; - p->setclip.y = y; - p->setclip.cx = cx; - p->setclip.cy = cy; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); + MUTEX_ENTER(); + #if GDISP_HARDWARE_CLIP + // Best is using hardware clipping + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + gdisp_lld_set_clip(); + #else + // Worst is using software clipping + if (x < 0) { cx += x; x = 0; } + if (y < 0) { cy += y; y = 0; } + if (cx <= 0 || cy <= 0 || x >= GC->g.Width || y >= GC->g.Height) { MUTEX_EXIT(); return; } + GC->clipx0 = x; + GC->clipy0 = y; + GC->clipx1 = x+cx; if (GC->clipx1 > GC->g.Width) GC->clipx1 = GC->g.Width; + GC->clipy1 = y+cy; if (GC->clipy1 > GC->g.Height) GC->clipy1 = GC->g.Height; + #endif + MUTEX_EXIT(); } #endif -#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD) +#if GDISP_NEED_CIRCLE void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_circle(x, y, radius, color); - gfxMutexExit(&gdispMutex); + coord_t a, b, P; + + MUTEX_ENTER(); + + // Calculate intermediates + a = 1; + b = radius; + P = 4 - radius; + GC->p.color = color; + + // Away we go using Bresenham's circle algorithm + // Optimized to prevent double drawing + GC->p.x = x; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x; GC->p.y = y - b; drawpixel_clip(); + GC->p.x = x + b; GC->p.y = y; drawpixel_clip(); + GC->p.x = x - b; GC->p.y = y; drawpixel_clip(); + do { + GC->p.x = x + a; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x + a; GC->p.y = y - b; drawpixel_clip(); + GC->p.x = x + b; GC->p.y = y + a; drawpixel_clip(); + GC->p.x = x - b; GC->p.y = y + a; drawpixel_clip(); + GC->p.x = x - a; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x - a; GC->p.y = y - b; drawpixel_clip(); + GC->p.x = x + b; GC->p.y = y - a; drawpixel_clip(); + GC->p.x = x - b; GC->p.y = y - a; drawpixel_clip(); + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + GC->p.x = x + a; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x + a; GC->p.y = y - b; drawpixel_clip(); + GC->p.x = x - a; GC->p.y = y + b; drawpixel_clip(); + GC->p.x = x - a; GC->p.y = y - b; drawpixel_clip(); + MUTEX_EXIT(); } -#elif GDISP_NEED_CIRCLE && GDISP_NEED_ASYNC - void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWCIRCLE); - p->drawcircle.x = x; - p->drawcircle.y = y; - p->drawcircle.radius = radius; - p->drawcircle.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); +#endif + +#if GDISP_NEED_CIRCLE + void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) { + coord_t a, b, P; + + MUTEX_ENTER(); + + // Calculate intermediates + a = 1; + b = radius; + P = 4 - radius; + GC->p.color = color; + + // Away we go using Bresenham's circle algorithm + // This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + GC->p.y = y+b; GC->p.x = x; drawpixel_clip(); + GC->p.y = y-b; GC->p.x = x; drawpixel_clip(); + do { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + if (P < 0) { + P += 3 + 2*a++; + } else { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); + P += 5 + 2*(a++ - b--); + } + } while(a < b); + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + MUTEX_EXIT(); + } +#endif + +#if GDISP_NEED_ELLIPSE + void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { + coord_t dx, dy; + int32_t a2, b2; + int32_t err, e2; + + MUTEX_ENTER(); + + // Calculate intermediates + dx = 0; + dy = b; + a2 = a*a; + b2 = b*b; + err = b2-(2*b-1)*a2; + GC->p.color = color; + + // Away we go using Bresenham's ellipse algorithm + do { + GC->p.x = x + dx; GC->p.y = y + dy; drawpixel_clip(); + GC->p.x = x - dx; GC->p.y = y + dy; drawpixel_clip(); + GC->p.x = x - dx; GC->p.y = y - dy; drawpixel_clip(); + GC->p.x = x + dx; GC->p.y = y - dy; drawpixel_clip(); + + e2 = 2*err; + if(e2 < (2*dx+1)*b2) { + dx++; + err += (2*dx+1)*b2; + } + if(e2 > -(2*dy-1)*a2) { + dy--; + err -= (2*dy-1)*a2; + } + } while(dy >= 0); + MUTEX_EXIT(); } #endif -#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD) - void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_fill_circle(x, y, radius, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_CIRCLE && GDISP_NEED_ASYNC - void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLCIRCLE); - p->fillcircle.x = x; - p->fillcircle.y = y; - p->fillcircle.radius = radius; - p->fillcircle.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif - -#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD) - void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_ellipse(x, y, a, b, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ELLIPSE && GDISP_NEED_ASYNC - void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWELLIPSE); - p->drawellipse.x = x; - p->drawellipse.y = y; - p->drawellipse.a = a; - p->drawellipse.b = b; - p->drawellipse.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif - -#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD) +#if GDISP_NEED_ELLIPSE void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_fill_ellipse(x, y, a, b, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ELLIPSE && GDISP_NEED_ASYNC - void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLELLIPSE); - p->fillellipse.x = x; - p->fillellipse.y = y; - p->fillellipse.a = a; - p->fillellipse.b = b; - p->fillellipse.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif + coord_t dx, dy; + int32_t a2, b2; + int32_t err, e2; -#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) - void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_draw_arc(x, y, radius, start, end, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ARC && GDISP_NEED_ASYNC - void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWARC); - p->drawarc.x = x; - p->drawarc.y = y; - p->drawarc.radius = radius; - p->drawarc.start = start; - p->drawarc.end = end; - p->drawarc.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } -#endif + MUTEX_ENTER(); -#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) - void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_fill_arc(x, y, radius, start, end, color); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_ARC && GDISP_NEED_ASYNC - void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLARC); - p->fillarc.x = x; - p->fillarc.y = y; - p->fillarc.radius = radius; - p->fillarc.start = start; - p->fillarc.end = end; - p->fillarc.color = color; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); + // Calculate intermediates + dx = 0; + dy = b; + a2 = a*a; + b2 = b*b; + err = b2-(2*b-1)*a2; + GC->p.color = color; + + // Away we go using Bresenham's ellipse algorithm + // This is optimized to prevent overdrawing by drawing a line only when a y is about to change value + do { + e2 = 2*err; + if(e2 < (2*dx+1)*b2) { + dx++; + err += (2*dx+1)*b2; + } + if(e2 > -(2*dy-1)*a2) { + GC->p.y = y + dy; GC->p.x = x - dx; GC->p.x1 = x + dx; hline_clip(); + if (y) { GC->p.y = y - dy; GC->p.x = x - dx; GC->p.x1 = x + dx; hline_clip(); } + dy--; + err -= (2*dy-1)*a2; + } + } while(dy >= 0); + MUTEX_EXIT(); } #endif #if GDISP_NEED_ARC -void gdispDrawRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { - if (2*radius > cx || 2*radius > cy) { - gdispDrawBox(x, y, cx, cy, color); - return; + #if !GMISC_NEED_FIXEDTRIG && !GMISC_NEED_FASTTRIG + #include + #endif + + void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { + coord_t a, b, P, sedge, eedge; + uint8_t full, sbit, ebit, tbit; + + // Normalize the angles + if (start < 0) + start -= (start/360-1)*360; + else if (start >= 360) + start %= 360; + if (end < 0) + end -= (end/360-1)*360; + else if (end >= 360) + end %= 360; + + sbit = 1<<(start/45); + ebit = 1<<(end/45); + full = 0; + if (start == end) { + full = 0xFF; + } else if (end < start) { + for(tbit=sbit<<1; tbit; tbit<<=1) full |= tbit; + for(tbit=ebit>>1; tbit; tbit>>=1) full |= tbit; + } else if (sbit < 0x80) { + for(tbit=sbit<<1; tbit < ebit; tbit<<=1) full |= tbit; + } + + MUTEX_ENTER(); + GC->p.color = color; + + if (full) { + // Draw full sectors + // Optimized to prevent double drawing + a = 1; + b = radius; + P = 4 - radius; + if (full & 0x60) { GC->p.y = y+b; GC->p.x = x; drawpixel_clip(); } + if (full & 0x06) { GC->p.y = y-b; GC->p.x = x; drawpixel_clip(); } + if (full & 0x81) { GC->p.y = y; GC->p.x = x+b; drawpixel_clip(); } + if (full & 0x18) { GC->p.y = y; GC->p.x = x-b; drawpixel_clip(); } + do { + if (full & 0x01) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } + if (full & 0x02) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (full & 0x04) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (full & 0x08) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } + if (full & 0x10) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } + if (full & 0x20) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if (full & 0x40) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (full & 0x80) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + if (full & 0xC0) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (full & 0x0C) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (full & 0x03) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (full & 0x30) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if (full == 0xFF) + return; + } + + #if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG + sedge = NONFIXED(radius * ((sbit & 0x99) ? ffsin(start) : ffcos(start)) + FIXED0_5); + eedge = NONFIXED(radius * ((ebit & 0x99) ? ffsin(end) : ffcos(end)) + FIXED0_5); + #elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG + sedge = round(radius * ((sbit & 0x99) ? fsin(start) : fcos(start))); + eedge = round(radius * ((ebit & 0x99) ? fsin(end) : fcos(end))); + #else + sedge = round(radius * ((sbit & 0x99) ? sin(start*M_PI/180) : cos(start*M_PI/180))); + eedge = round(radius * ((ebit & 0x99) ? sin(end*M_PI/180) : cos(end*M_PI/180))); + #endif + if (sbit & 0xB4) sedge = -sedge; + if (ebit & 0xB4) eedge = -eedge; + + if (sbit != ebit) { + // Draw start and end sectors + // Optimized to prevent double drawing + a = 1; + b = radius; + P = 4 - radius; + if ((sbit & 0x20) || (ebit & 0x40)) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); } + if ((sbit & 0x02) || (ebit & 0x04)) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); } + if ((sbit & 0x80) || (ebit & 0x01)) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); } + if ((sbit & 0x08) || (ebit & 0x10)) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); } + do { + if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } + if (((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } + if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } + if (((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge) || ((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) + { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge) || ((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) + { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge) || ((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) + { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge) || ((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) + { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + } else if (end < start) { + // Draw start/end sector where it is a non-internal angle + // Optimized to prevent double drawing + a = 1; + b = radius; + P = 4 - radius; + if (sbit & 0x60) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); } + if (sbit & 0x06) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); } + if (sbit & 0x81) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); } + if (sbit & 0x18) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); } + do { + if ((sbit & 0x01) && (a >= sedge || a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } + if ((sbit & 0x02) && (a <= sedge || a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if ((sbit & 0x04) && (a >= sedge || a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if ((sbit & 0x08) && (a <= sedge || a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } + if ((sbit & 0x10) && (a >= sedge || a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } + if ((sbit & 0x20) && (a <= sedge || a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if ((sbit & 0x40) && (a >= sedge || a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if ((sbit & 0x80) && (a <= sedge || a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + if (((sbit & 0x04) && (a >= sedge || a <= eedge)) || ((sbit & 0x08) && (a <= sedge || a >= eedge))) + { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x40) && (a >= sedge || a <= eedge)) || ((sbit & 0x80) && (a <= sedge || a >= eedge))) + { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x01) && (a >= sedge || a <= eedge)) || ((sbit & 0x02) && (a <= sedge || a >= eedge))) + { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x10) && (a >= sedge || a <= eedge)) || ((sbit & 0x20) && (a <= sedge || a >= eedge))) + { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + } else { + // Draw start/end sector where it is a internal angle + // Optimized to prevent double drawing + a = 1; + b = radius; + P = 4 - radius; + if (((sbit & 0x20) && !eedge) || ((sbit & 0x40) && !sedge)) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x02) && !eedge) || ((sbit & 0x04) && !sedge)) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x80) && !eedge) || ((sbit & 0x01) && !sedge)) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); } + if (((sbit & 0x08) && !eedge) || ((sbit & 0x10) && !sedge)) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); } + do { + if (((sbit & 0x01) && a >= sedge && a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } + if (((sbit & 0x02) && a <= sedge && a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x04) && a >= sedge && a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x08) && a <= sedge && a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } + if (((sbit & 0x10) && a >= sedge && a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } + if (((sbit & 0x20) && a <= sedge && a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x40) && a >= sedge && a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x80) && a <= sedge && a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (P < 0) + P += 3 + 2*a++; + else + P += 5 + 2*(a++ - b--); + } while(a < b); + if (((sbit & 0x04) && a >= sedge && a <= eedge) || ((sbit & 0x08) && a <= sedge && a >= eedge)) + { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x40) && a >= sedge && a <= eedge) || ((sbit & 0x80) && a <= sedge && a >= eedge)) + { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + if (((sbit & 0x01) && a >= sedge && a <= eedge) || ((sbit & 0x02) && a <= sedge && a >= eedge)) + { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + if (((sbit & 0x10) && a >= sedge && a <= eedge) || ((sbit & 0x20) && a <= sedge && a >= eedge)) + { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + } + MUTEX_EXIT(); } - gdispDrawArc(x+radius, y+radius, radius, 90, 180, color); - gdispDrawLine(x+radius+1, y, x+cx-2-radius, y, color); - gdispDrawArc(x+cx-1-radius, y+radius, radius, 0, 90, color); - gdispDrawLine(x+cx-1, y+radius+1, x+cx-1, y+cy-2-radius, color); - gdispDrawArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color); - gdispDrawLine(x+radius+1, y+cy-1, x+cx-2-radius, y+cy-1, color); - gdispDrawArc(x+radius, y+cy-1-radius, radius, 180, 270, color); - gdispDrawLine(x, y+radius+1, x, y+cy-2-radius, color); -} #endif #if GDISP_NEED_ARC -void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { - coord_t radius2; + void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { + coord_t a, b, P; + coord_t sy, ey; + fixed sxa, sxb, sxd, exa, exb, exd; + uint8_t qtr; - radius2 = radius*2; - if (radius2 > cx || radius2 > cy) { - gdispFillArea(x, y, cx, cy, color); - return; + MUTEX_ENTER(); + + // Do the trig to get the formulas for the start and end lines. + sxa = exa = FIXED(x)+FIXED0_5; + #if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG + sxb = radius*ffcos(start); sy = -NONFIXED(radius*ffsin(start) + FIXED0_5); + exb = radius*ffcos(end); ey = -NONFIXED(radius*ffsin(end) + FIXED0_5); + #elif GFX_USE_GMISC && GMISC_NEED_FASTTRIG + sxb = FP2FIXED(radius*fcos(start)); sy = -round(radius*fsin(start)); + exb = FP2FIXED(radius*fcos(end)); ey = -round(radius*fsin(end)); + #else + sxb = FP2FIXED(radius*cos(start*M_PI/180)); sy = -round(radius*sin(start*M_PI/180)); + exb = FP2FIXED(radius*cos(end*M_PI/180)); ey = -round(radius*sin(end*M_PI/180)); + #endif + sxd = sy ? sxb/sy : sxb; + exd = ey ? exb/ey : exb; + + // Calculate which quarters and which direction we are traveling + qtr = 0; + if (sxb > 0) qtr |= 0x01; // S1=0001(1), S2=0000(0), S3=0010(2), S4=0011(3) + if (sy > 0) qtr |= 0x02; + if (exb > 0) qtr |= 0x04; // E1=0100(4), E2=0000(0), E3=1000(8), E4=1100(12) + if (ey > 0) qtr |= 0x08; + if (sy > ey) qtr |= 0x10; // order of start and end lines + + // Calculate intermediates + a = 1; + b = radius; + P = 4 - radius; + GC->p.color = color; + sxb += sxa; + exb += exa; + + // Away we go using Bresenham's circle algorithm + // This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value + + switch(qtr) { + case 0: // S2E2 sy <= ey + case 1: // S1E2 sy <= ey + if (ey && sy) { + GC->p.x = x; GC->p.x1 = x; // E2S + sxa -= sxd; exa -= exd; + } else if (sy) { + GC->p.x = x-b; GC->p.x1 = x; // C2S + sxa -= sxd; + } else if (ey) { + GC->p.x = x; GC->p.x1 = x+b; // E2C + exa -= exd; + } else { + GC->p.x = x-b; GC->p.x1 = x+b; // C2C + } + GC->p.y = y; + hline_clip(); + do { + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + sxa -= sxd; exa -= exd; + } else if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + sxa -= sxd; + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= ey) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = NONFIXED(sxb); hline_clip(); // E2S + sxb += sxd; exb += exd; + } else if (-b >= sy) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + sxb += sxd; + } else if (qtr & 1) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + } else if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 2: // S3E2 sy <= ey + case 3: // S4E2 sy <= ey + case 6: // S3E1 sy <= ey + case 7: // S4E1 sy <= ey + case 18: // S3E2 sy > ey + case 19: // S4E2 sy > ey + case 22: // S3E1 sy > ey + case 23: // S4E1 sy > ey + GC->p.y = y; GC->p.x = x; GC->p.x1 = x+b; hline_clip(); // SE2C + sxa += sxd; exa -= exd; + do { + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + exa -= exd; + } else if (!(qtr & 4)) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= ey) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + exb += exd; + } else if (!(qtr & 4)) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + if (b <= sy) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (!(qtr & 4)) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+a; hline_clip(); // S2C + } else if (!(qtr & 1)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+a; hline_clip(); // C2C + } + break; + + case 4: // S2E1 sy <= ey + case 5: // S1E1 sy <= ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + do { + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + sxa -= sxd; exa -= exd; + } else if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + sxa -= sxd; + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= ey) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + sxb += sxd; exb += exd; + } else if (-b >= sy) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + sxb += sxd; + } else if (qtr & 1) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= ey) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + break; + + case 8: // S2E3 sy <= ey + case 9: // S1E3 sy <= ey + case 12: // S2E4 sy <= ey + case 13: // S1E4 sy <= ey + case 24: // S2E3 sy > ey + case 25: // S1E3 sy > ey + case 28: // S2E3 sy > ey + case 29: // S1E3 sy > ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x; hline_clip(); // C2SE + sxa -= sxd; exa += exd; + do { + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + sxa -= sxd; + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + exa += exd; + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= sy) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + sxb += sxd; + } else if (qtr & 1) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + if (b <= ey) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + exb -= exd; + } else if (qtr & 4) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + } else if (qtr & 1) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+a; hline_clip(); // C2C + } + break; + + case 10: // S3E3 sy <= ey + case 14: // S3E4 sy <= ey + GC->p.y = y; GC->p.x = x; drawpixel_clip(); // S2E + sxa += sxd; exa += exd; + do { + if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip(); // S2E + sxa += sxd; exa += exd; + } else if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + exa += exd; + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (b <= sy) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = NONFIXED(exb); hline_clip(); // S2E + sxb -= sxd; exb -= exd; + } else if (b <= ey) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + exb -= exd; + } else if (qtr & 4) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip(); // S2E + } else if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 11: // S4E3 sy <= ey + case 15: // S4E4 sy <= ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + do { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (a <= sy) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; exa += exd; + } else if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + exa += exd; + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + if (b <= sy) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; exb -= exd; + } else if (b <= ey) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + exb -= exd; + } else if (qtr & 4) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (a <= sy) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + } else if (qtr & 4) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 16: // S2E2 sy > ey + case 20: // S2E1 sy > ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + sxa -= sxd; exa -= exd; + do { + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + sxa -= sxd; exa -= exd; + } else if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + exa -= exd; + } else if (!(qtr & 4)){ + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= sy) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + sxb += sxd; exb += exd; + } else if (-b >= ey) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + exb += exd; + } else if (!(qtr & 4)){ + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (!(qtr & 4)){ + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + break; + + case 17: // S1E2 sy > ey + case 21: // S1E1 sy > ey + if (sy) { + GC->p.x = x; GC->p.x1 = x; // E2S + sxa -= sxd; exa -= exd; + } else { + GC->p.x = x; GC->p.x1 = x+b; // E2C + exa -= exd; + } + GC->p.y = y; + hline_clip(); + do { + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + sxa -= sxd; exa -= exd; + } else if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + exa -= exd; + } else if (!(qtr & 4)) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (-b >= sy) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = NONFIXED(sxb); hline_clip(); // E2S + sxb += sxd; exb += exd; + } else if (-b >= ey) { + GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + exb += exd; + } else if (!(qtr & 4)) { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (-a >= sy) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + } else if (-a >= ey) { + GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + } else if (!(qtr & 4)) { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 26: // S3E3 sy > ey + case 27: // S4E3 sy > ey + GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + do { + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; exa += exd; + } else if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + if (b <= ey) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; exb -= exd; + } else if (b <= sy) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + if (a <= ey) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (!(qtr & 4)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + + case 30: // S3E4 sy > ey + case 31: // S4E4 sy > ey + do { + if (a <= ey) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip(); // S2E + sxa += sxd; exa += exd; + } else if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + sxa += sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + if (P < 0) { + P += 3 + 2*a++; + } else { + if (b <= ey) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = NONFIXED(exb); hline_clip(); // S2E + sxb -= sxd; exb -= exd; + } else if (b <= sy) { + GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + sxb -= sxd; + } else if (!(qtr & 1)) { + GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + } + P += 5 + 2*(a++ - b--); + } + } while(a < b); + if (a <= ey) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (a <= sy) { + GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + } else if (!(qtr & 4)) { + GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + } + break; + } + + MUTEX_EXIT(); } - gdispFillArc(x+radius, y+radius, radius, 90, 180, color); - gdispFillArea(x+radius+1, y, cx-radius2, radius, color); - gdispFillArc(x+cx-1-radius, y+radius, radius, 0, 90, color); - gdispFillArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color); - gdispFillArea(x+radius+1, y+cy-radius, cx-radius2, radius, color); - gdispFillArc(x+radius, y+cy-1-radius, radius, 180, 270, color); - gdispFillArea(x, y+radius, cx, cy-radius2, color); -} + #endif -#if (GDISP_NEED_PIXELREAD && (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC)) +#if GDISP_NEED_ARC + void gdispDrawRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { + if (2*radius > cx || 2*radius > cy) { + gdispDrawBox(x, y, cx, cy, color); + return; + } + gdispDrawArc(x+radius, y+radius, radius, 90, 180, color); + gdispDrawLine(x+radius+1, y, x+cx-2-radius, y, color); + gdispDrawArc(x+cx-1-radius, y+radius, radius, 0, 90, color); + gdispDrawLine(x+cx-1, y+radius+1, x+cx-1, y+cy-2-radius, color); + gdispDrawArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color); + gdispDrawLine(x+radius+1, y+cy-1, x+cx-2-radius, y+cy-1, color); + gdispDrawArc(x+radius, y+cy-1-radius, radius, 180, 270, color); + gdispDrawLine(x, y+radius+1, x, y+cy-2-radius, color); + } +#endif + +#if GDISP_NEED_ARC + void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { + coord_t radius2; + + radius2 = radius*2; + if (radius2 > cx || radius2 > cy) { + gdispFillArea(x, y, cx, cy, color); + return; + } + gdispFillArc(x+radius, y+radius, radius, 90, 180, color); + gdispFillArea(x+radius+1, y, cx-radius2, radius, color); + gdispFillArc(x+cx-1-radius, y+radius, radius, 0, 90, color); + gdispFillArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color); + gdispFillArea(x+radius+1, y+cy-radius, cx-radius2, radius, color); + gdispFillArc(x+radius, y+cy-1-radius, radius, 180, 270, color); + gdispFillArea(x, y+radius, cx, cy-radius2, color); + } +#endif + +#if GDISP_NEED_PIXELREAD color_t gdispGetPixelColor(coord_t x, coord_t y) { color_t c; /* Always synchronous as it must return a value */ - gfxMutexEnter(&gdispMutex); - c = gdisp_lld_get_pixel_color(x, y); - gfxMutexExit(&gdispMutex); + MUTEX_ENTER(); + GC->p.x = x; + GC->p.y = y; + c = gdisp_lld_get_pixel_color(); + MUTEX_EXIT(); return c; } #endif -#if (GDISP_NEED_SCROLL && GDISP_NEED_MULTITHREAD) +#if GDISP_NEED_SCROLL void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_vertical_scroll(x, y, cx, cy, lines, bgcolor); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_SCROLL && GDISP_NEED_ASYNC - void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_VERTICALSCROLL); - p->verticalscroll.x = x; - p->verticalscroll.y = y; - p->verticalscroll.cx = cx; - p->verticalscroll.cy = cy; - p->verticalscroll.lines = lines; - p->verticalscroll.bgcolor = bgcolor; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); + MUTEX_ENTER(); + #if NEED_CLIPPING + if (x < GC->clipx0) { cx -= GC->clipx0 - x; x = GC->clipx0; } + if (y < GC->clipy0) { cy -= GC->clipy0 - y; y = GC->clipy0; } + if (cx <= 0 || cy <= 0 || x >= GC->clipx1 || y >= GC->clipy1) { MUTEX_EXIT(); return; } + if (x+cx > GC->clipx1) cx = GC->clipx1 - x; + if (y+cy > GC->clipy1) cy = GC->clipy1 - y; + #endif + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + GC->p.y1 = lines; + GC->p.color = bgcolor; + gdisp_lld_vertical_scroll(); + MUTEX_EXIT(); } #endif -#if (GDISP_NEED_CONTROL && GDISP_NEED_MULTITHREAD) - void gdispControl(unsigned what, void *value) { - gfxMutexEnter(&gdispMutex); - gdisp_lld_control(what, value); - gfxMutexExit(&gdispMutex); - } -#elif GDISP_NEED_CONTROL && GDISP_NEED_ASYNC - void gdispControl(unsigned what, void *value) { - gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_CONTROL); - p->control.what = what; - p->control.value = value; - gfxQueuePut(&gdispQueue, &p->qi, TIME_IMMEDIATE); - } +#if GDISP_NEED_CONTROL + #if GDISP_HARDWARE_CONTROL + void gdispControl(unsigned what, void *value) { + MUTEX_ENTER(); + GC->p.x = what; + GC->p.ptr = value; + gdisp_lld_control(); + #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION + if (what == GDISP_CONTROL_ORIENTATION) { + #if GDISP_HARDWARE_CLIP + // Best is hardware clipping + GC->p.x = 0; + GC->p.y = 0; + GC->p.cx = GC->g.Width; + GC->p.cy = GC->g.Height; + gdisp_lld_set_clip(); + #else + // Worst is software clipping + GC->clipx0 = 0; + GC->clipy0 = 0; + GC->clipx1 = GC->g.Width; + GC->clipy1 = GC->g.Height; + #endif + } + #endif + MUTEX_EXIT(); + } + #else + void gdispControl(unsigned what, void *value) { + (void)what; + (void)value; + /* Ignore everything */ + } + #endif #endif -#if (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC) && GDISP_NEED_QUERY - void *gdispQuery(unsigned what) { - void *res; +#if GDISP_NEED_QUERY + #if GDISP_HARDWARE_QUERY + void *gdispQuery(unsigned what) { + void *res; - gfxMutexEnter(&gdispMutex); - res = gdisp_lld_query(what); - gfxMutexExit(&gdispMutex); - return res; - } + MUTEX_ENTER(); + GC->p.x = (coord_t)what; + res = gdisp_lld_query(); + MUTEX_EXIT(); + return res; + } + #else + void *gdispQuery(unsigned what) { + (void) what; + return (void *)-1; + } + #endif #endif /*===========================================================================*/ @@ -458,29 +1546,30 @@ void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t r /*===========================================================================*/ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - /* No mutex required as we only call high level functions which have their own mutex */ - coord_t x1, y1; + if (cx <= 0 || cy <= 0) return; + cx = x+cx-1; cy = y+cy-1; // cx, cy are now the end point. - x1 = x+cx-1; - y1 = y+cy-1; + MUTEX_ENTER(); - if (cx > 2) { - if (cy >= 1) { - gdispDrawLine(x, y, x1, y, color); - if (cy >= 2) { - gdispDrawLine(x, y1, x1, y1, color); - if (cy > 2) { - gdispDrawLine(x, y+1, x, y1-1, color); - gdispDrawLine(x1, y+1, x1, y1-1, color); - } + GC->p.color = color; + + if (cx - x > 2) { + GC->p.x = x; GC->p.y = y; GC->p.x1 = cx; hline_clip(); + if (y != cy) { + GC->p.x = x; GC->p.y = cy; GC->p.x1 = cx; hline_clip(); + if (cy - y > 2) { + y++; cy--; + GC->p.x = x; GC->p.y = y; GC->p.y1 = cy; vline_clip(); + GC->p.x = cx; GC->p.y = y; GC->p.y1 = cy; vline_clip(); } } - } else if (cx == 2) { - gdispDrawLine(x, y, x, y1, color); - gdispDrawLine(x1, y, x1, y1, color); - } else if (cx == 1) { - gdispDrawLine(x, y, x, y1, color); + } else { + GC->p.x = x; GC->p.y = y; GC->p.y1 = cy; vline_clip(); + if (x != cx) { + GC->p.x = cx; GC->p.y = y; GC->p.y1 = cy; vline_clip(); + } } + MUTEX_EXIT(); } #if GDISP_NEED_CONVEX_POLYGON @@ -488,9 +1577,14 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { const point *epnt, *p; epnt = &pntarray[cnt-1]; - for(p = pntarray; p < epnt; p++) - gdispDrawLine(tx+p->x, ty+p->y, tx+p[1].x, ty+p[1].y, color); - gdispDrawLine(tx+p->x, ty+p->y, tx+pntarray->x, ty+pntarray->y, color); + + MUTEX_ENTER(); + GC->p.color = color; + for(p = pntarray; p < epnt; p++) { + GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+p[1].x; GC->p.y1=ty+p[1].y; line_clip(); + } + GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+pntarray->x; GC->p.y1=ty+pntarray->y; line_clip(); + MUTEX_EXIT(); } void gdispFillConvexPoly(coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) { @@ -510,21 +1604,21 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { y = rpnt->y; /* Work out the slopes of the two attached line segs */ - lpnt = rpnt <= pntarray ? epnts : rpnt-1; - while (lpnt->y == y) { + for (lpnt = rpnt <= pntarray ? epnts : rpnt-1; lpnt->y == y; cnt--) { + if (!cnt) return; lx = FIXED(lpnt->x); lpnt = lpnt <= pntarray ? epnts : lpnt-1; - if (!cnt--) return; } - rpnt = rpnt >= epnts ? pntarray : rpnt+1; - while (rpnt->y == y) { - rx = rpnt->x<<16; + for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) { + if (!cnt) return; + rx = FIXED(rpnt->x); rpnt = rpnt >= epnts ? pntarray : rpnt+1; - if (!cnt--) return; } lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y); rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y); + MUTEX_ENTER(); + GC->p.color = color; while(1) { /* Determine our boundary */ ymax = rpnt->y < lpnt->y ? rpnt->y : lpnt->y; @@ -539,38 +1633,40 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { * of pixels. */ if (lxc < rxc) { - if (rxc - lxc == 1) - gdispDrawPixel(tx+lxc, ty+y, color); - else - gdispDrawLine(tx+lxc, ty+y, tx+rxc-1, ty+y, color); + GC->p.x=tx+lxc; GC->p.y=ty+y; GC->p.x1=tx+rxc-1; hline_clip(); } else if (lxc > rxc) { - if (lxc - rxc == 1) - gdispDrawPixel(tx+rxc, ty+y, color); - else - gdispDrawLine(tx+rxc, ty+y, tx+lxc-1, ty+y, color); + GC->p.x=tx+rxc; GC->p.y=ty+y; GC->p.x1=tx+lxc-1; hline_clip(); } lx += lk; rx += rk; } - if (!cnt--) return; + if (!cnt) { + MUTEX_EXIT(); + return; + } + cnt--; /* Replace the appropriate point */ if (ymax == lpnt->y) { - lpnt = lpnt <= pntarray ? epnts : lpnt-1; - while (lpnt->y == y) { + for (lpnt = lpnt <= pntarray ? epnts : lpnt-1; lpnt->y == y; cnt--) { + if (!cnt) { + MUTEX_EXIT(); + return; + } lx = FIXED(lpnt->x); lpnt = lpnt <= pntarray ? epnts : lpnt-1; - if (!cnt--) return; } lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y); } else { - rpnt = rpnt >= epnts ? pntarray : rpnt+1; - while (rpnt->y == y) { + for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) { + if (!cnt) { + MUTEX_EXIT(); + return; + } rx = FIXED(rpnt->x); rpnt = rpnt >= epnts ? pntarray : rpnt+1; - if (!cnt--) return; } rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y); } @@ -582,146 +1678,130 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { #include "mcufont.h" #if GDISP_NEED_ANTIALIAS && GDISP_NEED_PIXELREAD - static void text_draw_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return; if (alpha == 255) { - if (count == 1) - gdispDrawPixel(x, y, ((color_t *)state)[0]); - else - gdispFillArea(x, y, count, 1, ((color_t *)state)[0]); + GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; GC->p.color = GC->t.color; + hline_clip(); } else { - while (count--) { - gdispDrawPixel(x, y, gdispBlendColor(((color_t *)state)[0], gdispGetPixelColor(x, y), alpha)); - x++; + for (; count; count--, x++) { + GC->p.x = x; GC->p.y = y; + GC->p.color = gdispBlendColor(GC->t.color, gdisp_lld_get_pixel_color(), alpha); + drawpixel_clip(); } } } #else - static void text_draw_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + (void) state; + if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return; if (alpha > 0x80) { // A best approximation when using anti-aliased fonts but we can't actually draw them anti-aliased - if (count == 1) - gdispDrawPixel(x, y, ((color_t *)state)[0]); - else - gdispFillArea(x, y, count, 1, ((color_t *)state)[0]); + GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; GC->p.color = GC->t.color; + hline_clip(); } } #endif - void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color) { - /* No mutex required as we only call high level functions which have their own mutex */ - mf_render_character(font, x, y, c, text_draw_char_callback, &color); - } - #if GDISP_NEED_ANTIALIAS - static void text_fill_char_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + static void fillcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { + (void) state; + if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return; if (alpha == 255) { - if (count == 1) - gdispDrawPixel(x, y, ((color_t *)state)[0]); - else - gdispFillArea(x, y, count, 1, ((color_t *)state)[0]); + GC->p.color = GC->t.color; } else { - while (count--) { - gdispDrawPixel(x, y, gdispBlendColor(((color_t *)state)[0], ((color_t *)state)[1], alpha)); - x++; - } + GC->p.color = gdispBlendColor(GC->t.color, GC->t.bgcolor, alpha); } + GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; + hline_clip(); } #else - #define text_fill_char_callback text_draw_char_callback + #define fillcharline drawcharline #endif - void gdispFillChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) { - /* No mutex required as we only call high level functions which have their own mutex */ - color_t state[2]; - - state[0] = color; - state[1] = bgcolor; - - gdispFillArea(x, y, mf_character_width(font, c) + font->baseline_x, font->height, bgcolor); - mf_render_character(font, x, y, c, text_fill_char_callback, state); + /* Callback to render characters. */ + static uint8_t drawcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { + (void) state; + return mf_render_character(GC->t.font, x, y, ch, drawcharline, 0); } - typedef struct - { - font_t font; - color_t color; - coord_t x, y; - coord_t cx, cy; - } gdispDrawString_state_t; - /* Callback to render characters. */ - static uint8_t gdispDrawString_callback(int16_t x, int16_t y, mf_char character, void *state) - { - gdispDrawString_state_t *s = state; - uint8_t w; - - w = mf_character_width(s->font, character); - if (x >= s->x && x+w < s->x + s->cx && y >= s->y && y+s->font->height <= s->y + s->cy) - mf_render_character(s->font, x, y, character, text_draw_char_callback, &s->color); - return w; + static uint8_t fillcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { + (void) state; + return mf_render_character(GC->t.font, x, y, ch, fillcharline, 0); + } + + void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color) { + MUTEX_ENTER(); + GC->t.font = font; + GC->t.clipx0 = x; + GC->t.clipy0 = y; + GC->t.clipx1 = x + mf_character_width(font, c) + font->baseline_x; + GC->t.clipy1 = y + font->height; + GC->t.color = color; + mf_render_character(font, x, y, c, drawcharline, 0); + MUTEX_EXIT(); + } + + void gdispFillChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) { + MUTEX_ENTER(); + GC->p.cx = mf_character_width(font, c) + font->baseline_x; + GC->p.cy = font->height; + GC->t.font = font; + GC->t.clipx0 = GC->p.x = x; + GC->t.clipy0 = GC->p.y = y; + GC->t.clipx1 = GC->p.x+GC->p.cx; + GC->t.clipy1 = GC->p.y+GC->p.cy; + GC->t.color = color; + GC->t.bgcolor = GC->p.color = bgcolor; + + TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { + fillarea(); + mf_render_character(font, x, y, c, fillcharline, 0); + } + MUTEX_EXIT(); } void gdispDrawString(coord_t x, coord_t y, const char *str, font_t font, color_t color) { - /* No mutex required as we only call high level functions which have their own mutex */ - gdispDrawString_state_t state; - - state.font = font; - state.color = color; - state.x = x; - state.y = y; - state.cx = GDISP.Width - x; - state.cy = GDISP.Height - y; - - x += font->baseline_x; - mf_render_aligned(font, x, y, MF_ALIGN_LEFT, str, 0, gdispDrawString_callback, &state); - } + MUTEX_ENTER(); + GC->t.font = font; + GC->t.clipx0 = x; + GC->t.clipy0 = y; + GC->t.clipx1 = x + mf_get_string_width(font, str, 0, 0); + GC->t.clipy1 = y + font->height; + GC->t.color = color; - typedef struct - { - font_t font; - color_t color[2]; - coord_t x, y; - coord_t cx, cy; - } gdispFillString_state_t; - - /* Callback to render characters. */ - static uint8_t gdispFillString_callback(int16_t x, int16_t y, mf_char character, void *state) - { - gdispFillString_state_t *s = state; - uint8_t w; - - w = mf_character_width(s->font, character); - if (x >= s->x && x+w < s->x + s->cx && y >= s->y && y+s->font->height <= s->y + s->cy) - mf_render_character(s->font, x, y, character, text_fill_char_callback, s->color); - return w; + mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, 0); + MUTEX_EXIT(); } void gdispFillString(coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor) { - /* No mutex required as we only call high level functions which have their own mutex */ - gdispFillString_state_t state; - - state.font = font; - state.color[0] = color; - state.color[1] = bgcolor; - state.x = x; - state.y = y; - state.cx = mf_get_string_width(font, str, 0, 0); - state.cy = font->height; - - gdispFillArea(x, y, state.cx, state.cy, bgcolor); - mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, gdispFillString_callback, &state); + MUTEX_ENTER(); + GC->p.cx = mf_get_string_width(font, str, 0, 0); + GC->p.cy = font->height; + GC->t.font = font; + GC->t.clipx0 = GC->p.x = x; + GC->t.clipy0 = GC->p.y = y; + GC->t.clipx1 = GC->p.x+GC->p.cx; + GC->t.clipy1 = GC->p.y+GC->p.cy; + GC->t.color = color; + GC->t.bgcolor = GC->p.color = bgcolor; + + TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { + fillarea(); + mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, 0); + } + MUTEX_EXIT(); } void gdispDrawStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) { - /* No mutex required as we only call high level functions which have their own mutex */ - gdispDrawString_state_t state; - - state.font = font; - state.color = color; - state.x = x; - state.y = y; - state.cx = cx; - state.cy = cy; - + MUTEX_ENTER(); + GC->t.font = font; + GC->t.clipx0 = x; + GC->t.clipy0 = y; + GC->t.clipx1 = x+cx; + GC->t.clipy1 = y+cy; + GC->t.color = color; + /* Select the anchor position */ switch(justify) { case justifyCenter: @@ -736,39 +1816,45 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { } y += (cy+1 - font->height)/2; - mf_render_aligned(font, x, y, justify, str, 0, gdispDrawString_callback, &state); + mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, 0); + MUTEX_EXIT(); } void gdispFillStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) { - /* No mutex required as we only call high level functions which have their own mutex */ - gdispFillString_state_t state; + MUTEX_ENTER(); + GC->p.cx = cx; + GC->p.cy = cy; + GC->t.font = font; + GC->t.clipx0 = GC->p.x = x; + GC->t.clipy0 = GC->p.y = y; + GC->t.clipx1 = x+cx; + GC->t.clipy1 = y+cy; + GC->t.color = color; + GC->t.bgcolor = GC->p.color = bgcolor; - state.font = font; - state.color[0] = color; - state.color[1] = bgcolor; - state.x = x; - state.y = y; - state.cx = cx; - state.cy = cy; + TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { - gdispFillArea(x, y, cx, cy, bgcolor); - - /* Select the anchor position */ - switch(justify) { - case justifyCenter: - x += (cx + 1) / 2; - break; - case justifyRight: - x += cx; - break; - default: // justifyLeft - x += font->baseline_x; - break; + // background fill + fillarea(); + + /* Select the anchor position */ + switch(justify) { + case justifyCenter: + x += (cx + 1) / 2; + break; + case justifyRight: + x += cx; + break; + default: // justifyLeft + x += font->baseline_x; + break; + } + y += (cy+1 - font->height)/2; + + /* Render */ + mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, 0); } - y += (cy+1 - font->height)/2; - - /* Render */ - mf_render_aligned(font, x, y, justify, str, 0, gdispFillString_callback, &state); + MUTEX_EXIT(); } coord_t gdispGetFontMetric(font_t font, fontmetric_t metric) { @@ -831,5 +1917,6 @@ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha) } #endif + #endif /* GFX_USE_GDISP */ /** @} */ From 01a6d6ff95d72e6e9107d8c3e386c2bd2ce5c28d Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 18 Sep 2013 23:36:35 +1000 Subject: [PATCH 002/160] Fix some compiler warnings --- src/gdisp/mcufont/mf_kerning.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gdisp/mcufont/mf_kerning.c b/src/gdisp/mcufont/mf_kerning.c index 4118b78e..0ef35363 100644 --- a/src/gdisp/mcufont/mf_kerning.c +++ b/src/gdisp/mcufont/mf_kerning.c @@ -25,6 +25,7 @@ static void fit_leftedge(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { struct kerning_state_s *s = state; + (void)count; if (alpha > 7) { @@ -64,7 +65,7 @@ static bool do_kerning(mf_char c) return true; } -static int16_t min16(int16_t a, int16_t b) { return (a < b) ? a : b; } +//static int16_t min16(int16_t a, int16_t b) { return (a < b) ? a : b; } static int16_t max16(int16_t a, int16_t b) { return (a > b) ? a : b; } static int16_t avg16(int16_t a, int16_t b) { return (a + b) / 2; } From 6858e33285e8c8ac4dc7285dd261152eecaee060 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 18 Sep 2013 23:38:26 +1000 Subject: [PATCH 003/160] Update demos so OS can be specified in the Makefile --- demos/modules/gdisp/gdisp_fonts_cyrillic/gfxconf.h | 8 ++++---- demos/modules/gdisp/gdisp_images/gfxconf.h | 6 +++--- demos/modules/gdisp/gdisp_images_animated/gfxconf.h | 6 +++--- demos/modules/gdisp/gdisp_text/main.c | 3 +-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/demos/modules/gdisp/gdisp_fonts_cyrillic/gfxconf.h b/demos/modules/gdisp/gdisp_fonts_cyrillic/gfxconf.h index 997e57dd..a282a5f8 100644 --- a/demos/modules/gdisp/gdisp_fonts_cyrillic/gfxconf.h +++ b/demos/modules/gdisp/gdisp_fonts_cyrillic/gfxconf.h @@ -15,10 +15,10 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX subsystems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/gdisp_images/gfxconf.h b/demos/modules/gdisp/gdisp_images/gfxconf.h index 74fffa61..9e37988c 100644 --- a/demos/modules/gdisp/gdisp_images/gfxconf.h +++ b/demos/modules/gdisp/gdisp_images/gfxconf.h @@ -31,9 +31,9 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +//#define GFX_USE_OS_CHIBIOS TRUE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_POSIX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/gdisp_images_animated/gfxconf.h b/demos/modules/gdisp/gdisp_images_animated/gfxconf.h index eded2fc4..ab91a9e7 100644 --- a/demos/modules/gdisp/gdisp_images_animated/gfxconf.h +++ b/demos/modules/gdisp/gdisp_images_animated/gfxconf.h @@ -31,9 +31,9 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +//#define GFX_USE_OS_CHIBIOS TRUE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_POSIX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/gdisp_text/main.c b/demos/modules/gdisp/gdisp_text/main.c index dee741fa..7ea3405e 100644 --- a/demos/modules/gdisp/gdisp_text/main.c +++ b/demos/modules/gdisp/gdisp_text/main.c @@ -30,7 +30,7 @@ #include "gfx.h" int main(void) { - coord_t width, height; + coord_t width; font_t font1, font2, font3, font4; const char *msg; @@ -39,7 +39,6 @@ int main(void) { // Get the screen size width = gdispGetWidth(); - height = gdispGetHeight(); // Get the fonts we want to use font1 = gdispOpenFont("UI2"); From 85aa1f03edd406f1499e4835e1591ad545e5354e Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 18 Sep 2013 23:40:17 +1000 Subject: [PATCH 004/160] Use scrolling console in widget demo by default --- demos/modules/gwin/widgets/gfxconf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index 50fcbf58..0bf8443a 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -48,7 +48,7 @@ #define GDISP_NEED_ELLIPSE FALSE #define GDISP_NEED_ARC FALSE #define GDISP_NEED_CONVEX_POLYGON TRUE -#define GDISP_NEED_SCROLL FALSE +#define GDISP_NEED_SCROLL TRUE #define GDISP_NEED_PIXELREAD FALSE #define GDISP_NEED_CONTROL FALSE #define GDISP_NEED_IMAGE TRUE From b25ac5e667d98f2915831a74707f6ec198a4498b Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 18 Sep 2013 23:46:37 +1000 Subject: [PATCH 005/160] Scrolling emulation when not supported by hardware Start of new multiple display support GDISP performance optimisations Documentation updates Win32 driver updates --- drivers/multiple/Win32/gdisp_lld.c | 503 +++++------------ drivers/multiple/Win32/gdisp_lld_config.h | 15 +- include/gdisp/gdisp.h | 140 +++-- include/gdisp/lld/gdisp_lld.h | 643 +++++++++++++++------- include/gdisp/options.h | 136 +++-- include/gfx_rules.h | 22 +- src/gdisp/gdisp.c | 469 +++++++++++----- 7 files changed, 1084 insertions(+), 844 deletions(-) diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 91b86616..d6c6b2fb 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -8,22 +8,15 @@ /** * @file drivers/multiple/Win32/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for Win32. - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP +#define GDISP_LLD_DECLARATIONS #include "gdisp/lld/gdisp_lld.h" -// Declare our driver object -GDISPDriver GDISP_Win32; - -#define GC (&GDISP_Win32) - #include #include #include @@ -41,10 +34,6 @@ GDISPDriver GDISP_Win32; #if GINPUT_NEED_TOGGLE /* Include toggle support code */ #include "ginput/lld/toggle.h" - - const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES] = { - {0, 0xFF, 0x00, 0}, - }; #endif #if GINPUT_NEED_MOUSE @@ -298,19 +287,13 @@ static DECLARE_THREAD_FUNCTION(WindowThread, param) { /* Driver exported functions. */ /*===========================================================================*/ -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ - /** - * @brief Low level GDISP driver initialisation. + * @brief Low level GDISP driver initialization. * @return TRUE if successful, FALSE on error. * * @notapi */ -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { RECT rect; gfxThreadHandle hth; @@ -333,45 +316,45 @@ bool_t gdisp_lld_init(void) { Sleep(1); /* Initialise the GDISP structure to match */ - GC->g.Orientation = GDISP_ROTATE_0; - GC->g.Powermode = powerOn; - GC->g.Backlight = 100; - GC->g.Contrast = 50; - GC->g.Width = wWidth; - GC->g.Height = wHeight; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = 100; + g->g.Contrast = 50; + g->g.Width = wWidth; + g->g.Height = wHeight; return TRUE; } #if GDISP_HARDWARE_DRAWPIXEL - void gdisp_lld_draw_pixel(void) { + LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) { HDC dcScreen; int x, y; COLORREF color; - color = COLOR2BGR(GC->p.color); + color = COLOR2BGR(g->p.color); #if GDISP_NEED_CONTROL - switch(GC->g.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: - x = GC->p.x; - y = GC->p.y; + x = g->p.x; + y = g->p.y; break; case GDISP_ROTATE_90: - x = GC->g.Height - 1 - GC->p.y; - y = GC->p.x; + x = g->g.Height - 1 - g->p.y; + y = g->p.x; break; case GDISP_ROTATE_180: - x = GC->g.Width - 1 - GC->p.x; - y = GC->g.Height - 1 - GC->p.y; + x = g->g.Width - 1 - g->p.x; + y = g->g.Height - 1 - g->p.y; break; case GDISP_ROTATE_270: - x = GC->p.y; - y = GC->g.Width - 1 - GC->p.x; + x = g->p.y; + y = g->g.Width - 1 - g->p.x; break; } #else - x = GC->p.x; - y = GC->p.y; + x = g->p.x; + y = g->p.y; #endif // Draw the pixel on the screen and in the buffer. @@ -384,176 +367,46 @@ bool_t gdisp_lld_init(void) { /* ---- Optional Routines ---- */ -#if 0 -#if GDISP_HARDWARE_LINES - /** - * @brief Draw a line. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x0, y0 The start of the line - * @param[in] x1, y1 The end of the line - * @param[in] color The color of the line - * - * @notapi - */ - void gdisp_lld_draw_line(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { - POINT p; - HPEN pen; - HDC dc; - HGDIOBJ old; - #if GDISP_NEED_CLIP - HRGN clip; - #endif - #if WIN32_USE_MSG_REDRAW - RECT rect; - #endif - #if GDISP_NEED_CONTROL - coord_t t; - #endif - - #if GDISP_NEED_CLIP - clip = NULL; - #endif - - #if GDISP_NEED_CONTROL - switch(GC->g.Orientation) { - case GDISP_ROTATE_0: - #if GDISP_NEED_CLIP - // Clip post orientation change - if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) - clip = CreateRectRgn(GC->g.clipx0, GC->g.clipy0, GC->g.clipx1, GC->g.clipy1); - #endif - break; - case GDISP_ROTATE_90: - t = GC->g.Height - 1 - y0; - y0 = x0; - x0 = t; - t = GC->g.Height - 1 - y1; - y1 = x1; - x1 = t; - #if GDISP_NEED_CLIP - // Clip post orientation change - if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) - clip = CreateRectRgn(GC->g.Height-1-GC->g.clipy1, GC->g.clipx0, GC->g.Height-1-GC->g.clipy0, GC->g.clipx1); - #endif - break; - case GDISP_ROTATE_180: - x0 = GC->g.Width - 1 - x0; - y0 = GC->g.Height - 1 - y0; - x1 = GC->g.Width - 1 - x1; - y1 = GC->g.Height - 1 - y1; - #if GDISP_NEED_CLIP - // Clip post orientation change - if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) - clip = CreateRectRgn(GC->g.Width-1-GC->g.clipx1, GC->g.Height-1-GC->g.clipy1, GC->g.Width-1-GC->g.clipx0, GC->g.Height-1-GC->g.clipy0); - #endif - break; - case GDISP_ROTATE_270: - t = GC->g.Width - 1 - x0; - x0 = y0; - y0 = t; - t = GC->g.Width - 1 - x1; - x1 = y1; - y1 = t; - #if GDISP_NEED_CLIP - // Clip post orientation change - if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) - clip = CreateRectRgn(GC->g.clipy0, GC->g.Width-1-GC->g.clipx1, GC->g.clipy1, GC->g.Width-1-GC->g.clipx0); - #endif - break; - } - #else - #if GDISP_NEED_CLIP - clip = NULL; - if (GC->g.clipx0 != 0 || GC->g.clipy0 != 0 || GC->g.clipx1 != GC->g.Width || GC->g.clipy1 != GC->g.Height) - clip = CreateRectRgn(GC->g.clipx0, GC->g.clipy0, GC->g.clipx1, GC->g.clipy1); - #endif - #endif - - color = COLOR2BGR(color); - pen = CreatePen(PS_SOLID, 1, color); - if (pen) { - // Draw the line in the buffer - #if GDISP_NEED_CLIP - if (clip) SelectClipRgn(dcBuffer, clip); - #endif - old = SelectObject(dcBuffer, pen); - MoveToEx(dcBuffer, x0, y0, &p); - LineTo(dcBuffer, x1, y1); - SelectObject(dcBuffer, old); - SetPixel(dcBuffer, x1, y1, color); - #if GDISP_NEED_CLIP - if (clip) SelectClipRgn(dcBuffer, NULL); - #endif - - #if WIN32_USE_MSG_REDRAW - rect.left = x0; rect.right = x1+1; - rect.top = y0; rect.bottom = y1+1; - InvalidateRect(winRootWindow, &rect, FALSE); - UpdateWindow(winRootWindow); - #else - // Redrawing the line on the screen is cheaper than invalidating the whole rectangular area - dc = GetDC(winRootWindow); - #if GDISP_NEED_CLIP - if (clip) SelectClipRgn(dc, clip); - #endif - old = SelectObject(dc, pen); - MoveToEx(dc, x0, y0, &p); - LineTo(dc, x1, y1); - SelectObject(dc, old); - SetPixel(dc, x1, y1, color); - #if GDISP_NEED_CLIP - if (clip) SelectClipRgn(dc, NULL); - #endif - ReleaseDC(winRootWindow, dc); - #endif - - DeleteObject(pen); - } - } -#endif -#endif - #if GDISP_HARDWARE_FILLS - void gdisp_lld_fill_area(void) { + LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { HDC dcScreen; RECT rect; HBRUSH hbr; COLORREF color; - color = COLOR2BGR(GC->p.color); + color = COLOR2BGR(g->p.color); #if GDISP_NEED_CONTROL - switch(GC->g.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: - rect.top = GC->p.y; - rect.bottom = rect.top + GC->p.cy; - rect.left = GC->p.x; - rect.right = rect.left + GC->p.cx; + rect.top = g->p.y; + rect.bottom = rect.top + g->p.cy; + rect.left = g->p.x; + rect.right = rect.left + g->p.cx; break; case GDISP_ROTATE_90: - rect.top = GC->p.x; - rect.bottom = rect.top + GC->p.cx; - rect.right = GC->g.Height - GC->p.y; - rect.left = rect.right - GC->p.cy; + rect.top = g->p.x; + rect.bottom = rect.top + g->p.cx; + rect.right = g->g.Height - g->p.y; + rect.left = rect.right - g->p.cy; break; case GDISP_ROTATE_180: - rect.bottom = GC->g.Height - GC->p.y; - rect.top = rect.bottom - GC->p.cy; - rect.right = GC->g.Width - GC->p.x; - rect.left = rect.right - GC->p.cx; + rect.bottom = g->g.Height - g->p.y; + rect.top = rect.bottom - g->p.cy; + rect.right = g->g.Width - g->p.x; + rect.left = rect.right - g->p.cx; break; case GDISP_ROTATE_270: - rect.bottom = GC->g.Width - GC->p.x; - rect.top = rect.bottom - GC->p.cx; - rect.left = GC->p.y; - rect.right = rect.left + GC->p.cy; + rect.bottom = g->g.Width - g->p.x; + rect.top = rect.bottom - g->p.cx; + rect.left = g->p.y; + rect.right = rect.left + g->p.cy; break; } #else - rect.top = GC->p.y; - rect.bottom = rect.top + GC->p.cy; - rect.left = GC->p.x; - rect.right = rect.left + GC->p.cx; + rect.top = g->p.y; + rect.bottom = rect.top + g->p.cy; + rect.left = g->p.x; + rect.right = rect.left + g->p.cx; #endif hbr = CreateSolidBrush(color); @@ -567,7 +420,7 @@ bool_t gdisp_lld_init(void) { } #endif -#if (GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL) || defined(__DOXYGEN__) +#if 0 && (GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL) static pixel_t *rotateimg(coord_t cx, coord_t cy, coord_t srcx, coord_t srccx, const pixel_t *buffer) { pixel_t *dstbuf; pixel_t *dst; @@ -615,7 +468,7 @@ bool_t gdisp_lld_init(void) { } #endif -#if GDISP_HARDWARE_BITFILLS +#if 0 && GDISP_HARDWARE_BITFILLS /** * @brief Fill an area with a bitmap. * @note Optional - The high level driver can emulate using software. @@ -628,23 +481,13 @@ bool_t gdisp_lld_init(void) { * * @notapi */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { + void gdisp_lld_blit_area(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { BITMAPV4HEADER bmpInfo; RECT rect; #if GDISP_NEED_CONTROL pixel_t *srcimg; #endif - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - // Clip pre orientation change - if (x < GC->g.clipx0) { cx -= GC->g.clipx0 - x; srcx += GC->g.clipx0 - x; x = GC->g.clipx0; } - if (y < GC->g.clipy0) { cy -= GC->g.clipy0 - y; srcy += GC->g.clipy0 - y; y = GC->g.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GC->g.clipx1 || y >= GC->g.clipy1) return; - if (x+cx > GC->g.clipx1) cx = GC->g.clipx1 - x; - if (y+cy > GC->g.clipy1) cy = GC->g.clipy1 - y; - #endif - // Make everything relative to the start of the line buffer += srccx*srcy; srcy = 0; @@ -724,225 +567,142 @@ bool_t gdisp_lld_init(void) { } #endif -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) - /** - * @brief Get the color of a particular pixel. - * @note Optional. - * @note If x,y is off the screen, the result is undefined. - * @return The color of the specified pixel. - * - * @param[in] x, y The start of the text - * - * @notapi - */ - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - color_t color; - #if GDISP_NEED_CONTROL - coord_t t; - #endif - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - // Clip pre orientation change - if (x < 0 || x >= GC->g.Width || y < 0 || y >= GC->g.Height) return 0; - #endif +#if GDISP_HARDWARE_PIXELREAD + LLDSPEC color_t gdisp_lld_get_pixel_color(GDISPDriver *g) { + COLORREF color; #if GDISP_NEED_CONTROL - switch(GC->g.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: + color = GetPixel(dcBuffer, g->p.x, g->p.y); break; case GDISP_ROTATE_90: - t = GC->g.Height - 1 - y; - y = x; - x = t; + color = GetPixel(dcBuffer, g->g.Height - 1 - g->p.y, g->p.x); break; case GDISP_ROTATE_180: - x = GC->g.Width - 1 - x; - y = GC->g.Height - 1 - y; + color = GetPixel(dcBuffer, g->g.Width - 1 - g->p.x, g->g.Height - 1 - g->p.y); break; case GDISP_ROTATE_270: - t = GC->g.Width - 1 - x; - x = y; - y = t; + color = GetPixel(dcBuffer, g->p.y, g->g.Width - 1 - g->p.x); break; } + #else + color = GetPixel(dcBuffer, g->p.x, g->p.y); #endif - color = GetPixel(dcBuffer, x, y); return BGR2COLOR(color); } #endif -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @note Optional. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - RECT rect, frect, srect; - HBRUSH hbr; +#if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL + void gdisp_lld_vertical_scroll(GDISPDriver *g) { + HDC dcScreen; + RECT rect; + coord_t lines; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - // Clip pre orientation change - if (x < GC->g.clipx0) { cx -= GC->g.clipx0 - x; x = GC->g.clipx0; } - if (y < GC->g.clipy0) { cy -= GC->g.clipy0 - y; y = GC->g.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GC->g.clipx1 || y >= GC->g.clipy1) return; - if (x+cx > GC->g.clipx1) cx = GC->g.clipx1 - x; - if (y+cy > GC->g.clipy1) cy = GC->g.clipy1 - y; - #endif - - if (lines > cy) lines = cy; - else if (-lines > cy) lines = -cy; - - bgcolor = COLOR2BGR(bgcolor); - hbr = CreateSolidBrush(bgcolor); - #if GDISP_NEED_CONTROL switch(GC->g.Orientation) { case GDISP_ROTATE_0: - rect.top = y; - rect.bottom = rect.top+cy; - rect.left = x; - rect.right = rect.left+cx; - lines = -lines; + rect.top = g->p.y; + rect.bottom = rect.top+g->p.cy; + rect.left = g->p.x; + rect.right = rect.left+g->p.cx; + lines = -g->p.y1; goto vertical_scroll; case GDISP_ROTATE_90: - rect.top = x; - rect.bottom = rect.top+cx; - rect.right = GC->g.Height - y; - rect.left = rect.right-cy; + rect.top = g->p.x; + rect.bottom = rect.top+g->p.cx; + rect.right = g->g.Height - g->p.y; + rect.left = rect.right-g->p.cy; + lines = g->p.y1; goto horizontal_scroll; case GDISP_ROTATE_180: - rect.bottom = GC->g.Height - y; - rect.top = rect.bottom-cy; - rect.right = GC->g.Width - x; - rect.left = rect.right-cx; + rect.bottom = g->g.Height - g->p.y; + rect.top = rect.bottom-g->p.cy; + rect.right = GC->g.Width - g->p.x; + rect.left = rect.right-g->p.cx; + lines = g->p.y1; vertical_scroll: - srect.left = frect.left = rect.left; - srect.right = frect.right = rect.right; if (lines > 0) { - srect.top = frect.top = rect.top; - frect.bottom = rect.top+lines; - srect.bottom = rect.bottom-lines; + rect.bottom -= lines; } else { - srect.bottom = frect.bottom = rect.bottom; - frect.top = rect.bottom+lines; - srect.top = rect.top-lines; + rect.top -= lines; + } + if (g->p.cy >= lines && g->p.cy >= -lines) { + dcScreen = GetDC(winRootWindow); + ScrollDC(dcBuffer, 0, lines, &rect, 0, 0, 0); + ScrollDC(dcScreen, 0, lines, &rect, 0, 0, 0); + ReleaseDC(winRootWindow, dcScreen); } - if (cy >= lines && cy >= -lines) - ScrollDC(dcBuffer, 0, lines, &srect, 0, 0, 0); break; case GDISP_ROTATE_270: - rect.bottom = GC->g.Width - x; - rect.top = rect.bottom-cx; - rect.left = y; - rect.right = rect.left+cy; - lines = -lines; + rect.bottom = g->g.Width - g->p.x; + rect.top = rect.bottom-g->p.cx; + rect.left = g->p.y; + rect.right = rect.left+g->p.cy; + lines = -g->p.y1; horizontal_scroll: - srect.top = frect.top = rect.top; - srect.bottom = frect.bottom = rect.bottom; if (lines > 0) { - srect.left = frect.left = rect.left; - frect.right = rect.left+lines; - srect.right = rect.right-lines; + rect.right -= lines; } else { - srect.right = frect.right = rect.right; - frect.left = rect.right+lines; - srect.left = rect.left-lines; + rect.left -= lines; + } + if (g->p.cy >= lines && g->p.cy >= -lines) { + dcScreen = GetDC(winRootWindow); + ScrollDC(dcBuffer, lines, 0, &rect, 0, 0, 0); + ScrollDC(dcScreen, lines, 0, &rect, 0, 0, 0); + ReleaseDC(winRootWindow, dcScreen); } - if (cy >= lines && cy >= -lines) - ScrollDC(dcBuffer, lines, 0, &srect, 0, 0, 0); break; } #else - rect.top = y; - rect.bottom = rect.top+cy; - rect.left = x; - rect.right = rect.left+cx; - lines = -lines; - srect.left = frect.left = rect.left; - srect.right = frect.right = rect.right; + rect.top = g->p.y; + rect.bottom = rect.top+g->p.cy; + rect.left = g->p.x; + rect.right = rect.left+g->p.cx; + lines = -g->p.y1; if (lines > 0) { - srect.top = frect.top = rect.top; - frect.bottom = rect.top+lines; - srect.bottom = rect.bottom-lines; + rect.bottom -= lines; } else { - srect.bottom = frect.bottom = rect.bottom; - frect.top = rect.bottom+lines; - srect.top = rect.top-lines; + rect.top -= lines; + } + if (g->p.cy >= lines && g->p.cy >= -lines) { + dcScreen = GetDC(winRootWindow); + ScrollDC(dcBuffer, 0, lines, &rect, 0, 0, 0); + ScrollDC(dcScreen, 0, lines, &rect, 0, 0, 0); + ReleaseDC(winRootWindow, dcScreen); } - if (cy >= lines && cy >= -lines) - ScrollDC(dcBuffer, 0, lines, &srect, 0, 0, 0); #endif - - if (hbr) - FillRect(dcBuffer, &frect, hbr); - InvalidateRect(winRootWindow, &rect, FALSE); - UpdateWindow(winRootWindow); } #endif -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @detail Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. - * GDISP_CONTROL_LLD - Low level driver control constants start at - * this value. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { - switch(what) { +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + switch(g->p.x) { case GDISP_CONTROL_ORIENTATION: - if (GC->g.Orientation == (gdisp_orientation_t)value) + if (g->g.Orientation == (orientation_t)g->p.ptr) return; - switch((gdisp_orientation_t)value) { + switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: - GC->g.Width = wWidth; - GC->g.Height = wHeight; + g->g.Width = wWidth; + g->g.Height = wHeight; break; case GDISP_ROTATE_90: - GC->g.Height = wWidth; - GC->g.Width = wHeight; + g->g.Height = wWidth; + g->g.Width = wHeight; break; case GDISP_ROTATE_180: - GC->g.Width = wWidth; - GC->g.Height = wHeight; + g->g.Width = wWidth; + g->g.Height = wHeight; break; case GDISP_ROTATE_270: - GC->g.Height = wWidth; - GC->g.Width = wHeight; + g->g.Height = wWidth; + g->g.Width = wHeight; break; default: return; } - - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GC->g.clipx0 = 0; - GC->g.clipy0 = 0; - GC->g.clipx1 = GC->g.Width; - GC->g.clipy1 = GC->g.Height; - #endif - GC->g.Orientation = (gdisp_orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; /* case GDISP_CONTROL_POWER: @@ -954,25 +714,22 @@ bool_t gdisp_lld_init(void) { #endif #if GINPUT_NEED_MOUSE - void ginput_lld_mouse_init(void) {} - void ginput_lld_mouse_get_reading(MouseReading *pt) { pt->x = mousex; pt->y = mousey > wHeight ? wHeight : mousey; pt->z = (mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; pt->buttons = mousebuttons; } - #endif /* GINPUT_NEED_MOUSE */ #if GINPUT_NEED_TOGGLE - + const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES] = { + {0, 0xFF, 0x00, 0}, + }; void ginput_lld_toggle_init(const GToggleConfig *ptc) { (void) ptc; } unsigned ginput_lld_toggle_getbits(const GToggleConfig *ptc) { (void) ptc; return toggles; } - #endif /* GINPUT_NEED_MOUSE */ #endif /* GFX_USE_GDISP */ -/** @} */ diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h index 357febe4..4a526f07 100644 --- a/drivers/multiple/Win32/gdisp_lld_config.h +++ b/drivers/multiple/Win32/gdisp_lld_config.h @@ -25,19 +25,14 @@ #define GDISP_DRIVER_NAME "Win32" #define GDISP_DRIVER_STRUCT GDISP_Win32 -#define GDISP_HARDWARE_STREAM FALSE -#define GDISP_HARDWARE_STREAM_END FALSE #define GDISP_HARDWARE_DRAWPIXEL TRUE -#define GDISP_HARDWARE_CLEARS FALSE #define GDISP_HARDWARE_FILLS TRUE +#define GDISP_HARDWARE_PIXELREAD TRUE +#define GDISP_HARDWARE_CONTROL TRUE //#define GDISP_HARDWARE_BITFILLS TRUE -//#define GDISP_HARDWARE_SCROLL TRUE -//#define GDISP_HARDWARE_PIXELREAD TRUE -//#define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_HARDWARE_QUERY FALSE -#define GDISP_HARDWARE_CLIP FALSE - -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 +#define GDISP_HARDWARE_SCROLL TRUE + +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 #endif /* GFX_USE_GDISP */ diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index 3a1968ed..cb98b46d 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -43,21 +43,15 @@ typedef int16_t coord_t; /** * @brief Type for a 2D point on the screen. */ -typedef struct point_t { - coord_t x, y; - } point; +typedef struct point { coord_t x, y; } point, point_t; /** * @brief Type for the text justification. */ -typedef enum justify { - justifyLeft = 0, - justifyCenter = 1, - justifyRight = 2 -} justify_t; +typedef enum justify { justifyLeft=0, justifyCenter=1, justifyRight=2 } justify_t; /** * @brief Type for the font metric. */ -typedef enum fontmetric {fontHeight, fontDescendersHeight, fontLineSpacing, fontCharPadding, fontMinWidth, fontMaxWidth} fontmetric_t; +typedef enum fontmetric { fontHeight, fontDescendersHeight, fontLineSpacing, fontCharPadding, fontMinWidth, fontMaxWidth } fontmetric_t; /** * @brief The type of a font. */ @@ -65,11 +59,11 @@ typedef const struct mf_font_s* font_t; /** * @brief Type for the screen orientation. */ -typedef enum orientation {GDISP_ROTATE_0, GDISP_ROTATE_90, GDISP_ROTATE_180, GDISP_ROTATE_270} gdisp_orientation_t; +typedef enum orientation { GDISP_ROTATE_0=0, GDISP_ROTATE_90=90, GDISP_ROTATE_180=180, GDISP_ROTATE_270=270 } orientation_t; /** * @brief Type for the available power modes for the screen. */ -typedef enum powermode {powerOff, powerSleep, powerDeepSleep, powerOn} gdisp_powermode_t; +typedef enum powermode { powerOff, powerSleep, powerDeepSleep, powerOn } powermode_t; /* * This is not documented in Doxygen as it is meant to be a black-box. @@ -79,8 +73,8 @@ typedef enum powermode {powerOff, powerSleep, powerDeepSleep, powerOn} gdisp_pow typedef struct GDISPControl { coord_t Width; coord_t Height; - gdisp_orientation_t Orientation; - gdisp_powermode_t Powermode; + orientation_t Orientation; + powermode_t Powermode; uint8_t Backlight; uint8_t Contrast; } GDISPControl; @@ -111,15 +105,6 @@ extern GDISPControl *GDISP; #define GDISP_CONTROL_CONTRAST 3 #define GDISP_CONTROL_LLD 1000 -/** - * @brief Driver Query Constants - * @details Unsupported query codes return (void *)-1. - * @note The result should be typecast the required type. - * @note GDISP_QUERY_LLD - Low level driver control constants start at - * this value. - */ -#define GDISP_QUERY_LLD 1000 - /** * @brief Driver Pixel Format Constants */ @@ -161,6 +146,80 @@ extern GDISPControl *GDISP; #define SkyBlue HTML2COLOR(0x87CEEB) /** @} */ +/*===========================================================================*/ +/* Defines relating to the display hardware */ +/*===========================================================================*/ + +#if GDISP_MULTIPLE_DRIVERS || defined(__DOXYGEN__) + /** + * @name GDISP pixel format choices + * @{ + */ + /** + * @brief The pixel format. + * @default It generally defaults to the hardware pixel format. + * @note This doesn't need to match the hardware pixel format. + * It is definitely more efficient when it does. + * @note When GDISP_MULTIPLE_DRIVERS is defined, this should + * also be explicitly defined to ensure the best match + * with your hardware across all devices. + * @note Should be set to one of the following: + * GDISP_PIXELFORMAT_RGB565 + * GDISP_PIXELFORMAT_BGR565 + * GDISP_PIXELFORMAT_RGB888 + * GDISP_PIXELFORMAT_RGB444 + * GDISP_PIXELFORMAT_RGB332 + * GDISP_PIXELFORMAT_RGB666 + * GDISP_PIXELFORMAT_CUSTOM + * @note If you set GDISP_PIXELFORMAT_CUSTOM you need to also define + * color_t, RGB2COLOR(r,g,b), HTML2COLOR(h), + * RED_OF(c), GREEN_OF(c), BLUE_OF(c), + * COLOR(c) and MASKCOLOR. + */ + #ifndef GDISP_PIXELFORMAT + #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_ERROR + #endif + /** + * @brief Do pixels require packing for a blit + * @note Is only valid for a pixel format that doesn't fill it's datatype. ie formats: + * GDISP_PIXELFORMAT_RGB888 + * GDISP_PIXELFORMAT_RGB444 + * GDISP_PIXELFORMAT_RGB666 + * GDISP_PIXELFORMAT_CUSTOM + * @note If you use GDISP_PIXELFORMAT_CUSTOM and packed bit fills + * you need to also define @p gdispPackPixels(buf,cx,x,y,c) + * @note If you are using GDISP_HARDWARE_BITFILLS = FALSE then the pixel + * format must not be a packed format as the software blit does + * not support packed pixels + * @note Very few cases should actually require packed pixels as the low + * level driver can also pack on the fly as it is sending it + * to the graphics device. + */ + #ifndef GDISP_PACKED_PIXELS + #define GDISP_PACKED_PIXELS FALSE + #endif + + /** + * @brief Do lines of pixels require packing for a blit + * @note Ignored if GDISP_PACKED_PIXELS is FALSE + */ + #ifndef GDISP_PACKED_LINES + #define GDISP_PACKED_LINES FALSE + #endif + /** @} */ +#else + #include "gdisp_lld_config.h" + #ifndef GDISP_PIXELFORMAT + #define GDISP_PIXELFORMAT GDISP_LLD_PIXELFORMAT + #endif + #ifndef GDISP_PACKED_PIXELS + #define GDISP_PACKED_PIXELS FALSE + #endif + #ifndef GDISP_PACKED_LINES + #define GDISP_PACKED_LINES FALSE + #endif +#endif + /*===========================================================================*/ /* Defines related to the pixel format */ /*===========================================================================*/ @@ -274,26 +333,6 @@ extern GDISPControl *GDISP; #error "GDISP: No supported pixel format has been specified." #endif -/* Verify information for packed pixels and define a non-packed pixel macro */ -#if !GDISP_PACKED_PIXELS - #define gdispPackPixels(buf,cx,x,y,c) { ((color_t *)(buf))[(y)*(cx)+(x)] = (c); } -#elif !GDISP_HARDWARE_BITFILLS - #error "GDISP: packed pixel formats are only supported for hardware accelerated drivers." -#elif GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 \ - && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB444 \ - && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB666 \ - && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_CUSTOM - #error "GDISP: A packed pixel format has been specified for an unsupported pixel format." -#endif - -#if GDISP_NEED_SCROLL && !GDISP_HARDWARE_SCROLL - #error "GDISP: Hardware scrolling is wanted but not supported." -#endif - -#if GDISP_NEED_PIXELREAD && !GDISP_HARDWARE_PIXELREAD - #error "GDISP: Pixel read-back is wanted but not supported." -#endif - /** * @brief The type of a pixel. */ @@ -775,23 +814,6 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color); #endif -/* Support routine for packed pixel formats */ -#if !defined(gdispPackPixels) || defined(__DOXYGEN__) - /** - * @brief Pack a pixel into a pixel buffer. - * @note This function performs no buffer boundary checking - * regardless of whether GDISP_NEED_CLIP has been specified. - * - * @param[in] buf The buffer to put the pixel in - * @param[in] cx The width of a pixel line - * @param[in] x, y The location of the pixel to place - * @param[in] color The color to put into the buffer - * - * @api - */ - void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color); -#endif - /* * Macro definitions */ diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 46d5488a..38c0ccc0 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -18,188 +18,141 @@ #if GFX_USE_GDISP || defined(__DOXYGEN__) +#if GDISP_MULTIPLE_DRIVERS && defined(GDISP_LLD_DECLARATIONS) + // include hardware definitions + #include "gdisp_lld_config.h" +#endif + /*===========================================================================*/ /* Error checks. */ /*===========================================================================*/ -/** - * @name GDISP hardware accelerated support - * @{ - */ +#if !GDISP_MULTIPLE_DRIVERS || defined(GDISP_LLD_DECLARATIONS) /** - * @brief Hardware streaming interface is supported. - * @details If set to @p FALSE software emulation is used. - * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver + * @name GDISP hardware accelerated support + * @{ */ - #ifndef GDISP_HARDWARE_STREAM - #define GDISP_HARDWARE_STREAM FALSE - #endif + /** + * @brief Hardware streaming interface is supported. + * @details If set to @p FALSE software emulation is used. + * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver + */ + #ifndef GDISP_HARDWARE_STREAM + #define GDISP_HARDWARE_STREAM FALSE + #endif - /** - * @brief Hardware streaming requires an explicit end call. - * @details If set to @p FALSE if an explicit stream end call is not required. - */ - #ifndef GDISP_HARDWARE_STREAM_END - #define GDISP_HARDWARE_STREAM_END FALSE - #endif + /** + * @brief Hardware streaming requires an explicit end call. + * @details If set to @p FALSE if an explicit stream end call is not required. + */ + #ifndef GDISP_HARDWARE_STREAM_END + #define GDISP_HARDWARE_STREAM_END FALSE + #endif - /** - * @brief Hardware accelerated draw pixel. - * @details If set to @p FALSE software emulation is used. - * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver - */ - #ifndef GDISP_HARDWARE_DRAWPIXEL - #define GDISP_HARDWARE_DRAWPIXEL FALSE - #endif + /** + * @brief Hardware accelerated draw pixel. + * @details If set to @p FALSE software emulation is used. + * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver + */ + #ifndef GDISP_HARDWARE_DRAWPIXEL + #define GDISP_HARDWARE_DRAWPIXEL FALSE + #endif - /** - * @brief Hardware accelerated screen clears. - * @details If set to @p FALSE software emulation is used. - * @note This clears the entire display surface regardless of the clipping area currently set - */ - #ifndef GDISP_HARDWARE_CLEARS - #define GDISP_HARDWARE_CLEARS FALSE - #endif + /** + * @brief Hardware accelerated screen clears. + * @details If set to @p FALSE software emulation is used. + * @note This clears the entire display surface regardless of the clipping area currently set + */ + #ifndef GDISP_HARDWARE_CLEARS + #define GDISP_HARDWARE_CLEARS FALSE + #endif - /** - * @brief Hardware accelerated rectangular fills. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_FILLS - #define GDISP_HARDWARE_FILLS FALSE - #endif + /** + * @brief Hardware accelerated rectangular fills. + * @details If set to @p FALSE software emulation is used. + */ + #ifndef GDISP_HARDWARE_FILLS + #define GDISP_HARDWARE_FILLS FALSE + #endif - /** - * @brief Hardware accelerated fills from an image. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_BITFILLS - #define GDISP_HARDWARE_BITFILLS FALSE - #endif + /** + * @brief Hardware accelerated fills from an image. + * @details If set to @p FALSE software emulation is used. + */ + #ifndef GDISP_HARDWARE_BITFILLS + #define GDISP_HARDWARE_BITFILLS FALSE + #endif - /** - * @brief Hardware accelerated scrolling. - * @details If set to @p FALSE there is no support for scrolling. - */ - #ifndef GDISP_HARDWARE_SCROLL - #define GDISP_HARDWARE_SCROLL FALSE - #endif + /** + * @brief Hardware accelerated scrolling. + * @details If set to @p FALSE there is no support for scrolling. + */ + #ifndef GDISP_HARDWARE_SCROLL + #define GDISP_HARDWARE_SCROLL FALSE + #endif - /** - * @brief Reading back of pixel values. - * @details If set to @p FALSE there is no support for pixel read-back. - */ - #ifndef GDISP_HARDWARE_PIXELREAD - #define GDISP_HARDWARE_PIXELREAD FALSE - #endif + /** + * @brief Reading back of pixel values. + * @details If set to @p FALSE there is no support for pixel read-back. + */ + #ifndef GDISP_HARDWARE_PIXELREAD + #define GDISP_HARDWARE_PIXELREAD FALSE + #endif - /** - * @brief The driver supports one or more control commands. - * @details If set to @p FALSE there is no support for control commands. - */ - #ifndef GDISP_HARDWARE_CONTROL - #define GDISP_HARDWARE_CONTROL FALSE - #endif + /** + * @brief The driver supports one or more control commands. + * @details If set to @p FALSE there is no support for control commands. + */ + #ifndef GDISP_HARDWARE_CONTROL + #define GDISP_HARDWARE_CONTROL FALSE + #endif - /** - * @brief The driver supports a non-standard query. - * @details If set to @p FALSE there is no support for non-standard queries. - */ - #ifndef GDISP_HARDWARE_QUERY - #define GDISP_HARDWARE_QUERY FALSE - #endif + /** + * @brief The driver supports a non-standard query. + * @details If set to @p FALSE there is no support for non-standard queries. + */ + #ifndef GDISP_HARDWARE_QUERY + #define GDISP_HARDWARE_QUERY FALSE + #endif - /** - * @brief The driver supports a clipping in hardware. - * @details If set to @p FALSE there is no support for non-standard queries. - * @note If this is defined the driver must perform its own clipping on all calls to - * the driver and respond appropriately if a parameter is outside the display area. - * @note If this is not defined then the software ensures that all calls to the - * driver do not exceed the display area (provided GDISP_NEED_CLIP or GDISP_NEED_VALIDATION - * has been set). - */ - #ifndef GDISP_HARDWARE_CLIP - #define GDISP_HARDWARE_CLIP FALSE - #endif -/** @} */ - -/** - * @name GDISP software algorithm choices - * @{ - */ -/** @} */ - -/** - * @name GDISP pixel format choices - * @{ - */ - /** - * @brief The native pixel format for this device - * @note Should be set to one of the following: - * GDISP_PIXELFORMAT_RGB565 - * GDISP_PIXELFORMAT_BGR565 - * GDISP_PIXELFORMAT_RGB888 - * GDISP_PIXELFORMAT_RGB444 - * GDISP_PIXELFORMAT_RGB332 - * GDISP_PIXELFORMAT_RGB666 - * GDISP_PIXELFORMAT_CUSTOM - * @note If you set GDISP_PIXELFORMAT_CUSTOM you need to also define - * color_t, RGB2COLOR(r,g,b), HTML2COLOR(h), - * RED_OF(c), GREEN_OF(c), BLUE_OF(c), - * COLOR(c) and MASKCOLOR. - */ - #ifndef GDISP_PIXELFORMAT - #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_ERROR - #endif - - /** - * @brief Do pixels require packing for a blit - * @note Is only valid for a pixel format that doesn't fill it's datatype. ie formats: - * GDISP_PIXELFORMAT_RGB888 - * GDISP_PIXELFORMAT_RGB444 - * GDISP_PIXELFORMAT_RGB666 - * GDISP_PIXELFORMAT_CUSTOM - * @note If you use GDISP_PIXELFORMAT_CUSTOM and packed bit fills - * you need to also define @p gdispPackPixels(buf,cx,x,y,c) - * @note If you are using GDISP_HARDWARE_BITFILLS = FALSE then the pixel - * format must not be a packed format as the software blit does - * not support packed pixels - * @note Very few cases should actually require packed pixels as the low - * level driver can also pack on the fly as it is sending it - * to the graphics device. - */ - #ifndef GDISP_PACKED_PIXELS - #define GDISP_PACKED_PIXELS FALSE - #endif - - /** - * @brief Do lines of pixels require packing for a blit - * @note Ignored if GDISP_PACKED_PIXELS is FALSE - */ - #ifndef GDISP_PACKED_LINES - #define GDISP_PACKED_LINES FALSE - #endif -/** @} */ + /** + * @brief The driver supports a clipping in hardware. + * @details If set to @p FALSE there is no support for non-standard queries. + * @note If this is defined the driver must perform its own clipping on all calls to + * the driver and respond appropriately if a parameter is outside the display area. + * @note If this is not defined then the software ensures that all calls to the + * driver do not exceed the display area (provided GDISP_NEED_CLIP or GDISP_NEED_VALIDATION + * has been set). + */ + #ifndef GDISP_HARDWARE_CLIP + #define GDISP_HARDWARE_CLIP FALSE + #endif + /** @} */ +#endif /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ typedef struct GDISPDriver { - GDISPControl g; + GDISPControl g; - uint16_t flags; + #if GDISP_MULTIPLE_DRIVERS + const struct GDISPVMT const * vmt; + #endif + + uint16_t flags; #define GDISP_FLG_INSTREAM 0x0001 // Multithread Mutex #if GDISP_NEED_MULTITHREAD - gfxMutex mutex; + gfxMutex mutex; #endif // Software clipping - #if !GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) - coord_t clipx0, clipy0; - coord_t clipx1, clipy1; /* not inclusive */ + #if (GDISP_MULTIPLE_DRIVERS || !GDISP_HARDWARE_CLIP) && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + coord_t clipx0, clipy0; + coord_t clipx1, clipy1; /* not inclusive */ #endif // Driver call parameters @@ -212,8 +165,10 @@ typedef struct GDISPDriver { void *ptr; } p; - // Text rendering parameters + // In call working buffers + #if GDISP_NEED_TEXT + // Text rendering parameters struct { font_t font; color_t color; @@ -222,53 +177,363 @@ typedef struct GDISPDriver { coord_t clipx1, clipy1; } t; #endif + #if GDISP_LINEBUF_SIZE != 0 && ((GDISP_NEED_SCROLL && !GDISP_HARDWARE_SCROLL) || (!GDISP_HARDWARE_STREAM && GDISP_HARDWARE_BITFILLS)) + // A pixel line buffer + color_t linebuf[GDISP_LINEBUF_SIZE]; + #endif + } GDISPDriver; -extern GDISPDriver GDISP_DRIVER_STRUCT; +#if !GDISP_MULTIPLE_DRIVERS || defined(GDISP_LLD_DECLARATIONS) + #if GDISP_MULTIPLE_DRIVERS + #define LLDSPEC static + #else + #define LLDSPEC + #endif -#ifdef __cplusplus -extern "C" { -#endif + #ifdef __cplusplus + extern "C" { + #endif + + /** + * @brief Initialize the driver. + * @return TRUE if successful. + * @param[in] g The driver structure + * @param[out] g->g The driver must fill in the GDISPControl structure + */ + LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g); - bool_t gdisp_lld_init(void); #if GDISP_HARDWARE_STREAM - void gdisp_lld_stream_start(void); // Uses p.x,p.y p.cx,p.cy - void gdisp_lld_stream_color(void); // Uses p.color + /** + * @brief Start a streamed operation + * @pre GDISP_HARDWARE_STREAM is TRUE + * + * @param[in] g The driver structure + * @param[in] g->p.x,g->p.y The window position + * @param[in] g->p.cx,g->p.cy The window size + * + * @note The parameter variables must not be altered by the driver. + * @note Streaming operations that wrap the defined window have + * undefined results. + */ + LLDSPEC void gdisp_lld_stream_start(GDISPDriver *g); + /** + * @brief Send a pixel to the current streaming position and then increment that position + * @pre GDISP_HARDWARE_STREAM is TRUE + * + * @param[in] g The driver structure + * @param[in] g->p.color The color to display at the curent position + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g); + + #if GDISP_HARDWARE_STREAM_READ + /** + * @brief Read a pixel from the current streaming position and then increment that position + * @return The color at the current position + * @pre GDISP_HARDWARE_STREAM and GDISP_HARDWARE_STREAM_READ is TRUE + * + * @param[in] g The driver structure + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC color_t gdisp_lld_stream_read(GDISPDriver *g); + #endif + #if GDISP_HARDWARE_STREAM_END - void gdisp_lld_stream_stop(void); // Uses no parameters + /** + * @brief End the current streaming operation + * @pre GDISP_HARDWARE_STREAM and GDISP_HARDWARE_STREAM_END is TRUE + * + * @param[in] g The driver structure + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_stream_stop(GDISPDriver *g); #endif #endif + #if GDISP_HARDWARE_DRAWPIXEL - void gdisp_lld_draw_pixel(void); // Uses p.x,p.y p.color - #endif - #if GDISP_HARDWARE_CLEARS - void gdisp_lld_clear(void); // Uses p.color - #endif - #if GDISP_HARDWARE_FILLS - void gdisp_lld_fill_area(void); // Uses p.x,p.y p.cx,p.cy p.color - #endif - #if GDISP_HARDWARE_BITFILLS - void gdisp_lld_blit_area_ex(void); // Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer) - #endif - #if GDISP_HARDWARE_PIXELREAD && GDISP_NEED_PIXELREAD - color_t gdisp_lld_get_pixel_color(void); // Uses p.x,p.y - #endif - #if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL - void gdisp_lld_vertical_scroll(void); // Uses p.x,p.y p.cx,p.cy, p.y1 (=lines) p.color - #endif - #if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL - void gdisp_lld_control(void); // Uses p.x (=what) p.ptr (=value) - #endif - #if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY - void *gdisp_lld_query(void); // Uses p.x (=what); - #endif - #if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) - void gdisp_lld_set_clip(void); // Uses p.x,p.y p.cx,p.cy + /** + * @brief Draw a pixel + * @pre GDISP_HARDWARE_DRAWPIXEL is TRUE + * + * @param[in] g The driver structure + * @param[in] g->p.x,g->p.y The pixel position + * @param[in] g->p.color The color to set + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g); #endif -#ifdef __cplusplus -} -#endif + #if GDISP_HARDWARE_CLEARS + /** + * @brief Clear the screen using the defined color + * @pre GDISP_HARDWARE_CLEARS is TRUE + * + * @param[in] g The driver structure + * @param[in] g->p.color The color to set + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_clear(GDISPDriver *g); + #endif + + #if GDISP_HARDWARE_FILLS + /** + * @brief Fill an area with a single color + * @pre GDISP_HARDWARE_FILLS is TRUE + * + * @param[in] g The driver structure + * @param[in] g->p.x,g->p.y The area position + * @param[in] g->p.cx,g->p.cy The area size + * @param[in] g->p.color The color to set + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g); + #endif + + #if GDISP_HARDWARE_BITFILLS + /** + * @brief Fill an area using a bitmap + * @pre GDISP_HARDWARE_BITFILLS is TRUE + * + * @param[in] g The driver structure + * @param[in] g->p.x,g->p.y The area position + * @param[in] g->p.cx,g->p.cy The area size + * @param[in] g->p.x1,g->p.y1 The starting position in the bitmap + * @param[in] g->p.x2 The width of a bitmap line + * @param[in] g->p.ptr The pointer to the bitmap + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g); + #endif + + #if GDISP_HARDWARE_PIXELREAD + /** + * @brief Read a pixel from the display + * @return The color at the defined position + * @pre GDISP_HARDWARE_PIXELREAD is TRUE (and the application needs it) + * + * @param[in] g The driver structure + * @param[in] g->p.x,g->p.y The pixel position + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC color_t gdisp_lld_get_pixel_color(GDISPDriver *g); + #endif + + #if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL + /** + * @brief Scroll an area of the screen + * @pre GDISP_HARDWARE_SCROLL is TRUE (and the application needs it) + * + * @param[in] g The driver structure + * @param[in] g->p.x,g->p.y The area position + * @param[in] g->p.cx,g->p.cy The area size + * @param[in] g->p.y1 The number of lines to scroll (positive or negative) + * + * @note The parameter variables must not be altered by the driver. + * @note This can be easily implemented if the hardware supports + * display area to display area copying. + * @note Clearing the exposed area on the scroll operation is not + * needed as the high level code handles this. + */ + LLDSPEC void gdisp_lld_vertical_scroll(GDISPDriver *g); + #endif + + #if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL + /** + * @brief Control some feature of the hardware + * @pre GDISP_HARDWARE_CONTROL is TRUE (and the application needs it) + * + * @param[in] g The driver structure + * @param[in] g->p.x The operation to perform + * @param[in] g->p.ptr The operation parameter + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_control(GDISPDriver *g); + #endif + + #if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY + /** + * @brief Query some feature of the hardware + * @return The information requested (typecast as void *) + * @pre GDISP_HARDWARE_QUERY is TRUE (and the application needs it) + * + * @param[in] g The driver structure + * @param[in] g->p.x What to query + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void *gdisp_lld_query(GDISPDriver *g); // Uses p.x (=what); + #endif + + #if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + /** + * @brief Set the hardware clipping area + * @pre GDISP_HARDWARE_CLIP is TRUE (and the application needs it) + * + * @param[in] g The driver structure + * @param[in] g->p.x,g->p.y The area position + * @param[in] g->p.cx,g->p.cy The area size + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_set_clip(GDISPDriver *g); + #endif + + #ifdef __cplusplus + } + #endif +#endif // !GDISP_MULTIPLE_DRIVERS || defined(GDISP_LLD_DECLARATIONS) + + +#if GDISP_MULTIPLE_DRIVERS + + typedef struct GDISPVMT { + bool_t (*init)(GDISPDriver *g); + void (*streamstart)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy + void (*streamcolor)(GDISPDriver *g); // Uses p.color + color_t (*streamread)(GDISPDriver *g); // Uses no parameters + void (*streamstop)(GDISPDriver *g); // Uses no parameters + void (*pixel)(GDISPDriver *g); // Uses p.x,p.y p.color + void (*clear)(GDISPDriver *g); // Uses p.color + void (*fill)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy p.color + void (*blit)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer) + color_t (*get)(GDISPDriver *g); // Uses p.x,p.y + void (*vscroll)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy, p.y1 (=lines) p.color + void (*control)(GDISPDriver *g); // Uses p.x (=what) p.ptr (=value) + void *(*query)(GDISPDriver *g); // Uses p.x (=what); + void (*setclip)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy + } GDISPVMT; + + #ifdef GDISP_LLD_DECLARATIONS + #define GDISP_DRIVER_STRUCT_INIT {{0}, &VMT} + static const GDISPVMT VMT = { + gdisp_lld_init, + #if GDISP_HARDWARE_STREAM + gdisp_lld_stream_start, + gdisp_lld_stream_color, + gdisp_lld_stream_read, + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_stop, + #else + 0, + #endif + #else + 0, 0, 0, + #endif + #if GDISP_HARDWARE_DRAWPIXEL + gdisp_lld_draw_pixel, + #else + 0, + #endif + #if GDISP_HARDWARE_CLEARS + gdisp_lld_clear, + #else + 0, + #endif + #if GDISP_HARDWARE_FILLS + gdisp_lld_fill_area, + #else + 0, + #endif + #if GDISP_HARDWARE_BITFILLS + gdisp_lld_blit_area, + #else + 0, + #endif + #if GDISP_HARDWARE_PIXELREAD + gdisp_lld_get_pixel_color, + #else + 0, + #endif + #if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL + gdisp_lld_vertical_scroll, + #else + 0, + #endif + #if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL + gdisp_lld_control, + #else + 0, + #endif + #if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY + gdisp_lld_query, + #else + 0, + #endif + #if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + gdisp_lld_set_clip, + #else + 0, + #endif + }; + GDISPDriver GDISP_DRIVER_STRUCT = {{0}, &VMT}; + + #else + #define gdisp_lld_init(g) g->vmt->init(g) + #define gdisp_lld_stream_start(g) g->vmt->streamstart(g) + #define gdisp_lld_stream_color(g) g->vmt->streamcolor(g) + #define gdisp_lld_stream_read(g) g->vmt->streamread(g) + #define gdisp_lld_stream_stop(g) g->vmt->streamstop(g) + #define gdisp_lld_draw_pixel(g) g->vmt->pixel(g) + #define gdisp_lld_clear(g) g->vmt->clear(g) + #define gdisp_lld_fill_area(g) g->vmt->fill(g) + #define gdisp_lld_blit_area(g) g->vmt->blit(g) + #define gdisp_lld_get_pixel_color(g) g->vmt->get(g) + #define gdisp_lld_vertical_scroll(g) g->vmt->vscroll(g) + #define gdisp_lld_control(g) g->vmt->control(g) + #define gdisp_lld_query(g) g->vmt->query(g) + #define gdisp_lld_set_clip(g) g->vmt->setclip(g) + + extern GDISPDriver GDISP_DRIVER_STRUCT; + + #endif // GDISP_LLD_DECLARATIONS + +#else // GDISP_MULTIPLE_DRIVERS + #ifdef GDISP_LLD_DECLARATIONS + GDISPDriver GDISP_DRIVER_STRUCT; + #else + extern GDISPDriver GDISP_DRIVER_STRUCT; + #endif + +#endif // GDISP_MULTIPLE_DRIVERS + + /* Verify information for packed pixels and define a non-packed pixel macro */ + #if !GDISP_PACKED_PIXELS + #define gdispPackPixels(buf,cx,x,y,c) { ((color_t *)(buf))[(y)*(cx)+(x)] = (c); } + #elif !GDISP_HARDWARE_BITFILLS + #error "GDISP: packed pixel formats are only supported for hardware accelerated drivers." + #elif GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 \ + && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB444 \ + && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB666 \ + && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_CUSTOM + #error "GDISP: A packed pixel format has been specified for an unsupported pixel format." + #endif + + /* Support routine for packed pixel formats */ + #if !defined(gdispPackPixels) || defined(__DOXYGEN__) + /** + * @brief Pack a pixel into a pixel buffer. + * @note This function performs no buffer boundary checking + * regardless of whether GDISP_NEED_CLIP has been specified. + * + * @param[in] buf The buffer to put the pixel in + * @param[in] cx The width of a pixel line + * @param[in] x, y The location of the pixel to place + * @param[in] color The color to put into the buffer + * + * @api + */ + void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color); + #endif #endif /* GFX_USE_GDISP */ diff --git a/include/gdisp/options.h b/include/gdisp/options.h index d5818284..1a0f6907 100644 --- a/include/gdisp/options.h +++ b/include/gdisp/options.h @@ -20,55 +20,86 @@ * @name GDISP Functionality to be included * @{ */ + /** + * @brief Should support for multiple displays be provided. + * @details Defaults to FALSE. + * @note Setting this to TRUE can significantly increase code size as many + * optimizations that remove code through conditional compilation can't + * be done. It may also slow some graphics operations as extra tests must + * be performed to determine how to do a particular operation. For these + * reasons do not set it to TRUE unless you really need multiple display + * support. + */ + #ifndef GDISP_MULTIPLE_DRIVERS + #define GDISP_MULTIPLE_DRIVERS FALSE + #endif /** * @brief Should all operations be clipped to the screen and colors validated. * @details Defaults to TRUE. * @note If this is FALSE, any operations that extend beyond the * edge of the screen will have undefined results. Any * out-of-range colors will produce undefined results. - * @note If defined then all low level and high level GDISP driver routines - * must check the validity of inputs and do something sensible - * if they are out of range. It doesn't have to be efficient, - * just valid. + * @note This should always be left as the default (TRUE) unless you + * are a maniac for speed and you have thoroughly tested your code + * and it never overwrites the edges of the screen. + * @note Setting GDISP_NEED_CLIP to TRUE internally uses the same mechanism + * as this validation. There is no advantage in setting this FALSE if + * GDISP_NEED_CLIP is TRUE. */ #ifndef GDISP_NEED_VALIDATION - #define GDISP_NEED_VALIDATION TRUE + #define GDISP_NEED_VALIDATION TRUE #endif /** * @brief Are clipping functions needed. * @details Defaults to TRUE */ #ifndef GDISP_NEED_CLIP - #define GDISP_NEED_CLIP TRUE + #define GDISP_NEED_CLIP TRUE + #endif + /** + * @brief Streaming functions are needed + * @details Defaults to FALSE. + */ + #ifndef GDISP_NEED_STREAMING + #define GDISP_NEED_STREAMING FALSE #endif /** * @brief Are text functions needed. * @details Defaults to TRUE + * @note You must also define at least one font. */ #ifndef GDISP_NEED_TEXT - #define GDISP_NEED_TEXT TRUE + #define GDISP_NEED_TEXT TRUE #endif /** * @brief Are circle functions needed. - * @details Defaults to TRUE + * @details Defaults to FALSE + * @note Uses integer algorithms only. It does not use any trig or floating point. */ #ifndef GDISP_NEED_CIRCLE - #define GDISP_NEED_CIRCLE TRUE + #define GDISP_NEED_CIRCLE FALSE #endif /** * @brief Are ellipse functions needed. - * @details Defaults to TRUE + * @details Defaults to FALSE + * @note Uses integer algorithms only. It does not use any trig or floating point. */ #ifndef GDISP_NEED_ELLIPSE - #define GDISP_NEED_ELLIPSE TRUE + #define GDISP_NEED_ELLIPSE FALSE #endif /** * @brief Are arc functions needed. * @details Defaults to FALSE - * @note Requires the maths library to be included in the link. ie -lm + * @note This can be compiled using fully integer mathematics by + * defining GFX_USE_GMISC and GMISC_NEED_FIXEDTRIG as TRUE. + * @note This can be compiled to use floating point but no trig functions + * by defining GFX_USE_GMISC and GMISC_NEED_FASTTRIG as TRUE. + * @note If neither of the above are defined it requires the maths library + * to be included in the link to provide floating point and trig support. + * ie include -lm in your compiler flags. */ #ifndef GDISP_NEED_ARC - #define GDISP_NEED_ARC FALSE + #define GDISP_NEED_ARC FALSE #endif /** * @brief Are convex polygon functions needed. @@ -88,7 +119,7 @@ * option will cause a compile error. */ #ifndef GDISP_NEED_SCROLL - #define GDISP_NEED_SCROLL FALSE + #define GDISP_NEED_SCROLL FALSE #endif /** * @brief Is the capability to read pixels back needed. @@ -98,7 +129,7 @@ * option will cause a compile error. */ #ifndef GDISP_NEED_PIXELREAD - #define GDISP_NEED_PIXELREAD FALSE + #define GDISP_NEED_PIXELREAD FALSE #endif /** * @brief Control some aspect of the hardware operation. @@ -107,7 +138,7 @@ * screen rotation, backlight levels, contrast etc */ #ifndef GDISP_NEED_CONTROL - #define GDISP_NEED_CONTROL FALSE + #define GDISP_NEED_CONTROL FALSE #endif /** * @brief Query some aspect of the hardware operation. @@ -115,21 +146,14 @@ * @note This allows query of hardware specific features */ #ifndef GDISP_NEED_QUERY - #define GDISP_NEED_QUERY FALSE + #define GDISP_NEED_QUERY FALSE #endif /** * @brief Is the image interface required. * @details Defaults to FALSE */ #ifndef GDISP_NEED_IMAGE - #define GDISP_NEED_IMAGE FALSE - #endif - /** - * @brief Is the messaging api interface required. - * @details Defaults to FALSE - */ - #ifndef GDISP_NEED_MSGAPI - #define GDISP_NEED_MSGAPI FALSE + #define GDISP_NEED_IMAGE FALSE #endif /** * @} @@ -143,42 +167,42 @@ * @details Defaults to FALSE */ #ifndef GDISP_NEED_IMAGE_NATIVE - #define GDISP_NEED_IMAGE_NATIVE FALSE + #define GDISP_NEED_IMAGE_NATIVE FALSE #endif /** * @brief Is GIF image decoding required. * @details Defaults to FALSE */ #ifndef GDISP_NEED_IMAGE_GIF - #define GDISP_NEED_IMAGE_GIF FALSE + #define GDISP_NEED_IMAGE_GIF FALSE #endif /** * @brief Is BMP image decoding required. * @details Defaults to FALSE */ #ifndef GDISP_NEED_IMAGE_BMP - #define GDISP_NEED_IMAGE_BMP FALSE + #define GDISP_NEED_IMAGE_BMP FALSE #endif /** * @brief Is JPG image decoding required. * @details Defaults to FALSE */ #ifndef GDISP_NEED_IMAGE_JPG - #define GDISP_NEED_IMAGE_JPG FALSE + #define GDISP_NEED_IMAGE_JPG FALSE #endif /** * @brief Is PNG image decoding required. * @details Defaults to FALSE */ #ifndef GDISP_NEED_IMAGE_PNG - #define GDISP_NEED_IMAGE_PNG FALSE + #define GDISP_NEED_IMAGE_PNG FALSE #endif /** * @brief Is memory accounting required during image decoding. * @details Defaults to FALSE */ #ifndef GDISP_NEED_IMAGE_ACCOUNTING - #define GDISP_NEED_IMAGE_ACCOUNTING FALSE + #define GDISP_NEED_IMAGE_ACCOUNTING FALSE #endif /** * @} @@ -191,7 +215,7 @@ * @details Defaults to FALSE */ #ifndef GDISP_NEED_UTF8 - #define GDISP_NEED_UTF8 FALSE + #define GDISP_NEED_UTF8 FALSE #endif /** @@ -199,7 +223,7 @@ * @details Defaults to FALSE */ #ifndef GDISP_NEED_TEXT_KERNING - #define GDISP_NEED_TEXT_KERNING FALSE + #define GDISP_NEED_TEXT_KERNING FALSE #endif /** @@ -207,7 +231,7 @@ * @details Defaults to FALSE */ #ifndef GDISP_NEED_ANTIALIAS - #define GDISP_NEED_ANTIALIAS FALSE + #define GDISP_NEED_ANTIALIAS FALSE #endif /** @@ -219,27 +243,10 @@ /** * @brief Do the drawing functions need to be thread-safe. * @details Defaults to FALSE - * @note Both GDISP_NEED_MULTITHREAD and GDISP_NEED_ASYNC make - * the gdisp API thread-safe. - * @note This is more efficient than GDISP_NEED_ASYNC as it only - * requires a context switch if something else is already - * drawing. */ #ifndef GDISP_NEED_MULTITHREAD #define GDISP_NEED_MULTITHREAD FALSE #endif - /** - * @brief Use asynchronous calls (multi-thread safe). - * @details Defaults to FALSE - * @note Both GDISP_NEED_MULTITHREAD and GDISP_NEED_ASYNC make - * the gdisp API thread-safe. - * @note Turning this on adds two context switches per transaction - * so it can significantly slow graphics drawing but it allows - * drawing operations to continue in the background. - */ - #ifndef GDISP_NEED_ASYNC - #define GDISP_NEED_ASYNC FALSE - #endif /** * @} * @@ -257,6 +264,23 @@ * @name GDISP Optional Sizing Parameters * @{ */ + /** + * @brief The size of pixel buffer (in pixels) used for optimization. + * @details Set to zero to guarantee disabling of the buffer. + * @note Depending on the driver and what operations the application + * needs, this buffer may never be allocated. + * @note Setting the size to zero may cause some operations to not + * compile eg. Scrolling if there is no hardware scroll support. + * @note Increasing the size will speedup certain operations + * at the expense of RAM. + * @note Currently only used to support scrolling on hardware without + * scrolling support, and to increase the speed of streaming + * operations on non-streaming hardware where there is a + * hardware supported bit-blit. + */ + #ifndef GDISP_LINEBUF_SIZE + #define GDISP_LINEBUF_SIZE 128 + #endif /** * @} * @@ -281,12 +305,6 @@ */ /* #define GDISP_SCREEN_WIDTH nnnn */ /* #define GDISP_SCREEN_HEIGHT nnnn */ - /** - * @brief Define which threading model to use. - * @details Optional for the X11 driver. - * @note Defaults to TRUE. Setting to FALSE causes POSIX threads to be used - */ - /* #define GDISP_THREAD_CHIBIOS FALSE */ /** * @brief Define which bus interface to use. * @details Only required by the SSD1963 driver. @@ -296,10 +314,6 @@ /* #define GDISP_USE_GPIO */ /** @} */ -#if GFX_USE_GDISP - #include "gdisp_lld_config.h" -#endif - #endif /* _GDISP_OPTIONS_H */ /** @} */ diff --git a/include/gfx_rules.h b/include/gfx_rules.h index afd2a8fe..a8dd031e 100644 --- a/include/gfx_rules.h +++ b/include/gfx_rules.h @@ -134,17 +134,13 @@ #endif #if GFX_USE_GDISP - #if GDISP_NEED_MULTITHREAD && GDISP_NEED_ASYNC - #error "GDISP: Only one of GDISP_NEED_MULTITHREAD and GDISP_NEED_ASYNC should be defined." - #endif - #if GDISP_NEED_ASYNC && !(GFX_USE_GQUEUE && GQUEUE_NEED_GSYNC) - #if GFX_DISPLAY_RULE_WARNINGS - #warning "GDISP: GDISP_NEED_ASYNC requires GFX_USE_GQUEUE and GQUEUE_NEED_GSYNC. They have been turned on for you." + #if GDISP_MULTIPLE_DRIVERS + #ifndef GDISP_PIXELFORMAT + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GDISP: GDISP_MULTIPLE_DRIVERS requires GDISP_PIXELFORMAT to be set. It has been defaulted to GDISP_PIXELFORMAT_RGB565." + #endif + #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif - #undef GFX_USE_GQUEUE - #define GFX_USE_GQUEUE TRUE - #undef GQUEUE_NEED_GSYNC - #define GQUEUE_NEED_GSYNC TRUE #endif #if GDISP_NEED_ANTIALIAS && !GDISP_NEED_PIXELREAD #if GDISP_HARDWARE_PIXELREAD @@ -161,11 +157,11 @@ #endif #if (defined(GDISP_INCLUDE_FONT_SMALL) && GDISP_INCLUDE_FONT_SMALL) || (defined(GDISP_INCLUDE_FONT_LARGER) && GDISP_INCLUDE_FONT_LARGER) #if GFX_DISPLAY_RULE_WARNINGS - #warning "GDISP: An old font (Small or Larger) has been defined. A single default font of DEJAVUSANS12 has been added instead." + #warning "GDISP: An old font (Small or Larger) has been defined. A single default font of UI2 has been added instead." #warning "GDISP: Please see <$(GFXLIB)/include/gdisp/fonts/fonts.h> for a list of available font names." #endif - #undef GDISP_INCLUDE_FONT_DEJAVUSANS12 - #define GDISP_INCLUDE_FONT_DEJAVUSANS12 TRUE + #undef GDISP_INCLUDE_FONT_UI2 + #define GDISP_INCLUDE_FONT_UI2 TRUE #endif #endif diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 1aecd26c..25c2621d 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -50,7 +50,7 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; #if GDISP_HARDWARE_STREAM_END #define STREAM_CLEAR() if ((GC->flags & GDISP_FLG_INSTREAM)) { \ - gdisp_lld_stream_end(); \ + gdisp_lld_stream_end(GC); \ GC->flags &= ~GDISP_FLG_INSTREAM; \ } #else @@ -71,10 +71,10 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; #if NEED_CLIPPING static INLINE void drawpixel_clip(void) { if (GC->p.x >= GC->clipx0 && GC->p.x < GC->clipx1 && GC->p.y >= GC->clipy0 && GC->p.y < GC->clipy1) - gdisp_lld_draw_pixel(); + gdisp_lld_draw_pixel(GC); } #else - #define drawpixel_clip() gdisp_lld_draw_pixel() + #define drawpixel_clip() gdisp_lld_draw_pixel(GC) #endif #else // Worst is streaming @@ -85,10 +85,10 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; #endif GC->cx = GC->cy = 1; - gdisp_lld_stream_start(); - gdisp_lld_stream_color(); + gdisp_lld_stream_start(GC); + gdisp_lld_stream_color(GC); #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(); + gdisp_lld_stream_end(GC); #endif } #endif @@ -99,7 +99,7 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; // Note: This is not clipped #if GDISP_HARDWARE_FILLS // Best is hardware accelerated area fill - #define fillarea() gdisp_lld_fill_area() + #define fillarea() gdisp_lld_fill_area(GC) #elif GDISP_HARDWARE_STREAM // Next best is hardware streaming static INLINE void fillarea(void) { @@ -107,11 +107,11 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; area = (uint32_t)GC->p.cx * GC->p.cy; - gdisp_lld_stream_start(); + gdisp_lld_stream_start(GC); for(; area; area--) - gdisp_lld_stream_color(); + gdisp_lld_stream_color(GC); #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(gc); + gdisp_lld_stream_end(GC); #endif } #else @@ -125,7 +125,7 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; y1 = GC->p.y + GC->p.cy; for(; GC->p.y < y1; GC->p.y++, GC->p.x = x0) for(; GC->p.x < x1; GC->p.x++) - gdisp_lld_draw_pixel(); + gdisp_lld_draw_pixel(GC); GC->p.y = y0; } #endif @@ -164,14 +164,14 @@ static void hline_clip(void) { if (GC->p.x == GC->p.x1) { #if GDISP_HARDWARE_DRAWPIXEL // Best is hardware accelerated pixel draw - gdisp_lld_draw_pixel(); + gdisp_lld_draw_pixel(GC); #else // Worst is streaming GC->p.cx = GC->p.cy = 1; - gdisp_lld_stream_start(); - gdisp_lld_stream_color(); + gdisp_lld_stream_start(GC); + gdisp_lld_stream_color(GC); #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(); + gdisp_lld_stream_end(GC); #endif #endif return; @@ -182,19 +182,19 @@ static void hline_clip(void) { // Best is hardware accelerated area fill GC->p.cx = GC->p.x1 - GC->p.x + 1; GC->p.cy = 1; - gdisp_lld_fill_area(); + gdisp_lld_fill_area(GC); #elif GDISP_HARDWARE_STREAM // Next best is streaming GC->p.cx = GC->p.x1 - GC->p.x; - gdisp_lld_stream_start(); - do { gdisp_lld_stream_color(); } while(GC->p.cx--); + gdisp_lld_stream_start(GC); + do { gdisp_lld_stream_color(GC); } while(GC->p.cx--); #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(); + gdisp_lld_stream_end(GC); #endif #else // Worst is drawing pixels for(; GC->p.x <= GC->p.x1; GC->p.x++) - gdisp_lld_draw_pixel(); + gdisp_lld_draw_pixel(GC); #endif } @@ -221,14 +221,14 @@ static void vline_clip(void) { if (GC->p.y == GC->p.y1) { #if GDISP_HARDWARE_DRAWPIXEL // Best is hardware accelerated pixel draw - gdisp_lld_draw_pixel(); + gdisp_lld_draw_pixel(GC); #else // Worst is streaming GC->p.cx = GC->p.cy = 1; - gdisp_lld_stream_start(); - gdisp_lld_stream_color(); + gdisp_lld_stream_start(GC); + gdisp_lld_stream_color(GC); #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(); + gdisp_lld_stream_end(GC); #endif #endif return; @@ -239,19 +239,19 @@ static void vline_clip(void) { // Best is hardware accelerated area fill GC->p.cy = GC->p.y1 - GC->p.y + 1; GC->p.cx = 1; - gdisp_lld_fill_area(); + gdisp_lld_fill_area(GC); #elif GDISP_HARDWARE_STREAM // Next best is streaming GC->p.cy = GC->p.y1 - GC->p.y; - gdisp_lld_stream_start(); - do { gdisp_lld_stream_color(); } while(GC->p.cy--); + gdisp_lld_stream_start(GC); + do { gdisp_lld_stream_color(GC); } while(GC->p.cy--); #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(); + gdisp_lld_stream_end(GC); #endif #else // Worst is drawing pixels for(; GC->p.y <= GC->p.y1; GC->p.y++) - gdisp_lld_draw_pixel(); + gdisp_lld_draw_pixel(GC); #endif } @@ -342,14 +342,15 @@ void _gdispInit(void) { /* Initialise driver */ MUTEX_ENTER(); - gdisp_lld_init(); + GC->flags = 0; + gdisp_lld_init(GC); #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP #if GDISP_HARDWARE_CLIP GC->p.x = x; GC->p.y = y; GC->p.cx = cx; GC->p.cy = cy; - gdisp_lld_set_clip(); + gdisp_lld_set_clip(GC); #else GC->clipx0 = 0; GC->clipy0 = 0; @@ -360,75 +361,140 @@ void _gdispInit(void) { MUTEX_EXIT(); } -void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy) { - MUTEX_ENTER(); +#if GDISP_NEED_STREAMING + void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy) { + MUTEX_ENTER(); - #if NEED_CLIPPING - // Test if the area is valid - if not then exit - if (x < GC->clipx0 || x+cx >= GC->clipx1 || y < GC->clipy0 || y+cy >= GC->clipy1) { - MUTEX_EXIT(); + #if NEED_CLIPPING + // Test if the area is valid - if not then exit + if (x < GC->clipx0 || x+cx >= GC->clipx1 || y < GC->clipy0 || y+cy >= GC->clipy1) { + MUTEX_EXIT(); + return; + } + #endif + + GC->flags |= GDISP_FLG_INSTREAM; + + #if GDISP_HARDWARE_STREAM + // Best is hardware streaming + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + gdisp_lld_stream_start(GC); + #else + // Worst - save the parameters and use pixel drawing + + // Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position, cx = bufpos + GC->p.x1 = GC->p.x = x; + GC->p.y1 = GC->p.y = y; + GC->p.x2 = x + cx; + GC->p.y2 = y + cy; + GC->p.cx = 0; + #endif + + // Don't release the mutex as gdispStreamEnd() will do that. + } + + void gdispStreamColor(color_t color) { + #if !GDISP_HARDWARE_STREAM && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS + coord_t pos, sx1, sy1, sx2; + #endif + + // Don't touch the mutex as we should already own it + + // Ignore this call if we are not streaming + if (!(GC->flags & GDISP_FLG_INSTREAM)) return; - } - #endif - GC->flags |= GDISP_FLG_INSTREAM; + #if GDISP_HARDWARE_STREAM + // Best is hardware streaming + GC->p.color = color; + gdisp_lld_stream_color(GC); + #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS + GC->linebuf[GC->p.cx++] = color; + if (GC->p.cx >= GDISP_LINEBUF_SIZE) { + pos = GC->p.cx; + sx1 = GC->p.x1; + sy1 = GC->p.y1; + sx2 = GC->p.x2; + GC->p.x -= pos; + GC->p.cx = pos; + GC->p.cy = 1; + GC->p.x1 = 0; + GC->p.y1 = 0; + GC->p.x2 = pos; + GC->p.ptr = (void *)GC->linebuf; + gdisp_lld_blit_area(GC); + GC->p.x1 = sx1; + GC->p.y1 = sy1; + GC->p.x2 = sx2; + GC->p.x += pos; + GC->p.cx = 0; + } - #if GDISP_HARDWARE_STREAM - // Best is hardware streaming - GC->p.x = x; - GC->p.y = y; - GC->p.cx = cx; - GC->p.cy = cy; - gdisp_lld_stream_start(); - #else - // Worst - save the parameters and use pixel drawing + // Just wrap at end-of-line and end-of-buffer + if (++GC->p.x >= GC->p.x2) { + if (GC->p.cx) { + pos = GC->p.cx; + sx1 = GC->p.x1; + sy1 = GC->p.y1; + sx2 = GC->p.x2; + GC->p.x -= pos; + GC->p.cx = pos; + GC->p.cy = 1; + GC->p.x1 = 0; + GC->p.y1 = 0; + GC->p.x2 = pos; + GC->p.ptr = (void *)GC->linebuf; + gdisp_lld_blit_area(GC); + GC->p.x1 = sx1; + GC->p.y1 = sy1; + GC->p.x2 = sx2; + GC->p.cx = 0; + } + GC->p.x = GC->p.x1; + if (++GC->p.y >= GC->p.x2) + GC->p.y = GC->p.y1; + } + #else + // Worst is using pixel drawing + GC->p.color = color; + gdisp_lld_draw_pixel(GC); - // Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position - GC->p.x1 = GC->p.x = x; - GC->p.y1 = GC->p.y = y; - GC->p.x2 = GC->p.x + GC->p.cx; - GC->p.x2 = GC->p.x + GC->p.cx; - #endif + // Just wrap at end-of-line and end-of-buffer + if (++GC->p.x >= GC->p.x2) { + GC->p.x = GC->p.x1; + if (++GC->p.y >= GC->p.x2) + GC->p.y = GC->p.y1; + } + #endif + } - // Don't release the mutex as gdispStreamEnd() will do that. -} + void gdispStreamEnd(void) { + // Only release the mutex and end the stream if we are actually streaming. + if (!(GC->flags & GDISP_FLG_INSTREAM)) + return; -void gdispStreamColor(color_t color) { - // Don't touch the mutex as we should already own it - - // Ignore this call if we are not streaming - if (!(GC->flags & GDISP_FLG_INSTREAM)) - return; - - #if GDISP_HARDWARE_STREAM - // Best is hardware streaming - GC->p.color = color; - gdisp_lld_stream_color(); - #else - // Worst is using pixel drawing - GC->p.color = color; - gdisp_lld_draw_pixel(); - - // Just wrap at end-of-line and end-of-buffer - if (++GC->p.x >= GC->p.x2) { - GC->p.x = GC->p.x1; - if (++GC->p.y >= GC->p.x2) - GC->p.y = GC->p.y1; - } - #endif -} - -void gdispStreamEnd(void) { - // Only release the mutex and end the stream if we are actually streaming. - if (!(GC->flags & GDISP_FLG_INSTREAM)) - return; - - #if GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(); - #endif - GC->flags &= ~GDISP_FLG_INSTREAM; - MUTEX_EXIT(); -} + #if GDISP_HARDWARE_STREAM + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(GC); + #endif + #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS + if (GC->p.cx) { + GC->p.x -= GC->p.cx; + GC->p.cy = 1; + GC->p.x1 = 0; + GC->p.y1 = 0; + GC->p.x2 = GC->p.cx; + GC->p.ptr = (void *)GC->linebuf; + gdisp_lld_blit_area(GC); + } + #endif + GC->flags &= ~GDISP_FLG_INSTREAM; + MUTEX_EXIT(); + } +#endif void gdispDrawPixel(coord_t x, coord_t y, color_t color) { MUTEX_ENTER(); @@ -457,14 +523,14 @@ void gdispClear(color_t color) { #if GDISP_HARDWARE_CLEARS // Best is hardware accelerated clear GC->p.color = color; - gdisp_lld_clear(); + gdisp_lld_clear(GC); #elif GDISP_HARDWARE_FILLS // Next best is hardware accelerated area fill GC->p.x = GC->p.y = 0; GC->p.cx = GC->g.Width; GC->p.cy = GC->g.Height; GC->p.color = color; - gdisp_lld_fill_area(); + gdisp_lld_fill_area(GC); #elif GDISP_HARDWARE_STREAM // Next best is streaming uint32_t area; @@ -475,18 +541,18 @@ void gdispClear(color_t color) { GC->p.color = color; area = (uint32_t)GC->p.cx * GC->p.cy; - gdisp_lld_stream_start(); + gdisp_lld_stream_start(GC); for(; area; area--) - gdisp_lld_stream_color(); + gdisp_lld_stream_color(GC); #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(gc); + gdisp_lld_stream_end(GC); #endif #else // Worst is drawing pixels GC->p.color = color; for(GC->p.y = 0; GC->p.y < GC->g.Height; GC->p.y++) for(GC->p.x = 0; GC->p.x < GC->g.Width; GC->p.x++) - gdisp_lld_draw_pixel(); + gdisp_lld_draw_pixel(GC); #endif MUTEX_EXIT(); } @@ -527,7 +593,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.y1 = srcy; GC->p.x2 = srccx; GC->p.ptr = (void *)buffer; - gdisp_lld_blit_area_ex(); + gdisp_lld_blit_area(GC); #elif GDISP_HARDWARE_STREAM // Next best is hardware streaming @@ -537,15 +603,15 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, srcy = y + cy; srccx -= cx; - gdisp_lld_stream_start(gc); + gdisp_lld_stream_start(GC); for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { for(GC->p.x = x; GC->p.x < srcx; GC->p.x++) { GC->p.color = *buffer++; - gdisp_lld_stream_color(); + gdisp_lld_stream_color(GC); } } #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(gc); + gdisp_lld_stream_end(GC); #endif #else // Worst is drawing pixels @@ -559,7 +625,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { for(GC->p.x=x; GC->p.x < srcx; GC->p.x++) { GC->p.color = *buffer++; - gdisp_lld_draw_pixel(); + gdisp_lld_draw_pixel(GC); } } #endif @@ -575,7 +641,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.y = y; GC->p.cx = cx; GC->p.cy = cy; - gdisp_lld_set_clip(); + gdisp_lld_set_clip(GC); #else // Worst is using software clipping if (x < 0) { cx += x; x = 0; } @@ -1456,9 +1522,26 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, /* Always synchronous as it must return a value */ MUTEX_ENTER(); - GC->p.x = x; - GC->p.y = y; - c = gdisp_lld_get_pixel_color(); + #if GDISP_HARDWARE_PIXELREAD + // Best is direct pixel read + GC->p.x = x; + GC->p.y = y; + c = gdisp_lld_get_pixel_color(GC); + #elif GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_READ + // Next best is hardware streaming + GC->p.x = x; + GC->p.y = y; + GC->p.cx = 1; + GC->p.cy = 1; + gdisp_lld_stream_start(GC); + c = gdisp_lld_stream_read(GC); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(GC); + #endif + #else + // Worst is "not possible" + #error "GDISP: GDISP_NEED_PIXELREAD has been set but there is no hardware support for reading the display" + #endif MUTEX_EXIT(); return c; @@ -1467,21 +1550,127 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, #if GDISP_NEED_SCROLL void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { + coord_t abslines; + #if !GDISP_HARDWARE_SCROLL + coord_t fy, dy, ix, fx, i, j; + #endif + MUTEX_ENTER(); #if NEED_CLIPPING if (x < GC->clipx0) { cx -= GC->clipx0 - x; x = GC->clipx0; } if (y < GC->clipy0) { cy -= GC->clipy0 - y; y = GC->clipy0; } - if (cx <= 0 || cy <= 0 || x >= GC->clipx1 || y >= GC->clipy1) { MUTEX_EXIT(); return; } + if (!lines || cx <= 0 || cy <= 0 || x >= GC->clipx1 || y >= GC->clipy1) { MUTEX_EXIT(); return; } if (x+cx > GC->clipx1) cx = GC->clipx1 - x; if (y+cy > GC->clipy1) cy = GC->clipy1 - y; #endif + + abslines = lines < 0 ? -lines : lines; + if (abslines >= cy) { + abslines = cy; + cy = 0; + } else { + #if GDISP_HARDWARE_SCROLL + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; + GC->p.y1 = lines; + GC->p.color = bgcolor; + gdisp_lld_vertical_scroll(GC); + cy -= abslines; + #elif GDISP_LINEBUF_SIZE == 0 + #error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support and GDISP_LINEBUF_SIZE is zero." + #else + cy -= abslines; + if (lines < 0) { + fy = y+cx-1; + dy = -1; + } else { + fy = y; + dy = 1; + } + // Move the screen - one line at a time + for(i = 0; i < cy; i++, fy += dy) { + + // Handle where the buffer is smaller than a line + for(ix=0; ix < cx; ix += GDISP_LINEBUF_SIZE) { + + // Calculate the data we can move in one operation + fx = cx - ix; + if (fx > GDISP_LINEBUF_SIZE) + fx = GDISP_LINEBUF_SIZE; + + // Read one line of data from the screen + #if GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_READ + // Best is hardware streaming + GC->p.x = x+ix; + GC->p.y = fy+lines; + GC->p.cx = fx; + GC->p.cy = 1; + gdisp_lld_stream_start(GC); + for(j=0; j < fx; j++) + GC->linebuf[j] = gdisp_lld_stream_read(GC); + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(GC); + #endif + #elif GDISP_HARDWARE_PIXELREAD + // Next best is single pixel reads + for(j=0; j < fx; j++) { + GC->p.x = x+ix+j; + GC->p.y = fy+lines; + GC->linebuf[j] = gdisp_lld_get_pixel_color(GC); + } + #else + // Worst is "not possible" + #error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support for scrolling or reading pixels." + #endif + + // Write that line to the new location + #if GDISP_HARDWARE_BITFILLS + // Best is hardware bitfills + GC->p.x = x+ix; + GC->p.y = fy; + GC->p.cx = fx; + GC->p.cy = 1; + GC->p.x1 = 0; + GC->p.y1 = 0; + GC->p.x2 = fx; + GC->p.ptr = (void *)GC->linebuf; + gdisp_lld_blit_area(GC); + #elif GDISP_HARDWARE_STREAM + // Next best is hardware streaming + GC->p.x = x+ix; + GC->p.y = fy; + GC->p.cx = fx; + GC->p.cy = 1; + gdisp_lld_stream_start(GC); + for(j = 0; j < fx; j++) { + GC->p.color = GC->linebuf[j]; + gdisp_lld_stream_color(GC); + } + #if GDISP_HARDWARE_STREAM_END + gdisp_lld_stream_end(GC); + #endif + #else + // Worst is drawing pixels + GC->p.y = fy; + for(GC->p.x = x+ix, j = 0; j < fx; GC->p.x++, j++) { + GC->p.color = GC->linebuf[j]; + gdisp_lld_draw_pixel(GC); + } + #endif + } + } + #endif + } + + /* fill the remaining gap */ GC->p.x = x; - GC->p.y = y; + GC->p.y = lines > 0 ? (y+cy) : y; GC->p.cx = cx; - GC->p.cy = cy; - GC->p.y1 = lines; + GC->p.cy = abslines; GC->p.color = bgcolor; - gdisp_lld_vertical_scroll(); + fillarea(); MUTEX_EXIT(); } #endif @@ -1492,7 +1681,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, MUTEX_ENTER(); GC->p.x = what; GC->p.ptr = value; - gdisp_lld_control(); + gdisp_lld_control(GC); #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION if (what == GDISP_CONTROL_ORIENTATION) { #if GDISP_HARDWARE_CLIP @@ -1501,7 +1690,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.y = 0; GC->p.cx = GC->g.Width; GC->p.cy = GC->g.Height; - gdisp_lld_set_clip(); + gdisp_lld_set_clip(GC); #else // Worst is software clipping GC->clipx0 = 0; @@ -1529,7 +1718,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, MUTEX_ENTER(); GC->p.x = (coord_t)what; - res = gdisp_lld_query(); + res = gdisp_lld_query(GC); MUTEX_EXIT(); return res; } @@ -1677,42 +1866,46 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { #if GDISP_NEED_TEXT #include "mcufont.h" - #if GDISP_NEED_ANTIALIAS && GDISP_NEED_PIXELREAD + #if GDISP_NEED_ANTIALIAS && GDISP_HARDWARE_PIXELREAD static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { - if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return; + #define GD ((GDISPDriver *)state) + if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x < GD->t.clipx0 || x+count > GD->t.clipx1) return; if (alpha == 255) { - GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; GC->p.color = GC->t.color; + GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color; hline_clip(); } else { for (; count; count--, x++) { - GC->p.x = x; GC->p.y = y; - GC->p.color = gdispBlendColor(GC->t.color, gdisp_lld_get_pixel_color(), alpha); + GD->p.x = x; GD->p.y = y; + GD->p.color = gdispBlendColor(GD->t.color, gdisp_lld_get_pixel_color(GD), alpha); drawpixel_clip(); } } + #undef GD } #else static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { - (void) state; - if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return; + #define GD ((GDISPDriver *)state) + if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x < GD->t.clipx0 || x+count > GD->t.clipx1) return; if (alpha > 0x80) { // A best approximation when using anti-aliased fonts but we can't actually draw them anti-aliased - GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; GC->p.color = GC->t.color; + GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color; hline_clip(); } + #undef GD } #endif #if GDISP_NEED_ANTIALIAS static void fillcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { - (void) state; - if (y < GC->t.clipy0 || y >= GC->t.clipy1 || x < GC->t.clipx0 || x+count > GC->t.clipx1) return; + #define GD ((GDISPDriver *)state) + if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x < GD->t.clipx0 || x+count > GD->t.clipx1) return; if (alpha == 255) { - GC->p.color = GC->t.color; + GD->p.color = GD->t.color; } else { - GC->p.color = gdispBlendColor(GC->t.color, GC->t.bgcolor, alpha); + GD->p.color = gdispBlendColor(GD->t.color, GD->t.bgcolor, alpha); } - GC->p.x = x; GC->p.y = y; GC->p.x1 = x+count-1; + GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; hline_clip(); + #undef GD } #else #define fillcharline drawcharline @@ -1720,14 +1913,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { /* Callback to render characters. */ static uint8_t drawcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { - (void) state; - return mf_render_character(GC->t.font, x, y, ch, drawcharline, 0); + return mf_render_character(GC->t.font, x, y, ch, drawcharline, state); } /* Callback to render characters. */ static uint8_t fillcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { - (void) state; - return mf_render_character(GC->t.font, x, y, ch, fillcharline, 0); + return mf_render_character(GC->t.font, x, y, ch, fillcharline, state); } void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color) { @@ -1738,7 +1929,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { GC->t.clipx1 = x + mf_character_width(font, c) + font->baseline_x; GC->t.clipy1 = y + font->height; GC->t.color = color; - mf_render_character(font, x, y, c, drawcharline, 0); + mf_render_character(font, x, y, c, drawcharline, GC); MUTEX_EXIT(); } @@ -1756,7 +1947,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { fillarea(); - mf_render_character(font, x, y, c, fillcharline, 0); + mf_render_character(font, x, y, c, fillcharline, GC); } MUTEX_EXIT(); } @@ -1770,7 +1961,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { GC->t.clipy1 = y + font->height; GC->t.color = color; - mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, 0); + mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, GC); MUTEX_EXIT(); } @@ -1788,7 +1979,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { fillarea(); - mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, 0); + mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, GC); } MUTEX_EXIT(); } @@ -1816,7 +2007,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { } y += (cy+1 - font->height)/2; - mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, 0); + mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, GC); MUTEX_EXIT(); } @@ -1852,7 +2043,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { y += (cy+1 - font->height)/2; /* Render */ - mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, 0); + mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, GC); } MUTEX_EXIT(); } From 40ec5a4e522450458fac6f4c5c9011623b9fa328 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 19 Sep 2013 08:28:26 +1000 Subject: [PATCH 006/160] Fix bug where freed memory is written to. --- src/gwin/gwin.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index 998fb8d3..44d4143c 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -172,10 +172,11 @@ void gwinDestroy(GHandle gh) { gh->vmt->Destroy(gh); // Clean up the structure - if (gh->flags & GWIN_FLG_DYNAMIC) + if (gh->flags & GWIN_FLG_DYNAMIC) { + gh->flags = 0; // To be sure, to be sure gfxFree((void *)gh); - - gh->flags = 0; // To be sure, to be sure + } else + gh->flags = 0; // To be sure, to be sure } const char *gwinGetClassName(GHandle gh) { From 973e34089e33f06cfd9ed560db968870e22c2b8a Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 24 Sep 2013 16:10:15 +1000 Subject: [PATCH 007/160] GDISP streaming bug fixes Win32 bitmap support Win32 Rotation is back to front. Need to check touch and other drivers. --- drivers/multiple/Win32/gdisp_lld.c | 192 ++++++++++------------ drivers/multiple/Win32/gdisp_lld_config.h | 2 +- gfxconf.example.h | 31 ++-- include/gdisp/gdisp.h | 52 ++++++ include/gdisp/lld/gdisp_lld.h | 26 +-- include/gmisc/gmisc.h | 17 ++ include/gmisc/options.h | 14 +- src/gdisp/gdisp.c | 37 ++--- 8 files changed, 209 insertions(+), 162 deletions(-) diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index d6c6b2fb..0f1a0b03 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -340,16 +340,16 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { y = g->p.y; break; case GDISP_ROTATE_90: - x = g->g.Height - 1 - g->p.y; - y = g->p.x; + x = g->p.y; + y = g->g.Width - 1 - g->p.x; break; case GDISP_ROTATE_180: x = g->g.Width - 1 - g->p.x; y = g->g.Height - 1 - g->p.y; break; case GDISP_ROTATE_270: - x = g->p.y; - y = g->g.Width - 1 - g->p.x; + x = g->g.Height - 1 - g->p.y; + y = g->p.x; break; } #else @@ -384,10 +384,10 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.right = rect.left + g->p.cx; break; case GDISP_ROTATE_90: - rect.top = g->p.x; - rect.bottom = rect.top + g->p.cx; - rect.right = g->g.Height - g->p.y; - rect.left = rect.right - g->p.cy; + rect.bottom = g->g.Width - g->p.x; + rect.top = rect.bottom - g->p.cx; + rect.left = g->p.y; + rect.right = rect.left + g->p.cy; break; case GDISP_ROTATE_180: rect.bottom = g->g.Height - g->p.y; @@ -396,10 +396,10 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.left = rect.right - g->p.cx; break; case GDISP_ROTATE_270: - rect.bottom = g->g.Width - g->p.x; - rect.top = rect.bottom - g->p.cx; - rect.left = g->p.y; - rect.right = rect.left + g->p.cy; + rect.top = g->p.x; + rect.bottom = rect.top + g->p.cx; + rect.right = g->g.Height - g->p.y; + rect.left = rect.right - g->p.cy; break; } #else @@ -420,8 +420,8 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } #endif -#if 0 && (GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL) - static pixel_t *rotateimg(coord_t cx, coord_t cy, coord_t srcx, coord_t srccx, const pixel_t *buffer) { +#if GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL + static pixel_t *rotateimg(GDISPDriver *g, const pixel_t *buffer) { pixel_t *dstbuf; pixel_t *dst; const pixel_t *src; @@ -429,37 +429,37 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { coord_t i, j; // Shortcut. - if (GC->g.Orientation == GDISP_ROTATE_0 && srcx == 0 && cx == srccx) + if (g->g.Orientation == GDISP_ROTATE_0 && g->p.x1 == 0 && g->p.cx == g->p.x2) return (pixel_t *)buffer; // Allocate the destination buffer - sz = (size_t)cx * (size_t)cy; + sz = (size_t)g->p.cx * (size_t)g->p.cy; if (!(dstbuf = (pixel_t *)malloc(sz * sizeof(pixel_t)))) return 0; // Copy the bits we need - switch(GC->g.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: - for(dst = dstbuf, src = buffer+srcx, j = 0; j < cy; j++) - for(i = 0; i < cx; i++, src += srccx - cx) + for(dst = dstbuf, src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) + for(i = 0; i < g->p.cx; i++) *dst++ = *src++; break; case GDISP_ROTATE_90: - for(src = buffer+srcx, j = 0; j < cy; j++) { - dst = dstbuf+cy-j-1; - for(i = 0; i < cx; i++, src += srccx - cx, dst += cy) + for(src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) { + dst = dstbuf+sz-g->p.cy+j; + for(i = 0; i < g->p.cx; i++, dst -= g->p.cy) *dst = *src++; } break; case GDISP_ROTATE_180: - for(dst = dstbuf+sz, src = buffer+srcx, j = 0; j < cy; j++) - for(i = 0; i < cx; i++, src += srccx - cx) + for(dst = dstbuf+sz, src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) + for(i = 0; i < g->p.cx; i++) *--dst = *src++; break; case GDISP_ROTATE_270: - for(src = buffer+srcx, j = 0; j < cy; j++) { - dst = dstbuf+sz-cy+j; - for(i = 0; i < cx; i++, src += srccx - cx, dst -= cy) + for(src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) { + dst = dstbuf+g->p.cy-j-1; + for(i = 0; i < g->p.cx; i++, dst += g->p.cy) *dst = *src++; } break; @@ -468,34 +468,24 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } #endif -#if 0 && GDISP_HARDWARE_BITFILLS - /** - * @brief Fill an area with a bitmap. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { +#if GDISP_HARDWARE_BITFILLS + void gdisp_lld_blit_area(GDISPDriver *g) { BITMAPV4HEADER bmpInfo; - RECT rect; + HDC dcScreen; + pixel_t * buffer; #if GDISP_NEED_CONTROL - pixel_t *srcimg; + RECT rect; + pixel_t * srcimg; #endif // Make everything relative to the start of the line - buffer += srccx*srcy; - srcy = 0; + buffer = g->p.ptr; + buffer += g->p.x2*g->p.y1; memset(&bmpInfo, 0, sizeof(bmpInfo)); bmpInfo.bV4Size = sizeof(bmpInfo); bmpInfo.bV4Planes = 1; - bmpInfo.bV4BitCount = 32; + bmpInfo.bV4BitCount = sizeof(pixel_t)*8; bmpInfo.bV4AlphaMask = 0; bmpInfo.bV4RedMask = RGB2COLOR(255,0,0); bmpInfo.bV4GreenMask = RGB2COLOR(0,255,0); @@ -508,62 +498,60 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { bmpInfo.bV4CSType = 0; //LCS_sRGB; #if GDISP_NEED_CONTROL - bmpInfo.bV4SizeImage = (cy*cx) * sizeof(pixel_t); - srcimg = rotateimg(cx, cy, srcx, srccx, buffer); + bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(pixel_t); + srcimg = rotateimg(g, buffer); if (!srcimg) return; - switch(GC->g.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: - bmpInfo.bV4Width = cx; - bmpInfo.bV4Height = -cy; /* top-down image */ - rect.top = y; - rect.bottom = rect.top+cy; - rect.left = x; - rect.right = rect.left+cx; + bmpInfo.bV4Width = g->p.cx; + bmpInfo.bV4Height = -g->p.cy; /* top-down image */ + rect.top = g->p.y; + rect.bottom = rect.top+g->p.cy; + rect.left = g->p.x; + rect.right = rect.left+g->p.cx; break; case GDISP_ROTATE_90: - bmpInfo.bV4Width = cy; - bmpInfo.bV4Height = -cx; /* top-down image */ - rect.top = x; - rect.bottom = rect.top+cx; - rect.right = GC->g.Height - y; - rect.left = rect.right-cy; + bmpInfo.bV4Width = g->p.cy; + bmpInfo.bV4Height = -g->p.cx; /* top-down image */ + rect.bottom = g->g.Width - g->p.x; + rect.top = rect.bottom-g->p.cx; + rect.left = g->p.y; + rect.right = rect.left+g->p.cy; break; case GDISP_ROTATE_180: - bmpInfo.bV4Width = cx; - bmpInfo.bV4Height = -cy; /* top-down image */ - rect.bottom = GC->g.Height - y; - rect.top = rect.bottom-cy; - rect.right = GC->g.Width - x; - rect.left = rect.right-cx; + bmpInfo.bV4Width = g->p.cx; + bmpInfo.bV4Height = -g->p.cy; /* top-down image */ + rect.bottom = g->g.Height-1 - g->p.y; + rect.top = rect.bottom-g->p.cy; + rect.right = g->g.Width - g->p.x; + rect.left = rect.right-g->p.cx; break; case GDISP_ROTATE_270: - bmpInfo.bV4Width = cy; - bmpInfo.bV4Height = -cx; /* top-down image */ - rect.bottom = GC->g.Width - x; - rect.top = rect.bottom-cx; - rect.left = y; - rect.right = rect.left+cy; + bmpInfo.bV4Width = g->p.cy; + bmpInfo.bV4Height = -g->p.cx; /* top-down image */ + rect.top = g->p.x; + rect.bottom = rect.top+g->p.cx; + rect.right = g->g.Height - g->p.y; + rect.left = rect.right-g->p.cy; break; } + dcScreen = GetDC(winRootWindow); SetDIBitsToDevice(dcBuffer, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, srcimg, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); - if (srcimg != (pixel_t *)buffer) + SetDIBitsToDevice(dcScreen, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, srcimg, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); + ReleaseDC(winRootWindow, dcScreen); + if (srcimg != buffer) free(srcimg); #else - bmpInfo.bV4Width = srccx; - bmpInfo.bV4Height = -cy; /* top-down image */ - bmpInfo.bV4SizeImage = (cy*srccx) * sizeof(pixel_t); - rect.top = y; - rect.bottom = rect.top+cy; - rect.left = x; - rect.right = rect.left+cx; - SetDIBitsToDevice(dcBuffer, x, y, cx, cy, srcx, 0, 0, cy, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); + bmpInfo.bV4Width = g->p.x2; + bmpInfo.bV4Height = -g->p.cy; /* top-down image */ + bmpInfo.bV4SizeImage = (g->p.cy*g->p.x2) * sizeof(pixel_t); + dcScreen = GetDC(winRootWindow); + SetDIBitsToDevice(dcBuffer, g->p.x, g->p.y, g->p.cx, g->p.cy, g->p.x1, 0, 0, g->p.cy, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); + SetDIBitsToDevice(dcScreen, g->p.x, g->p.y, g->p.cx, g->p.cy, g->p.x1, 0, 0, g->p.cy, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); + ReleaseDC(winRootWindow, dcScreen); #endif - - // Invalidate the region to get it on the screen. - InvalidateRect(winRootWindow, &rect, FALSE); - UpdateWindow(winRootWindow); } #endif @@ -577,13 +565,13 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { color = GetPixel(dcBuffer, g->p.x, g->p.y); break; case GDISP_ROTATE_90: - color = GetPixel(dcBuffer, g->g.Height - 1 - g->p.y, g->p.x); + color = GetPixel(dcBuffer, g->p.y, g->g.Width - 1 - g->p.x); break; case GDISP_ROTATE_180: color = GetPixel(dcBuffer, g->g.Width - 1 - g->p.x, g->g.Height - 1 - g->p.y); break; case GDISP_ROTATE_270: - color = GetPixel(dcBuffer, g->p.y, g->g.Width - 1 - g->p.x); + color = GetPixel(dcBuffer, g->g.Height - 1 - g->p.y, g->p.x); break; } #else @@ -610,11 +598,11 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { lines = -g->p.y1; goto vertical_scroll; case GDISP_ROTATE_90: - rect.top = g->p.x; - rect.bottom = rect.top+g->p.cx; - rect.right = g->g.Height - g->p.y; - rect.left = rect.right-g->p.cy; - lines = g->p.y1; + rect.bottom = g->g.Width - g->p.x; + rect.top = rect.bottom-g->p.cx; + rect.left = g->p.y; + rect.right = rect.left+g->p.cy; + lines = -g->p.y1; goto horizontal_scroll; case GDISP_ROTATE_180: rect.bottom = g->g.Height - g->p.y; @@ -636,11 +624,11 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } break; case GDISP_ROTATE_270: - rect.bottom = g->g.Width - g->p.x; - rect.top = rect.bottom-g->p.cx; - rect.left = g->p.y; - rect.right = rect.left+g->p.cy; - lines = -g->p.y1; + rect.top = g->p.x; + rect.bottom = rect.top+g->p.cx; + rect.right = g->g.Height - g->p.y; + rect.left = rect.right-g->p.cy; + lines = g->p.y1; horizontal_scroll: if (lines > 0) { rect.right -= lines; @@ -684,17 +672,11 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return; switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: - g->g.Width = wWidth; - g->g.Height = wHeight; - break; - case GDISP_ROTATE_90: - g->g.Height = wWidth; - g->g.Width = wHeight; - break; case GDISP_ROTATE_180: g->g.Width = wWidth; g->g.Height = wHeight; break; + case GDISP_ROTATE_90: case GDISP_ROTATE_270: g->g.Height = wWidth; g->g.Width = wHeight; diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h index 4a526f07..b8a030ef 100644 --- a/drivers/multiple/Win32/gdisp_lld_config.h +++ b/drivers/multiple/Win32/gdisp_lld_config.h @@ -29,7 +29,7 @@ #define GDISP_HARDWARE_FILLS TRUE #define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_HARDWARE_CONTROL TRUE -//#define GDISP_HARDWARE_BITFILLS TRUE +#define GDISP_HARDWARE_BITFILLS TRUE #define GDISP_HARDWARE_SCROLL TRUE #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 diff --git a/gfxconf.example.h b/gfxconf.example.h index 65bc97f0..1f7d9c2e 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -14,11 +14,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use - one of these must be defined - preferably via your makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX subsystems to turn on */ #define GFX_USE_GDISP FALSE @@ -37,8 +37,8 @@ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE TRUE +#define GDISP_NEED_CIRCLE FALSE +#define GDISP_NEED_ELLIPSE FALSE #define GDISP_NEED_ARC FALSE #define GDISP_NEED_CONVEX_POLYGON FALSE #define GDISP_NEED_SCROLL FALSE @@ -47,13 +47,17 @@ #define GDISP_NEED_QUERY FALSE #define GDISP_NEED_IMAGE FALSE #define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE +#define GDISP_NEED_STREAMING FALSE + +/* GDISP - text features */ #define GDISP_NEED_ANTIALIAS FALSE #define GDISP_NEED_UTF8 FALSE #define GDISP_NEED_TEXT_KERNING FALSE /* GDISP - fonts to include */ +#define GDISP_INCLUDE_FONT_UI1 FALSE +#define GDISP_INCLUDE_FONT_UI2 FALSE +#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE #define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE #define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE #define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE @@ -68,10 +72,6 @@ #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE - -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 FALSE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE #define GDISP_INCLUDE_USER_FONTS FALSE /* GDISP image decoders */ @@ -139,12 +139,11 @@ #define GMISC_NEED_ARRAYOPS FALSE #define GMISC_NEED_FASTTRIG FALSE #define GMISC_NEED_FIXEDTRIG FALSE +#define GMISC_NEED_INVSQRT FALSE /* Optional Parameters for various subsystems */ /* - #define GDISP_NEED_UTF8 FALSE - #define GDISP_NEED_TEXT_KERNING FALSE - #define GDISP_NEED_ANTIALIAS FALSE + #define GDISP_LINEBUF_SIZE 128 #define GEVENT_MAXIMUM_SIZE 32 #define GEVENT_MAX_SOURCE_LISTENERS 32 #define GTIMER_THREAD_WORKAREA_SIZE 512 diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index cb98b46d..6b2f5b47 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -430,6 +430,58 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, */ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); +/* Streaming Functions */ + +#if GDISP_NEED_STREAMING || defined(__DOXYGEN__) + /** + * @brief Start a streaming operation. + * @details Stream data to a window on the display sequentially and very fast. + * @note While streaming is in operation - no other calls to GDISP functions + * can be made (with the exception of @p gdispBlendColor() and streaming + * functions). If a call is made (eg in a multi-threaded application) the other + * call is blocked waiting for the streaming operation to finish. + * @note @p gdispStreamStop() must be called to finish the streaming operation. + * @note If more data is written than the defined area then the results are unspecified. + * Some drivers may wrap back to the beginning of the area, others may just + * ignore subsequent data. + * @note Unlike most operations that clip the defined area to the display to generate + * a smaller active area, this call will just silently fail if any of the stream + * region lies outside the current clipping area. + * @note A streaming operation may be terminated early (without writing to every location + * in the stream area) by calling @p gdispStreamStop(). + * + * @param[in] x,y The start position + * @param[in] cx,cy The size of the streamable area + * + * @api + */ + void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy); + + /** + * @brief Send pixel data to the stream. + * @details Write a pixel to the next position in the streamed area and increment the position + * @pre @p gdispStreamStart() has been called. + * @note If the gdispStreamStart() has not been called (or failed due to clipping), the + * data provided here is simply thrown away. + * + * @param[in] color The color of the pixel to write + * + * @api + */ + void gdispStreamColor(color_t color); + + /** + * @brief Finish the current streaming operation. + * @details Completes the current streaming operation and allows other GDISP calls to operate again. + * @pre @p gdispStreamStart() has been called. + * @note If the gdispStreamStart() has not been called (or failed due to clipping), this + * call is simply ignored. + * + * @api + */ + void gdispStreamStop(void); +#endif + /* Clipping Functions */ #if GDISP_NEED_CLIP || defined(__DOXYGEN__) diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 38c0ccc0..3698efb0 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -184,7 +184,7 @@ typedef struct GDISPDriver { } GDISPDriver; -#if !GDISP_MULTIPLE_DRIVERS || defined(GDISP_LLD_DECLARATIONS) +#if !GDISP_MULTIPLE_DRIVERS || defined(GDISP_LLD_DECLARATIONS) || defined(__DOXYGEN__) #if GDISP_MULTIPLE_DRIVERS #define LLDSPEC static #else @@ -203,7 +203,7 @@ typedef struct GDISPDriver { */ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g); - #if GDISP_HARDWARE_STREAM + #if GDISP_HARDWARE_STREAM || defined(__DOXYGEN__) /** * @brief Start a streamed operation * @pre GDISP_HARDWARE_STREAM is TRUE @@ -228,7 +228,7 @@ typedef struct GDISPDriver { */ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g); - #if GDISP_HARDWARE_STREAM_READ + #if GDISP_HARDWARE_STREAM_READ || defined(__DOXYGEN__) /** * @brief Read a pixel from the current streaming position and then increment that position * @return The color at the current position @@ -241,7 +241,7 @@ typedef struct GDISPDriver { LLDSPEC color_t gdisp_lld_stream_read(GDISPDriver *g); #endif - #if GDISP_HARDWARE_STREAM_END + #if GDISP_HARDWARE_STREAM_END || defined(__DOXYGEN__) /** * @brief End the current streaming operation * @pre GDISP_HARDWARE_STREAM and GDISP_HARDWARE_STREAM_END is TRUE @@ -254,7 +254,7 @@ typedef struct GDISPDriver { #endif #endif - #if GDISP_HARDWARE_DRAWPIXEL + #if GDISP_HARDWARE_DRAWPIXEL || defined(__DOXYGEN__) /** * @brief Draw a pixel * @pre GDISP_HARDWARE_DRAWPIXEL is TRUE @@ -268,7 +268,7 @@ typedef struct GDISPDriver { LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g); #endif - #if GDISP_HARDWARE_CLEARS + #if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) /** * @brief Clear the screen using the defined color * @pre GDISP_HARDWARE_CLEARS is TRUE @@ -281,7 +281,7 @@ typedef struct GDISPDriver { LLDSPEC void gdisp_lld_clear(GDISPDriver *g); #endif - #if GDISP_HARDWARE_FILLS + #if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) /** * @brief Fill an area with a single color * @pre GDISP_HARDWARE_FILLS is TRUE @@ -296,7 +296,7 @@ typedef struct GDISPDriver { LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g); #endif - #if GDISP_HARDWARE_BITFILLS + #if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) /** * @brief Fill an area using a bitmap * @pre GDISP_HARDWARE_BITFILLS is TRUE @@ -313,7 +313,7 @@ typedef struct GDISPDriver { LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g); #endif - #if GDISP_HARDWARE_PIXELREAD + #if GDISP_HARDWARE_PIXELREAD || defined(__DOXYGEN__) /** * @brief Read a pixel from the display * @return The color at the defined position @@ -327,7 +327,7 @@ typedef struct GDISPDriver { LLDSPEC color_t gdisp_lld_get_pixel_color(GDISPDriver *g); #endif - #if GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL + #if (GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL) || defined(__DOXYGEN__) /** * @brief Scroll an area of the screen * @pre GDISP_HARDWARE_SCROLL is TRUE (and the application needs it) @@ -346,7 +346,7 @@ typedef struct GDISPDriver { LLDSPEC void gdisp_lld_vertical_scroll(GDISPDriver *g); #endif - #if GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL + #if (GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL) || defined(__DOXYGEN__) /** * @brief Control some feature of the hardware * @pre GDISP_HARDWARE_CONTROL is TRUE (and the application needs it) @@ -360,7 +360,7 @@ typedef struct GDISPDriver { LLDSPEC void gdisp_lld_control(GDISPDriver *g); #endif - #if GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY + #if (GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY) || defined(__DOXYGEN__) /** * @brief Query some feature of the hardware * @return The information requested (typecast as void *) @@ -374,7 +374,7 @@ typedef struct GDISPDriver { LLDSPEC void *gdisp_lld_query(GDISPDriver *g); // Uses p.x (=what); #endif - #if GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + #if (GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)) || defined(__DOXYGEN__) /** * @brief Set the hardware clipping area * @pre GDISP_HARDWARE_CLIP is TRUE (and the application needs it) diff --git a/include/gmisc/gmisc.h b/include/gmisc/gmisc.h index 5943e642..ff3d0c76 100644 --- a/include/gmisc/gmisc.h +++ b/include/gmisc/gmisc.h @@ -184,6 +184,23 @@ extern "C" { /** @} */ #endif +#if GMISC_NEED_INVSQRT + /** + * @brief Fast inverse square root function (x^-1/2) + * @return The approximate inverse square root + * + * @param[in] n The number to find the inverse square root of + * + * @note This function generates an approximate result. Higher accuracy (at the expense + * of speed) can be obtained by modifying the source code (the necessary line + * is already there - just commented out). + * @note This function relies on the internal machine format of a float and a long. + * If your machine architecture is very unusual this function may not work. + * + * @api + */ + float invsqrt(float n); +#endif #ifdef __cplusplus } #endif diff --git a/include/gmisc/options.h b/include/gmisc/options.h index d5cf5898..73b41800 100644 --- a/include/gmisc/options.h +++ b/include/gmisc/options.h @@ -27,13 +27,6 @@ #ifndef GMISC_NEED_ARRAYOPS #define GMISC_NEED_ARRAYOPS FALSE #endif - /** - * @brief Include fast array based trig functions (sin, cos) - * @details Defaults to FALSE - */ - #ifndef GMISC_NEED_FASTTRIG - #define GMISC_NEED_FASTTRIG FALSE - #endif /** * @brief Include fast fixed point trig functions (sin, cos) * @details Defaults to FALSE @@ -41,6 +34,13 @@ #ifndef GMISC_NEED_FIXEDTRIG #define GMISC_NEED_FIXEDTRIG FALSE #endif + /** + * @brief Include fast inverse square root (x^-1/2) + * @details Defaults to FALSE + */ + #ifndef GMISC_NEED_INVSQRT + #define GMISC_NEED_INVSQRT FALSE + #endif /** * @} * diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 25c2621d..8ec2c998 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -367,7 +367,7 @@ void _gdispInit(void) { #if NEED_CLIPPING // Test if the area is valid - if not then exit - if (x < GC->clipx0 || x+cx >= GC->clipx1 || y < GC->clipy0 || y+cy >= GC->clipy1) { + if (x < GC->clipx0 || x+cx > GC->clipx1 || y < GC->clipy0 || y+cy > GC->clipy1) { MUTEX_EXIT(); return; } @@ -398,7 +398,7 @@ void _gdispInit(void) { void gdispStreamColor(color_t color) { #if !GDISP_HARDWARE_STREAM && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS - coord_t pos, sx1, sy1, sx2; + coord_t sx1, sy1, sx2; #endif // Don't touch the mutex as we should already own it @@ -413,48 +413,45 @@ void _gdispInit(void) { gdisp_lld_stream_color(GC); #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS GC->linebuf[GC->p.cx++] = color; + GC->p.x++; if (GC->p.cx >= GDISP_LINEBUF_SIZE) { - pos = GC->p.cx; sx1 = GC->p.x1; sy1 = GC->p.y1; - sx2 = GC->p.x2; - GC->p.x -= pos; - GC->p.cx = pos; + //sx2 = GC->p.x2; + GC->p.x -= GC->p.cx; GC->p.cy = 1; GC->p.x1 = 0; GC->p.y1 = 0; - GC->p.x2 = pos; + //GC->p.x2 = GC->p.cx; GC->p.ptr = (void *)GC->linebuf; gdisp_lld_blit_area(GC); GC->p.x1 = sx1; GC->p.y1 = sy1; - GC->p.x2 = sx2; - GC->p.x += pos; + //GC->p.x2 = sx2; + GC->p.x += GC->p.cx; GC->p.cx = 0; } // Just wrap at end-of-line and end-of-buffer - if (++GC->p.x >= GC->p.x2) { + if (GC->p.x >= GC->p.x2) { if (GC->p.cx) { - pos = GC->p.cx; sx1 = GC->p.x1; sy1 = GC->p.y1; - sx2 = GC->p.x2; - GC->p.x -= pos; - GC->p.cx = pos; + //sx2 = GC->p.x2; + GC->p.x -= GC->p.cx; GC->p.cy = 1; GC->p.x1 = 0; GC->p.y1 = 0; - GC->p.x2 = pos; + //GC->p.x2 = GC->p.cx; GC->p.ptr = (void *)GC->linebuf; gdisp_lld_blit_area(GC); GC->p.x1 = sx1; GC->p.y1 = sy1; - GC->p.x2 = sx2; + //GC->p.x2 = sx2; GC->p.cx = 0; } GC->p.x = GC->p.x1; - if (++GC->p.y >= GC->p.x2) + if (++GC->p.y >= GC->p.y2) GC->p.y = GC->p.y1; } #else @@ -465,13 +462,13 @@ void _gdispInit(void) { // Just wrap at end-of-line and end-of-buffer if (++GC->p.x >= GC->p.x2) { GC->p.x = GC->p.x1; - if (++GC->p.y >= GC->p.x2) + if (++GC->p.y >= GC->p.y2) GC->p.y = GC->p.y1; } #endif } - void gdispStreamEnd(void) { + void gdispStreamStop(void) { // Only release the mutex and end the stream if we are actually streaming. if (!(GC->flags & GDISP_FLG_INSTREAM)) return; @@ -486,7 +483,7 @@ void _gdispInit(void) { GC->p.cy = 1; GC->p.x1 = 0; GC->p.y1 = 0; - GC->p.x2 = GC->p.cx; + //GC->p.x2 = GC->p.cx; GC->p.ptr = (void *)GC->linebuf; gdisp_lld_blit_area(GC); } From d704c2f6d05ecaffa644213f728ed2d0182eeaee Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 24 Sep 2013 16:11:29 +1000 Subject: [PATCH 008/160] New inverse square root accelerated math function --- src/gmisc/trig.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/gmisc/trig.c b/src/gmisc/trig.c index 510ee597..00b6365a 100644 --- a/src/gmisc/trig.c +++ b/src/gmisc/trig.c @@ -142,5 +142,23 @@ #endif +#if GMISC_NEED_INVSQRT + // Algorithm based on Quake code + float invsqrt(float n) { + long i; + float x2, y; + const float threehalfs = 1.5F; + + x2 = n * 0.5F; + y = n; + i = * ( long * ) &y; // evil floating point bit level hacking + i = 0x5f3759df - ( i >> 1 ); // what the? + y = * ( float * ) &i; + y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration + //y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration for extra precision, this can be removed + return y; + } +#endif + #endif /* GFX_USE_GMISC */ /** @} */ From f16d80e099fd7e7fad241d8d08525920235893e5 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 24 Sep 2013 16:12:03 +1000 Subject: [PATCH 009/160] New streaming demo --- demos/modules/gdisp/gdisp_streaming/gfxconf.h | 42 +++++++ demos/modules/gdisp/gdisp_streaming/main.c | 106 ++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 demos/modules/gdisp/gdisp_streaming/gfxconf.h create mode 100644 demos/modules/gdisp/gdisp_streaming/main.c diff --git a/demos/modules/gdisp/gdisp_streaming/gfxconf.h b/demos/modules/gdisp/gdisp_streaming/gfxconf.h new file mode 100644 index 00000000..0b5701ba --- /dev/null +++ b/demos/modules/gdisp/gdisp_streaming/gfxconf.h @@ -0,0 +1,42 @@ +/** + * This file has a different license to the rest of the GFX system. + * You can copy, modify and distribute this file as you see fit. + * You do not need to publish your source modifications to this file. + * The only thing you are not permitted to do is to relicense it + * under a different license. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + +/* The operating system to use - one of these must be defined */ +//#define GFX_USE_OS_CHIBIOS TRUE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_POSIX FALSE + +/* GFX sub-systems to turn on */ +#define GFX_USE_GDISP TRUE +#define GFX_USE_GMISC TRUE + +/* Features for the GDISP sub-system. */ +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP FALSE +#define GDISP_NEED_TEXT FALSE +#define GDISP_NEED_CIRCLE FALSE +#define GDISP_NEED_ELLIPSE FALSE +#define GDISP_NEED_ARC FALSE +#define GDISP_NEED_SCROLL FALSE +#define GDISP_NEED_PIXELREAD FALSE +#define GDISP_NEED_CONTROL TRUE +#define GDISP_NEED_MULTITHREAD FALSE +#define GDISP_NEED_STREAMING TRUE + +/* Builtin Fonts */ +#define GDISP_INCLUDE_FONT_UI2 FALSE + +#define GFX_USE_GMISC TRUE +#define GMISC_NEED_FIXEDTRIG FALSE +#define GMISC_NEED_FASTTRIG FALSE +#define GMISC_NEED_INVSQRT TRUE + +#endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/gdisp_streaming/main.c b/demos/modules/gdisp/gdisp_streaming/main.c new file mode 100644 index 00000000..cc5eb8b3 --- /dev/null +++ b/demos/modules/gdisp/gdisp_streaming/main.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * Derived from the 2011 IOCCC submission by peter.eastman@gmail.com + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gfx.h" +#include + +#define Lightgrey () +#define Midgrey () +#define Darkgrey (HTML2COLOR(0x303030)) + +#define BALLCOLOR1 Red +#define BALLCOLOR2 Yellow +#define WALLCOLOR HTML2COLOR(0x303030) +#define BACKCOLOR HTML2COLOR(0xC0C0C0) +#define FLOORCOLOR HTML2COLOR(0x606060) +#define SHADOW (255-255*0.2) + +int main(void) { + coord_t width, height, x, y, i, l, m, n, floor; + color_t colour; + float ii, spin, o, spinspeed, h, f, g; + + gfxInit(); + gdispSetOrientation(GDISP_ROTATE_90); + + width = gdispGetWidth(); + height = gdispGetHeight(); + + i=height/5+height%2+1; + ii = 1.0/i; + floor=height/5-1; + spin=0.0; + l=width/2; + m=height/4; + n=.01*width; + o=0.0; + spinspeed=0.1; + + while(1) { + // Draw one frame + gdispStreamStart(0, 0, width, height); + for (y=0; h = (m-y)*ii, y height-floor) { + if (x < height-y || height-y > width-x) + colour = WALLCOLOR; + else + colour = FLOORCOLOR; + } else if (xwidth-floor) + colour = WALLCOLOR; + else + colour = BACKCOLOR; + + // The ball shadow is darker + if (g*(g+.4)+h*(h+.1) < 1) + colour = gdispBlendColor(colour, Black, SHADOW); + } + gdispStreamColor(colour); /* pixel to the LCD */ + } + } + gdispStreamStop(); + + // Motion + spin += spinspeed; + m += o; + o = m > height-1.75*floor ? -.04*height : o+.002*height; + n = (l+=n)width-i ? spinspeed=-spinspeed,-n : n; + } +} From c5ceb31e730b31f003b3b61c1172670e6e549994 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 25 Sep 2013 17:15:50 +1000 Subject: [PATCH 010/160] Update to streaming demo program to only update the needed area (results in much faster display on slow devices) Also now demonstrates streaming to a non-full screen area. --- demos/modules/gdisp/gdisp_streaming/gfxconf.h | 2 +- demos/modules/gdisp/gdisp_streaming/main.c | 61 ++++++++++++------- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/demos/modules/gdisp/gdisp_streaming/gfxconf.h b/demos/modules/gdisp/gdisp_streaming/gfxconf.h index 0b5701ba..72bb0618 100644 --- a/demos/modules/gdisp/gdisp_streaming/gfxconf.h +++ b/demos/modules/gdisp/gdisp_streaming/gfxconf.h @@ -27,7 +27,7 @@ #define GDISP_NEED_ARC FALSE #define GDISP_NEED_SCROLL FALSE #define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL TRUE +#define GDISP_NEED_CONTROL FALSE #define GDISP_NEED_MULTITHREAD FALSE #define GDISP_NEED_STREAMING TRUE diff --git a/demos/modules/gdisp/gdisp_streaming/main.c b/demos/modules/gdisp/gdisp_streaming/main.c index cc5eb8b3..41b900c3 100644 --- a/demos/modules/gdisp/gdisp_streaming/main.c +++ b/demos/modules/gdisp/gdisp_streaming/main.c @@ -40,35 +40,44 @@ #define WALLCOLOR HTML2COLOR(0x303030) #define BACKCOLOR HTML2COLOR(0xC0C0C0) #define FLOORCOLOR HTML2COLOR(0x606060) -#define SHADOW (255-255*0.2) +#define SHADOWALPHA (255-255*0.2) int main(void) { - coord_t width, height, x, y, i, l, m, n, floor; + coord_t width, height, x, y, radius, ballx, bally, dx, floor; + coord_t minx, miny, maxx, maxy; + coord_t ballcx, ballcy; color_t colour; - float ii, spin, o, spinspeed, h, f, g; + float ii, spin, dy, spinspeed, h, f, g; gfxInit(); - gdispSetOrientation(GDISP_ROTATE_90); + #if GDISP_NEED_CONTROL + gdispSetOrientation(GDISP_ROTATE_90); + #endif width = gdispGetWidth(); height = gdispGetHeight(); - i=height/5+height%2+1; - ii = 1.0/i; - floor=height/5-1; - spin=0.0; - l=width/2; - m=height/4; - n=.01*width; - o=0.0; - spinspeed=0.1; + radius=height/5+height%2+1; // The ball radius + ii = 1.0/radius; // radius as easy math + floor=height/5-1; // floor position + spin=0.0; // current spin angle on the ball + spinspeed=0.1; // current spin speed of the ball + ballx=width/2; // ball x position (relative to the ball center) + bally=height/4; // ball y position (relative to the ball center) + dx=.01*width; // motion in the x axis + dy=0.0; // motion in the y axis + ballcx = 12*radius/5; // ball x diameter including the shadow + ballcy = 21*radius/10; // ball y diameter including the shadow + + + minx = miny = 0; maxx = width; maxy = height; // The clipping window for this frame. while(1) { // Draw one frame - gdispStreamStart(0, 0, width, height); - for (y=0; h = (m-y)*ii, y 0) maxx += dx; else minx += dx; + if (dy > 0) maxy += dy; else miny += dy; + if (minx < 0) minx = 0; + if (maxx > width) maxx = width; + if (miny < 0) miny = 0; + if (maxy > height) maxy = height; + // Motion spin += spinspeed; - m += o; - o = m > height-1.75*floor ? -.04*height : o+.002*height; - n = (l+=n)width-i ? spinspeed=-spinspeed,-n : n; + ballx += dx; bally += dy; + dx = ballx < radius || ballx > width-radius ? spinspeed=-spinspeed,-dx : dx; + dy = bally > height-1.75*floor ? -.04*height : dy+.002*height; } } From 30154560b6f588c42032bce94152676c3756124e Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 25 Sep 2013 17:17:05 +1000 Subject: [PATCH 011/160] Rename a macro and fix some bugs --- drivers/multiple/Win32/gdisp_lld.c | 6 --- include/gdisp/lld/gdisp_lld.h | 11 ++--- src/gdisp/gdisp.c | 65 ++++++++++++++---------------- 3 files changed, 36 insertions(+), 46 deletions(-) diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 0f1a0b03..f55f3700 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -287,12 +287,6 @@ static DECLARE_THREAD_FUNCTION(WindowThread, param) { /* Driver exported functions. */ /*===========================================================================*/ -/** - * @brief Low level GDISP driver initialization. - * @return TRUE if successful, FALSE on error. - * - * @notapi - */ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { RECT rect; gfxThreadHandle hth; diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 3698efb0..6efdb6bb 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -45,8 +45,8 @@ * @brief Hardware streaming requires an explicit end call. * @details If set to @p FALSE if an explicit stream end call is not required. */ - #ifndef GDISP_HARDWARE_STREAM_END - #define GDISP_HARDWARE_STREAM_END FALSE + #ifndef GDISP_HARDWARE_STREAM_STOP + #define GDISP_HARDWARE_STREAM_STOP FALSE #endif /** @@ -143,6 +143,7 @@ typedef struct GDISPDriver { uint16_t flags; #define GDISP_FLG_INSTREAM 0x0001 + #define GDISP_FLG_DRIVER 0x0002 // This flags and above are for use by the driver // Multithread Mutex #if GDISP_NEED_MULTITHREAD @@ -241,10 +242,10 @@ typedef struct GDISPDriver { LLDSPEC color_t gdisp_lld_stream_read(GDISPDriver *g); #endif - #if GDISP_HARDWARE_STREAM_END || defined(__DOXYGEN__) + #if GDISP_HARDWARE_STREAM_STOP || defined(__DOXYGEN__) /** * @brief End the current streaming operation - * @pre GDISP_HARDWARE_STREAM and GDISP_HARDWARE_STREAM_END is TRUE + * @pre GDISP_HARDWARE_STREAM and GDISP_HARDWARE_STREAM_STOP is TRUE * * @param[in] g The driver structure * @@ -421,7 +422,7 @@ typedef struct GDISPDriver { gdisp_lld_stream_start, gdisp_lld_stream_color, gdisp_lld_stream_read, - #if GDISP_HARDWARE_STREAM_END + #if GDISP_HARDWARE_STREAM_STOP gdisp_lld_stream_stop, #else 0, diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 8ec2c998..2e423764 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -48,9 +48,9 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; #define MUTEX_EXIT() #endif -#if GDISP_HARDWARE_STREAM_END +#if GDISP_HARDWARE_STREAM_STOP #define STREAM_CLEAR() if ((GC->flags & GDISP_FLG_INSTREAM)) { \ - gdisp_lld_stream_end(GC); \ + gdisp_lld_stream_stop(GC); \ GC->flags &= ~GDISP_FLG_INSTREAM; \ } #else @@ -84,11 +84,11 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; return; #endif - GC->cx = GC->cy = 1; + GC->p.cx = GC->p.cy = 1; gdisp_lld_stream_start(GC); gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif } #endif @@ -110,8 +110,8 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; gdisp_lld_stream_start(GC); for(; area; area--) gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif } #else @@ -170,8 +170,8 @@ static void hline_clip(void) { GC->p.cx = GC->p.cy = 1; gdisp_lld_stream_start(GC); gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #endif return; @@ -186,10 +186,11 @@ static void hline_clip(void) { #elif GDISP_HARDWARE_STREAM // Next best is streaming GC->p.cx = GC->p.x1 - GC->p.x; + GC->p.cy = 1; gdisp_lld_stream_start(GC); do { gdisp_lld_stream_color(GC); } while(GC->p.cx--); - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #else // Worst is drawing pixels @@ -227,8 +228,8 @@ static void vline_clip(void) { GC->p.cx = GC->p.cy = 1; gdisp_lld_stream_start(GC); gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #endif return; @@ -243,10 +244,11 @@ static void vline_clip(void) { #elif GDISP_HARDWARE_STREAM // Next best is streaming GC->p.cy = GC->p.y1 - GC->p.y; + GC->p.cx = 1; gdisp_lld_stream_start(GC); do { gdisp_lld_stream_color(GC); } while(GC->p.cy--); - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #else // Worst is drawing pixels @@ -398,7 +400,7 @@ void _gdispInit(void) { void gdispStreamColor(color_t color) { #if !GDISP_HARDWARE_STREAM && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS - coord_t sx1, sy1, sx2; + coord_t sx1, sy1; #endif // Don't touch the mutex as we should already own it @@ -417,17 +419,14 @@ void _gdispInit(void) { if (GC->p.cx >= GDISP_LINEBUF_SIZE) { sx1 = GC->p.x1; sy1 = GC->p.y1; - //sx2 = GC->p.x2; GC->p.x -= GC->p.cx; GC->p.cy = 1; GC->p.x1 = 0; GC->p.y1 = 0; - //GC->p.x2 = GC->p.cx; GC->p.ptr = (void *)GC->linebuf; gdisp_lld_blit_area(GC); GC->p.x1 = sx1; GC->p.y1 = sy1; - //GC->p.x2 = sx2; GC->p.x += GC->p.cx; GC->p.cx = 0; } @@ -437,17 +436,14 @@ void _gdispInit(void) { if (GC->p.cx) { sx1 = GC->p.x1; sy1 = GC->p.y1; - //sx2 = GC->p.x2; GC->p.x -= GC->p.cx; GC->p.cy = 1; GC->p.x1 = 0; GC->p.y1 = 0; - //GC->p.x2 = GC->p.cx; GC->p.ptr = (void *)GC->linebuf; gdisp_lld_blit_area(GC); GC->p.x1 = sx1; GC->p.y1 = sy1; - //GC->p.x2 = sx2; GC->p.cx = 0; } GC->p.x = GC->p.x1; @@ -474,8 +470,8 @@ void _gdispInit(void) { return; #if GDISP_HARDWARE_STREAM - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS if (GC->p.cx) { @@ -483,7 +479,6 @@ void _gdispInit(void) { GC->p.cy = 1; GC->p.x1 = 0; GC->p.y1 = 0; - //GC->p.x2 = GC->p.cx; GC->p.ptr = (void *)GC->linebuf; gdisp_lld_blit_area(GC); } @@ -541,8 +536,8 @@ void gdispClear(color_t color) { gdisp_lld_stream_start(GC); for(; area; area--) gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #else // Worst is drawing pixels @@ -607,8 +602,8 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, gdisp_lld_stream_color(GC); } } - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #else // Worst is drawing pixels @@ -1532,8 +1527,8 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.cy = 1; gdisp_lld_stream_start(GC); c = gdisp_lld_stream_read(GC); - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #else // Worst is "not possible" @@ -1607,8 +1602,8 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, gdisp_lld_stream_start(GC); for(j=0; j < fx; j++) GC->linebuf[j] = gdisp_lld_stream_read(GC); - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #elif GDISP_HARDWARE_PIXELREAD // Next best is single pixel reads @@ -1645,8 +1640,8 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.color = GC->linebuf[j]; gdisp_lld_stream_color(GC); } - #if GDISP_HARDWARE_STREAM_END - gdisp_lld_stream_end(GC); + #if GDISP_HARDWARE_STREAM_STOP + gdisp_lld_stream_stop(GC); #endif #else // Worst is drawing pixels From 5eabbaf7bf34463b52fb8deb96ff6df0f5a851ec Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 25 Sep 2013 17:18:18 +1000 Subject: [PATCH 012/160] Nokia6610 streaming driver. Orientation not supported yet in this new driver version. --- drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 347 ++++++++++-------- .../gdisp_lld_board_olimexsam7ex256.h | 24 +- .../Nokia6610GE8/gdisp_lld_board_template.h | 14 + drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h | 8 +- 4 files changed, 222 insertions(+), 171 deletions(-) diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index ba5178d8..e16c6d5c 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -15,18 +15,40 @@ #include "gfx.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" + +/** + * This is for the EPSON (GE8) controller driving a Nokia6610 color LCD display. + * Note that there is also a PHILIPS (GE12) controller for the same display that this code + * does not support. + * + * The controller drives a 132x132 display but a 1 pixel surround is not visible + * which gives a visible area of 130x130. + * + * This controller does not support reading back over the SPI interface. + * Additionally, the Olimex board doesn't even connect the pin. + * + * The hardware is capable of doing full width vertical scrolls aligned + * on a 4 line boundary however that is not sufficient to support general vertical scrolling. + * We also can't manually do read/modify scrolling because we can't read in SPI mode. + * + * The controller has some quirkyness when operating in other than rotation 0 mode. + * When any direction is decremented it starts at location 0 rather than the end of + * the area. + * + * Some of the more modern controllers have a broken command set. If you have one of these + * you will recognise it by the colors being off on anything drawn after an odd (as opposed to + * even) pixel count area being drawn. If so then set GDISP_GE8_BROKEN_CONTROLLER to TRUE + * on your gdisp_lld_board.h file. + */ /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ -#include "GE8.h" - -/* This controller is only ever used with a 130 x 130 display */ #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GDISP_SCREEN_HEIGHT @@ -35,17 +57,40 @@ #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_SCREEN_HEIGHT 130 -#define GDISP_SCREEN_WIDTH 130 -#define GDISP_SCAN_LINES 132 /* 130 lines + 2 invisible lines */ -#define GDISP_RAM_X_OFFSET 0 /* Offset in RAM of visible area */ -#define GDISP_RAM_Y_OFFSET 2 /* Offset in RAM of visible area */ -#define GDISP_SLEEP_SIZE 32 /* Sleep mode window lines */ -#define GDISP_SLEEP_POS ((GDISP_SCAN_LINES-GDISP_SLEEP_SIZE)/2) +#include "GE8.h" +#include "gdisp_lld_board.h" -#define GDISP_INITIAL_CONTRAST 38 -#define GDISP_INITIAL_BACKLIGHT 100 +#define GDISP_SCAN_LINES 132 + +// Set parameters if they are not already set +#ifndef GDISP_GE8_BROKEN_CONTROLLER + #define GDISP_GE8_BROKEN_CONTROLLER TRUE +#endif +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 130 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 130 +#endif +#ifndef GDISP_RAM_X_OFFSET + #define GDISP_RAM_X_OFFSET 0 /* Offset in RAM of visible area */ +#endif +#ifndef GDISP_RAM_Y_OFFSET + #define GDISP_RAM_Y_OFFSET 2 /* Offset in RAM of visible area */ +#endif +#ifndef GDISP_SLEEP_SIZE + #define GDISP_SLEEP_SIZE 32 /* Sleep mode window lines */ +#endif +#ifndef GDISP_SLEEP_POS + #define GDISP_SLEEP_POS ((GDISP_SCAN_LINES-GDISP_SLEEP_SIZE)/2) +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 38 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif /*===========================================================================*/ /* Driver exported variables. */ @@ -55,12 +100,18 @@ /* Driver local variables. */ /*===========================================================================*/ +static color_t savecolor; +#if GDISP_GE8_BROKEN_CONTROLLER + static color_t firstcolor; +#endif + +#define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0) +#define GDISP_FLG_RUNBYTE (GDISP_FLG_DRIVER<<1) + /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -#include "gdisp_lld_board.h" - // Some macros just to make reading the code easier #define delayms(ms) gfxSleepMilliseconds(ms) #define write_data2(d1, d2) { write_data(d1); write_data(d2); } @@ -71,29 +122,6 @@ #define write_cmd3(cmd, d1, d2, d3) { write_cmd(cmd); write_data3(d1, d2, d3); } #define write_cmd4(cmd, d1, d2, d3, d4) { write_cmd(cmd); write_data4(d1, d2, d3, d4); } -// Set the drawing window on the controller. -// An inline function has been used here incase the parameters have side effects with the internal calculations. -static __inline void setviewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+x, GDISP_RAM_X_OFFSET+x+cx-1); // Column address set - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+y, GDISP_RAM_Y_OFFSET+y+cy-1); // Page address set - break; - case GDISP_ROTATE_90: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+GDISP.Height-y-cy, GDISP_RAM_X_OFFSET+GDISP.Height-y-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+x, GDISP_RAM_Y_OFFSET+x+cx-1); - break; - case GDISP_ROTATE_180: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+GDISP.Width-x-cx, GDISP_RAM_X_OFFSET+GDISP.Width-x-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+GDISP.Height-y-cy, GDISP_RAM_Y_OFFSET+GDISP.Height-y-1); - break; - case GDISP_ROTATE_270: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+y, GDISP_RAM_X_OFFSET+y+cy-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+GDISP.Width-x-cx, GDISP_RAM_Y_OFFSET+GDISP.Width-x-1); - break; - } -} - /*===========================================================================*/ /* Driver interrupt handlers. */ /*===========================================================================*/ @@ -102,12 +130,7 @@ static __inline void setviewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { /* Driver exported functions. */ /*===========================================================================*/ -/** - * @brief Low level GDISP driver initialisation. - * - * @notapi - */ -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { /* Initialise your display */ init_board(); @@ -147,43 +170,115 @@ bool_t gdisp_lld_init(void) { set_backlight(GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure to match */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = GDISP_INITIAL_BACKLIGHT; - GDISP.Contrast = GDISP_INITIAL_CONTRAST; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif +LLDSPEC void gdisp_lld_stream_start(GDISPDriver *g) { acquire_bus(); - setviewport(x, y, 1, 1); - write_cmd3(RAMWR, 0, (color>>8) & 0x0F, color & 0xFF); - release_bus(); + #if GDISP_NEED_CONTROL + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set + write_cmd(RAMWR); + break; + case GDISP_ROTATE_90: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-1); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1); + write_cmd(RAMWR); + break; + case GDISP_ROTATE_180: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-1); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-1); + write_cmd(RAMWR); + break; + case GDISP_ROTATE_270: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y+g->p.cy-1); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-1); + write_cmd(RAMWR); + break; + } + #else + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set + write_cmd(RAMWR); + #endif + g->flags &= ~(GDISP_FLG_ODDBYTE|GDISP_FLG_RUNBYTE); } +LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { + //write_data2(((g->p.color >> 8)&0xFF), (g->p.color & 0xFF)); + + #if GDISP_GE8_BROKEN_CONTROLLER + if (!(g->flags & GDISP_FLG_RUNBYTE)) { + firstcolor = g->p.color; + g->flags |= GDISP_FLG_RUNBYTE; + } + #endif + if ((g->flags & GDISP_FLG_ODDBYTE)) { + // Write the pair of pixels to the display + write_data3(((savecolor >> 4) & 0xFF), (((savecolor << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); + g->flags &= ~GDISP_FLG_ODDBYTE; + } else { + savecolor = g->p.color; + g->flags |= GDISP_FLG_ODDBYTE; + } +} + +#if GDISP_HARDWARE_STREAM_STOP + LLDSPEC void gdisp_lld_stream_stop(GDISPDriver *g) { + if ((g->flags & GDISP_FLG_ODDBYTE)) { + #if GDISP_GE8_BROKEN_CONTROLLER + /** + * We have a real problem here - we need to write a singular pixel + * Methods that are supposed to work... + * 1/ Write the pixel (2 bytes) and then send a NOP command. This doesn't work, the pixel doesn't get written + * and it is maintained in the latch where it causes problems for the next window. + * 2/ Just write a dummy extra pixel as stuff beyond the window gets discarded. This doesn't work as contrary to + * the documentation the buffer wraps and the first pixel gets overwritten. + * 3/ Put the controller in 16 bits per pixel Type B mode where each pixel is performed by writing two bytes. This + * also doesn't work as the controller refuses to enter Type B mode (it stays in Type A mode). + * + * These methods might work on some controllers - just not on the one of the broken versions. + * + * For these broken controllers: + * We know we can wrap to the first byte (just overprint it) if we are at the end of the stream area. + * If not, we need to create a one pixel by one pixel window to fix this - Uuch. Fortunately this should only happen if the + * user application uses the streaming calls and then terminates the stream early or after buffer wrap. + * Since this is such an unlikely situation we just don't handle it. + */ + write_data3(((savecolor >> 4) & 0xFF), (((savecolor << 4) & 0xF0)|((firstcolor >> 8) & 0x0F)), (firstcolor & 0xFF)); + #else + write_data2(((savecolor >> 4) & 0xFF), ((savecolor << 4) & 0xF0)); + write_cmd(NOP); + #endif + } + + release_bus(); + } +#endif + +#if 0 + void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { + #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; + #endif + acquire_bus(); + setviewport(x, y, 1, 1); + write_cmd3(RAMWR, 0, (color>>8) & 0x0F, color & 0xFF); + release_bus(); + } +#endif + /* ---- Optional Routines ---- */ -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) +#if 0 && GDISP_HARDWARE_FILLS /** * @brief Fill an area with a color. * @@ -216,7 +311,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { } #endif -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) +#if 0 && GDISP_HARDWARE_BITFILLS /** * @brief Fill an area with a bitmap. * @@ -343,8 +438,8 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { /* Get the next pixel */ switch(pnum++ & 1) { - case 0: c1 = (((color_t)p[0]) << 4)|(((color_t)p[1])>>4); break; - case 1: c1 = (((color_t)p[1]&0x0F) << 8)|((color_t)p[1]); p += 3; break; + case 0: c2 = (((color_t)p[0]) << 4)|(((color_t)p[1])>>4); break; + case 1: c2 = (((color_t)p[1]&0x0F) << 8)|((color_t)p[1]); p += 3; break; } /* Check for line or buffer wrapping */ @@ -369,80 +464,20 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { } #endif -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) - /** - * @brief Get the color of a particular pixel. - * @note If x,y is off the screen, the result is undefined. - * - * @param[in] x, y The start of the text - * - * @notapi - */ - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - /* NOT IMPLEMENTED */ - /* This controller does not support reading back over the SPI interface. - * Additionally, the Olimex board doesn't even connect the pin. - */ - } -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) - /** - * @brief Scroll vertically a section of the screen. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - /* NOT IMPLEMENTED */ - /** - * The hardware is capable of doing full width vertical scrolls aligned - * on a 4 line boundary however that is not sufficient to support this routine. - * - * We also can't manually do read/modify scrolling because we can't read in SPI mode. - */ - } -#endif - -#if GDISP_HARDWARE_CONTROL || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. - * GDISP_CONTROL_LLD - Low level driver control constants start at - * this value. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { +#if 0 && GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDISPDriver *g) { /* The hardware is capable of supporting... * GDISP_CONTROL_POWER - supported * GDISP_CONTROL_ORIENTATION - supported * GDISP_CONTROL_BACKLIGHT - supported * GDISP_CONTROL_CONTRAST - supported */ - switch(what) { + switch(g->p.x) { case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) + if (g->g.Powermode == (powermode_t)g->p.ptr) return; acquire_bus(); - switch((gdisp_powermode_t)value) { + switch((powermode_t)g->p.ptr) { case powerOff: set_backlight(0); // Turn off the backlight write_cmd(DISOFF); // Turn off the display @@ -485,13 +520,13 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { return; } release_bus(); - GDISP.Powermode = (gdisp_powermode_t)value; + g->g.Powermode = (powermode_t)g->p.ptr; return; case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) + if (g->g.Orientation == (orientation_t)g->p.ptr) return; acquire_bus(); - switch((gdisp_orientation_t)value) { + switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: write_cmd3(DATCTL, 0x00, 0x00, 0x02); // P1: page normal, column normal, scan in column direction GDISP.Height = GDISP_SCREEN_HEIGHT; @@ -517,25 +552,19 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { return; } release_bus(); - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: - if ((unsigned)value > 100) value = (void *)100; - set_backlight((unsigned)value); - GDISP.Backlight = (unsigned)value; + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; + set_backlight((unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; return; case GDISP_CONTROL_CONTRAST: - if ((unsigned)value > 100) value = (void *)100; + if ((unsigned)value > 100) g->p.ptr = (void *)100; acquire_bus(); - write_cmd2(VOLCTR, (unsigned)value, 0x03); + write_cmd2(VOLCTR, (unsigned)g->p.ptr, 0x03); release_bus(); - GDISP.Contrast = (unsigned)value; + g->g.Contrast = (unsigned)g->p.ptr; return; } } diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h index 90a1277b..8afc3573 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h @@ -16,6 +16,20 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H +/* + * Set various display properties. These properties mostly depend on the exact controller chip you get. + * The defaults should work for most controllers. + */ +//#define GDISP_GE8_BROKEN_CONTROLLER FALSE // Uncomment this out if you have a controller thats not window wrap broken. +//#define GDISP_SCREEN_HEIGHT 130 // The visible display height +//#define GDISP_SCREEN_WIDTH 130 // The visible display width +//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area +//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area +//#define GDISP_SLEEP_SIZE 32 // The size of the sleep mode partial display +//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display +//#define GDISP_INITIAL_CONTRAST 38 // The initial contrast percentage +//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage + // ****************************************************** // Pointers to AT91SAM7X256 peripheral data structures // ****************************************************** @@ -98,14 +112,10 @@ static inline void init_board(void) { pPMC->PMC_PCER = 1 << AT91C_ID_SPI0; // Fixed mode - pSPI->SPI_CR = 0x81; //SPI Enable, Sowtware reset + pSPI->SPI_CR = 0x81; //SPI Enable, Software reset pSPI->SPI_CR = 0x01; //SPI Enable - - //pSPI->SPI_MR = 0xE0019; //Master mode, fixed select, disable decoder, FDIV=1 (MCK), PCS=1110 - pSPI->SPI_MR = 0xE0011; //Master mode, fixed select, disable decoder, FDIV=0 (MCK), PCS=1110 - - //pSPI->SPI_CSR[0] = 0x01010C11; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/32*12 = 125kHz - pSPI->SPI_CSR[0] = 0x01010311; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/8 = 6MHz if using commented MR line above + pSPI->SPI_MR = 0xE0011; //Master mode, fixed select, disable decoder, PCS=1110 + pSPI->SPI_CSR[0] = 0x01010311; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/3 = 16MHz /* Display backlight control at 100% */ pwmRunning = FALSE; diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h index a1fa6050..43cc4830 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h @@ -16,6 +16,20 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H +/* + * Set various display properties. These properties mostly depend on the exact controller chip you get. + * The defaults should work for most controllers. + */ +//#define GDISP_GE8_BROKEN_CONTROLLER FALSE // Uncomment this out if you have a controller thats not window wrap broken. +//#define GDISP_SCREEN_HEIGHT 130 // The visible display height +//#define GDISP_SCREEN_WIDTH 130 // The visible display width +//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area +//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area +//#define GDISP_SLEEP_SIZE 32 // The size of the sleep mode partial display +//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display +//#define GDISP_INITIAL_CONTRAST 38 // The initial contrast percentage +//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage + /** * @brief Initialise the board for the display. * @notes Performs the following functions: diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h index 1a748684..e6834d13 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h @@ -23,14 +23,12 @@ /*===========================================================================*/ #define GDISP_DRIVER_NAME "Nokia6610GE8" +#define GDISP_DRIVER_STRUCT GDISP_Nokia6610GE8 -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE +#define GDISP_HARDWARE_STREAM TRUE +#define GDISP_HARDWARE_STREAM_STOP TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_SOFTWARE_TEXTFILLDRAW FALSE -#define GDISP_SOFTWARE_TEXTBLITCOLUMN FALSE - #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 /* This driver supports both packed and unpacked pixel formats and line formats. * By default we leave these as FALSE. From a8688eef3923dd85afb02a5bb4761a572c0cfc51 Mon Sep 17 00:00:00 2001 From: Petteri Aimonen Date: Tue, 24 Sep 2013 22:15:55 +0300 Subject: [PATCH 013/160] Add driver for ED060SC4 e-ink display panel --- drivers/gdisp/ED060SC4/ed060sc4.h | 16 + drivers/gdisp/ED060SC4/example_schematics.png | Bin 0 -> 305333 bytes drivers/gdisp/ED060SC4/gdisp_lld.c | 606 ++++++++++++++++++ drivers/gdisp/ED060SC4/gdisp_lld.mk | 2 + .../gdisp/ED060SC4/gdisp_lld_board_example.h | 127 ++++ .../gdisp/ED060SC4/gdisp_lld_board_template.h | 83 +++ drivers/gdisp/ED060SC4/gdisp_lld_config.h | 27 + drivers/gdisp/ED060SC4/readme.txt | 85 +++ 8 files changed, 946 insertions(+) create mode 100644 drivers/gdisp/ED060SC4/ed060sc4.h create mode 100644 drivers/gdisp/ED060SC4/example_schematics.png create mode 100644 drivers/gdisp/ED060SC4/gdisp_lld.c create mode 100644 drivers/gdisp/ED060SC4/gdisp_lld.mk create mode 100644 drivers/gdisp/ED060SC4/gdisp_lld_board_example.h create mode 100644 drivers/gdisp/ED060SC4/gdisp_lld_board_template.h create mode 100644 drivers/gdisp/ED060SC4/gdisp_lld_config.h create mode 100644 drivers/gdisp/ED060SC4/readme.txt diff --git a/drivers/gdisp/ED060SC4/ed060sc4.h b/drivers/gdisp/ED060SC4/ed060sc4.h new file mode 100644 index 00000000..8a38f135 --- /dev/null +++ b/drivers/gdisp/ED060SC4/ed060sc4.h @@ -0,0 +1,16 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +#ifndef _ED060SC4_H_ +#define _ED060SC4_H_ + +#include "gfx.h" + +/* Control command for flushing all data to display. */ +#define GDISP_CONTROL_FLUSH (GDISP_CONTROL_LLD + 0) + +#endif diff --git a/drivers/gdisp/ED060SC4/example_schematics.png b/drivers/gdisp/ED060SC4/example_schematics.png new file mode 100644 index 0000000000000000000000000000000000000000..0d9d095fc92830db42f5f2575aa4b937075f0d50 GIT binary patch literal 305333 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ⅆU^u;0^K{b8YktZZ)3)>e^F!D^3e6Aa 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 zËp5)cfCaAzo-i7XA#Lt6H#HvK=7GDPiq@izvAPvulTLQTP=}qb~`W7f}LzZ}N zpIbjMf4C-_l+vVQR3Hh^gqz~iB*A+gKk4_#{y(PPJDkn-{U1-nXw4d}RipM+wYM(B zti4C6z4sy!Yi^%Wp^SqzW_xDeZBgt{x$$j0|d0yvu zov+tr3c2*f&;PIhDdGhza*)yS6Un{z*$YgBRe(u|2iC%4FdIRU4l&>q(+6~fQ;Le^&hNj+UV!#>JJG2N7l&KN+ zwHi`k=jaO)F>6%3&Ec!pub|!&vO5T8r@a12rf0}DC6L9p1Cc)D`J~et-Jqswua5=W z-?tt&TQv>4=%Wae6@Qja-S)*cCmI+>5#q{u!Z-v(=j&PcmBA0e*XzrHan^_gp z57EqUQuSFsIA2Df`2+{oIx{p`E2s1x#+&RoBhY7pjc(BP<|@CFAQO)lk6YV(9X)h| zzbqHQUYpbx&_#+ft;4VK*zm63g+{FY^0}c`c;;AV{CHM(#inZRoJ2`zU0ed+BxefY zJsMur=B-TkIO&EXM=BlfLvtCXFu##Si%Re$;UPsWG}k^s2d+1iUU_Rh-?fj*|JBqd z&m#e#6a2&^9`WV?|1fx1%hD2k-R~XlXSEX)*CP>Tj+SXTGwN&1wcE{yo4z5msk7Fv z1b>+Sk=aa5U_RhTZ_wcGb5nqp{wkR^)AKh&$JF7|8{BU`+p@+t&b2BE`FXLi5SBRC zuR;s@YFqA)*!sN##$N9~KEq$f>%2I!qrA!G1_KcGQ8zYQWd@StHYuSM*GFp+6vorj z!|&QmNi{7$yu@1>FOsQ>tgE#IFu|w#3j&~uPSa1k7ti6pDju^M_0;xP{UBRz?cyov zO6WS#+z@laSufytDovag7WRKH^8Sok_4D&4)lztfMi}^1d{LNod$M#XRA#W6EB7m= zU)RSvYw;fXe(l2GPul*TwSgk|WeOV(?xk}zQp63}%&uKvVqpVSG%+6?sja$bhnNt; z3|qJ4?l5G!kYzE34iBlw)Z4|nz<5sb1pZJQEvZUELi8`f-4mE$O9A5)L~U8KL$fql zY+2A%H_+|+RTcq`O)kt%}z(B-NZw5 zC(5{?a5|jQ*P7VV-T76Hg`Fg(XNXn zebfPAhx_E$=z-xxf3*Iuxpt{&Pi?zj7|C0>;I!3A++LEpIF#Z>blCmL2fVBGNDB}8ZE{K6_z?1TJ>VC3u@EfG*FS>ET$GaP z4MZ3up0LJuLM#S3U*6Ss$w;$Fpqbx>U;oBy#YnVRhV+M4fE0TbP{l6@v;=*PGnl>4 z2I(y`qLR2{8={-MZbt$bMsu=eP;y-kwXFL*>kPS(x4H0h19c z8>X{$71%LjD`Sj$gOBBWc3{v&)E_!*B$j5wP}37e<8VS!1*tO5i;W?%PxqUV36)xk z&z3MmZ=nR$oI~>{VmQ>%PeN6&eXs)n2)&XeDhui&6C;-S!hMC66N5&P~&BHZRv^? zSp3KI$W?gKH_{pe5|| zkrC>CHn{!EF(W8H&Z+9_Zpu+%sJv479Y-5~y|sN$CfG?^q6A}&RM51q-Td2t>w6sY z{adQ2vs*14%!_L$J-Dh|UR{I73;aX{S+gF^{67~TW|DO#5nh4bKsTsN<7wYI1N9Wy~cb(IDDtXp#wshMbCkB9guh5>cj~?{w;i5#G0nYDh z(bZ{m?itVaB0f2Px#jwqNqm!hh<1GCXe(iDs0vj@vQ|7CEB!4I-{a>#S_Vq$!yvCBpC3bTB=c|E1E`SWU=&>P*j_PAZ6 z=q^e#u`uFOS`N>s_L_N@Qp#F%z9cF* zIlX~Ps;%t0(&Wr)Lanl9*?Q7nKKq%DdJK>SRJq1L8Kpl&*}0sVbjQ}ps(|KM^}XO; zxQtVr-$3eEqGS9_EUDP8{q1p)Z+31)(s9=9cHAm2HF*}ym1%GWkKiBE}T zrOX^Pu>O*R@5HJqO#!+2px9i$wYTm^&V6LL(^O~kizqMWU?XF}oi(zSm3F}zK5rh6 zKS&Cl=NuJLenqau5{XW+kDY_Pp|hqaymN4L!%C`aOg6n5$9!|Bx{eP8fDX&HoC<1b zZ6oT-olUG=%-+8|FSE|O?_2s@xlGd1`664x9nzmKR16q>mc8pyV2Y|l$5y6THYw%w7BY5Yytx^Y!|De$o7GCWwWh+A5S9T| z4oT)N927?1o<_*OmH*RD;%V<(-4`g1HI&5Vy|jLsTp8Q7rg9_ZV2f=2mYa|ytEoT) zo$GDemrH%wbQ8v*c6V4#xz8(7Cgf++B?g8%lkvGicJ|J8+H+L;OX(z_O6sl0M@CEF zcdR&B*}drW?M4OX;B9D1N9}=@Tu$b{1coYN1u5Oag+_q&~_}DK{T`248q~qZ2u3XsajAJ(rG& zErp$pTvCxrw%J68kUikWN*8};YM^2vYnIvH;*Z3N+qG|!CQKwU;6<^tZ80|~Zw6%r z*%+gZgzhHo4cq0&FgkW{c+lg^;ZvA{!NNy6o1a?xHoo`Q!XyZ`O0V{lQI5Qj&y&p{ z*&5}==T0apk5^jZWE`kU+1sL-_iZ4uJ8XJKvExUvc;Pf%5)q*?eVtM00`~A#DDhTj zV#Cp$`L{<}I!muKzIG-k`Y;qJwe>`-7@vZIvOhFTd99sM&fG<3H!pYdU*G5;*WuIm z2zr*?ks_SSVMaU{N|t3~*mMzO<{SQPWH{Vd#x=cCmZK3zQPo;2kbkGb)!byq1}84n z9`jaMT|^ge-Ph<##s0Y68EO$+Rf0+<9T6@|{Wu!Xd~Xz>7=D-@UJ3y?*(Ua^UWms& z<5hmDk(*iKl2TDR1Y5JJ{;Ck#5Xo#rM6q`MlH_BXSl3s!FT(2IZ~T6JLWuGW+wowP z{0T}OFnQhNN5}0DzdgH8clzf`YrYc4}6UGxJY<$*P8CA^eb*y8AcBqs$F4j z_xZSXA#V06iIQOgop+WO zIkcPIWa-ih%J0Ul)YXyg;WC)Utx6FiqfQ4!o~h&qW}>+Tx7;}MyF2N+c|~)4>>lG! zASY`jG=fv{XGMNTS%8|~g4#B@L)WzxZW08Tv)*hB$X!pq45Q)r37yS5l+ z5V`wSK&fy*AksHX^TO`UhZ>5#drUaXcg{N%gTM7Y#OQ&dtrsQgEqMYfBp|+4avynf zdMVY0spZpm($#l9h`9JQ#+4-8+CSm8&%HNW9?Eft+56os%9|CSv-y=H7H&8B4Gq{Y z`Rg3FJ>RoDicR!AqU`3D_DMLy??rDu!gj$&MjsBD@)Tmsik@DCaL>nb6nXf$ZH1q0 zJNg0)YX?L=4|9d&ee|@$e)2b`_~>mUbXkN0T{F!sjUIKaIku2{Gg8yY(l6he_`NS$ z8D~UY)Kul7i(nLkY4q;1!B_28Xpc@HqlO_~H>UA#5LA97>0~^35I}Ip@yJ33DcAM; z5ET7Rc)`bMb9fZT#zENyFYel_8b7Rp%5qB||u znjLB`q79vU#tv{r@a{PYh)v#OZ1=H)banb5_D^~OR!+!#J>$uT$4-?cObanUOOL;* zV?XUW-tWbWp_c8#Q>s2T(^m|#?#@2dl~;=?I%C>SpBE_n}jdLmD)v9d}@5XxRDz{ znz^9ar{}LFRtD-$>&3wEq}HRPc<&T5M`V?P%qe86^53kf7Z9J` zauErAdt39x*n!qS;(hF{fD8JOf{Y{Amq+yT@vMIAq|_4i2H3KPaTnj<&fvw=K&aS8 z1DF;(OEaTb_$_BZz*-s0phPn1=afFQbsySYR<(F2vvcKK4?4Tn%tMGD+W{K~-}v|n zVcY!KW2I2&S@r_?ywE5HFU7tc9l}uH=BzPUm*|JJR$|0mHs84?c#F0@_2NtGHQDcY zs@=Y}wesNZ(VmZ<>e=J>_hfdq_TBsW2B)kdo!=#wip`M8?)_qRcJ65aSw!4fiIKHG zpnH+f%M>rn$dDKRIiQYX{_9bY)NA|$ljX&Ncye-va%~I$kJ)&in{$q*LD3S68WWOV z))EMrX>xIlXIGNdqgoML6iWO71?E06LW&epy*|yJ_+wpjXS;SgoN%;H!b6~S&U087 zw#ovOu_$FP^=aCZ6roQ}el87v+HKyxS7c3e^SQ=ClC)*+ET{dW`O>Bz>uMvyN@mX8 zne?&^?~Qd6qXXqiB;6IYUFy z0F0J5sHpDiq%CT~`8Xmz6OTK!->Ym1s{q+aaV>T5>83vTi;m+Wjg(7*EX7|XhT5e{ z<|GO`n?idP$Ee><)MuN`CcbTx9c5OM4@yz$-v8E@;0XI*%)z9@A-grj&9!D${Fr*% zj3+O-LZ{NpnGY(@JwAQP>FTKWaScnZdm>|4&B6!*Mx8%F9(=Q{E~qp^KWV;WBu$3U zh+W`WaCa`^tt4*8Xg={3J%j+v#-leV>Kt#39WSA^^xB+{>k#=sJS^ap&gI4>$x6R= z;<%AkM+)xKRFJ0(%!Q0Pk8sMDzS7mA+@AI8lqf`*fmFzu|J<#u(%H5@$jbD=y=^Xt zF8lydE5-v-MtzgC+s@^hf+40~nxTq_G;8+c%%}b7 ze%Fn)tylXDA(_BrV_4Eg^{2;kNyueD>F$>%*LI2$zW;B%IwM4jf61(`_AGvG!mT&A zc`do*vMH#unptqY;*;|1#m8gm#aAv)y1{huE~{LpN74*t+_UdruF6Q%56OFIxd%Ao z`-c`Qi*0}hxE-hRs{`rXcgndA!751SoANsf&Z(FE)fC~A`SxQxuMmz`(|Mr>*rWtuFky)Kt-8U9N|1sW z(BI#)!$v|km*s!0ffkD|VH+PWIv+0ReiXqMESb)>8=#mD=KEEDuKieAU+Yz&>JAuO zy1sFB!R?!-(hH!7I?6-!xv0#vmuk4^BZr_gk_{fdlCn<$_RyRI$pQ7_w++hd*>jwQ zW@rMKUpt&Wv!{UFta4z=4w@6>X(i;vs=Cv&TEFQa14nYi_8t z6pl$LiE+b2=%(2|$<$?TvZ^zhqrPlC4Cc!lZs?J^FnLGJAWL+S)!gS+y2PsF92w${-EzJpxtkLxI3R(^`e zcKD|17kSsU-@C}(>i!nk!52Xfjrr_t1}Oi7Tr(bdA|MF}ejr!1m?Zpo+o-Y%;pP`K z@h^{`^!q=4X(NdMx81w+pC?)yCp}K63}8}Sbgmi5k?+z&_!)C&;fWKulpK-sbQ}!% z#F>)qyaP=nK+S5Kd@zqJGAC0x0h~w?OZf53BxFV2vi@^k`krgaXyJuPWX-QP^9o5{ zcufz=!A+JwdlO^x<@Y`d?0tTrKP1BOITL77O5D2IL3vb6NRp{nEcCS47>wcYa=spL zP5T@IKqJUOEAa?+0IG>S(6C5z|DYG5)EAQf`Y5;7tL+DEnbV!dczFZ6K%K1E`lDN*i z=dwJs=n4Z=(_6Z;+$+U(^tHA(xn>PH{=;Q&*?Sgo0)2 z+JK+jPrGMV27QUjLWa5pkUGXuV?&(-qOua+I=M=AH}q&qiQeQ|JQSSw)yt-0N=qi9 zaluUb-Cvn;q;ql{_0a(ao?V2f(sww*v|hJc!oWV@>K|bN2b3h?KSq~A9L`8$PyA2% zWHHdoXJXJjq%s4OtBvWLR z67{MpEIIQ-ogx)>zqLP`81eD*Lkm`%B{4D?R+KUNp+X_Ux)g!+3ea;~l#jEFNL8Xq zY}uZNH&edD&mfkPtuwG}Z*`JJ*0ZH?n$@bt|4@#`eM@~85?{LdxSp1803833?7_4_Ly#SoKOqzf%A(vNt_V9sjj=+NjrRljF5;wTm8W8V*p4?_{td-I;%0aZ)W zPq#6NKSAGrlud%)XE(L5i;;EsYb(?yP|!xT#%FuYl48VIw{AWjzIZI2%us*<*i1)` zrkb~_q>MpKlPuGBAMCT6^sj$VzNLTNATZ4}eI-pm0~n!k?^hU((x0l?_LfSp<**3! zbbYzq@Eb2^=5+dbNY6XzNZJqM)VHS}ApP>!{77RncW=*d%i^zpQ#Ry1KPOP?ihr3uuj`;3V4PqUl$c*G0 z?p|E}<#!K_Dep;rlXr9OGBY1FQ|rOksQa(9k>)-rw1l!7ev?dr(`bskirU1 zG6%ty=a&}|tjEfg{*-==9ajqr{_@;ReHqG6YY_0I-pf%EotbVXnqWi;0#}#g`=`T4 z`o9jv^XcDe)~0(A^H=Q~5S4erKEM4Q!Ia6#Mh&pi0@?-@i8*rwgzZlVjixblQQll=71h%D zrg_dP79ZjRwGhYV{>qU1JH7aC2S2`qZX}SSx0(`~Q$NXKoGplH1p{9h02>xCr#Vsh z4MEBOz|25jo=lcX&dw=UcZtZL!p&FSzcW(u#3~;|+pKJKE6QXM>S=C_S&fV;xUk z>Ej*ik3Uo&C(_r@7mm+aA<`pf%Cmq@E|%s8Ur;mASDpFplbe@3W$1B%nS~-_K7nS z=$UiDCpohMSTIz(=OWCvxVQrI$?3mU{omp`|6B44ez~2wokz-Fklqw5Fv64Ie>gt8EVN!heyP zl2y3_D=gU^%YJ>J71Gt{U`0nSlS>3yCRC}(f+Qop42|3>qBuRGSlRh|6u|84lEMmEmAel8D`K! zi*FRHh^#=0O{Q(YYV=gMHg|&}! z_gw3(;UOzj8vK_`eKLg;1$ejNZY~`?6P%AE0}RMTfY^^>kch^6wC`J*Wcj~K@~KMK zS8EUSf~vD;a#oYDw;TN2kCScs5--)@6`LS zU^2-u;`vKZSlQ6ltNC{3*p}Gcp{=4Xe=KHQFY=kP8?T-s;pK@4D%fa!RN4ep7gBXN z$+5~CAX456@nb!6yyfO@|5>0sq(h6YM(VQi(9bWIcRP=^YqvKoO_z#t^!%B11Xx9? zez&4h@gJzlzngFMAE@P+*x#p4f_mwEY-qtI$?63#!0Lly$f`V@EY{giQ5zG^GSats z^NUUp)_H=lf|j*^H{XiC;vUi4Bl#GTD)JSB-XT&Yc&zFdeq_D5!GbR`~o(o>xS{ynh9e-LhVukCsAp%_2cdp|duR z;ze5KUbG};q{QGN2G!BhYDBcFX(>?BL`2%_udmfAXeKKRTwV{&{$g89c)i=)rB`o4 z-_hh}q&*c@&HC2ru{j|fbSEa9ziwL z=HHq<1MsbT)LQ7q4EKME5lhdGvC$pqQ z!?K{%-b3nBzs_67+bHV=0%-J6h{*In<;D&BQR@X8SeyT9ra=gMe%j%#^=!v!6O`b3 za_r__vK?O>aCAzxULbw+t0oT%C;q)KIA#N_`uIi4K#f6!50dcrIO*{?#(sF^uI5Jl!3 zd|xM|SZ{LYvHi%*aY?g;%!)f!Kr)xj>~1Kt65ImqHtWE)R$sat~?R5b<0OxOBC)Hy+i2(<_B>@6l>*A7Y91J} z&5&aDm9I(39;Of>kEGkSV40!IQbcySH1IDScWFqeq8`8S(gOq669a8=xn+EeVGUYy zHN#?Al8lf$@-We5mKW#K_d~3yI2FzK4FM9a|92jZ5&wIr8d(mWazwtSfk)9?s79Qy ziJ6&n_+8*$s==Py7BkW!o=MRXBPhrjHrwUOwDltdY=Bh)2+A%4*TXM?c<*^zj2 zb!M8@;=4)H-J*38MmoxNj=MV7y;yjXNZ7?=Ml~;}!>@;Cp5i6FR)+Zo26Y5hZG7DM zF6;u?xo*V35%int#>r;tM7sme4c6IaRJxCU`=59XvRF3gHh3oOOgv4??HtJ7z6U=u97-3|dOH}qaL5x}B25g&V@W5R081vPm_?clD zR?fcZ4_?~DLb_pVZAGkvIy8l}S{vFOKRWiz>ZpE%g?FY?Io(Y}%fBxWSuGqDo_?xx z8ChK27(G5BMVyX!#gX~Y1Du>b;4~9Gb-bD$WETGAP%abnW|B8Ugxd2{mZ5#W7&V?+ zg5-Mwb?G#mw5)x)^#`+q5WLK?VRJ*0r#Q_}OAvTre2Mgi8)|hF4eieeovIRaQx*X3ePGrx1$?g6AXSXQ-hIqyNRV$&`+)}SI9SbCu6a7RbW{Oz0xn2x z;LoGK$10!61jRQXHe*vg?(QrLaect5an%;8eCtX5+UlfgnnWtoF3r%MDBJ( z*iBCOt;Gr-W1>k_p3aC3JZbaHaUuw5C)Aa@n;FP$uy{GI#q~L^&K4D{bLD-qO9Vqr zWEr;Rerl(zzk~saefFP_?T$M{OeO%5fG^?s5=V1k+GrQ4+y}Z(yAROs9-zBTo!n`D zpZl?^^BjXDDs{r_sQGPkuNgUPY4Ai?>+ld8dzsnB05Ee*bVHRsciii%iMGNvXB0Io z>4H~;N-CAiFxN~#|2}yw!5||(5F+h-oak#$nN^#sB+;qJcDfTAr8BQsd!wV2!9ajO zjl1A!1Y}2Xwq2HG{^Gw`+0>UFWP2#PWW^` z@xm4_6CbhuP}F7hQsr4Z>Ea~%Ws*zxd2yF+^;fkh_hM$H^jj&))0?z!KgnlZc~pR& zjMd&FpwX{(P0u9@6Qi4q;a8?I8t7`S`X(Y0g^g~sQ(vSANOp1iK3Nd+<{gPp2Lua$ zp$gVLNtYvU5lzX`^~>l3QR$l0MggKR{`puj|MDTH&;x5NC7<1?YLTn-C+XM=mssbk zpd#1&M-s0!qs`mq?K0*1_6II~K;8{e);BPxbrj>a zQ=7sx9&s*83yO)o@^N=&L>)=E<#u;DAe4VO(#+lO9fjwTwS~-UXoOdRZhL777)hE` zW<`+LZ(h*RDUz_gdTIC2*c>oYBHjvR%PyXn3L=(X5UTrPP=6l|!&oq36VEY;xk@OoaVWbcI5uXBMB$ERH` zxEir@NkQ9NLZFMxBxvU-BtSE#>W)K<;Ig#k=58B`7cNGouATEiWK#`o7B{UG<CGX}R~0%)7duxJF9?!B7*oHMO1q-YF*e!2UF?o3e((p)4hYTI z*5Vtsr+IB4)&lF94|<*ldHGlzcM;Xxru}3?7204Sczh>n@*Jg%3PiC?@ZOn;&M}O7 z|M`%$KFv`F5}BU#8Dqgy2~At#pq>|5AAcZt*rIjyI-3SN*LHBEWCeXf*uXU6r|0a1`mZ!b=Nl!} zTUH#1Y`>)cO!$Fnn7Y%nqk)<4=h8S$nKVUB>q!f(+PGIlKJ=gK6+M?sro9vIe7WJ!iDmWbLchZ62vS96f`@;V5`-l} z6j4SxOph2-T$cw)`u5L`t9`(sx%AAR|pt z4;NaE;soWV>hK>B7O<2?;zyWK&DOXq_)iI~vk*Y(u+1=A>qBhrV9T_U4sjlM@jY>g z@D8_n(|skeE|O!BwWwQr(|FDZk z_&Qqz-}0?NB*y=IOI=KOBLQeL#y_Cz??BzPdB=LR$usTIH%wZ7;5l58ouScEin`k6_q^ z-J-DH(FHNI;~e(5>rg9NLP!=#Gsmf((*Y*?_6v%y9xKNKc*Xb=w~h~}p|1yl;TFL~ zh%QHPo$ zD0gjldP2*I9CqO4gDH=qVGEGpy4~Emt#Q7bwc30?PJVcE&6IFWuH>`8R%Mupv>*7i0oZhgZjAKVDvgl0>mwyxL!i!LPE}Z^p7;kkv$qIc+5UFWA$< z|8vklw4&(LVovyr)6gg$H(Q5GtUhh*7YdlF+@Mvlltm3*%D_-L=<{(OY9GIlyl7l5 z_HJSc|Jy^p(d?g?5qODDzxwxYm*xVDy2>E=qe!j z$T1h)(S-v7%>Q;k`1IS$9W^aMX$Kq+_O`vP!xI&U0wd~dWKrhtp7$aq@Uo#dr-{uQHUMz zV^jj-ARh<@nq!LgL{*_w!}qf=AT#J(DPwYqVREXJat*t$*Fw3|K-~-2byyHg_q-wC z|6Q@HZ}m!Y8X9K$D@GUiw6`9gf}oGBAEdIEs?ikZIG4eyL6P`PTNP6+WhV&M07FP= zQ1va@HuJL6<`q;!Lr~WE$^QS=T(EdTvW^J2WxxhljCrWQ!DPsKQF~IXf&&X|@sMYa z1j`9s+Fo@mo-mSuhzZ8*fm7%Bl} zj%CN*!|bLXSwWgG(I4uDt56S-OJXNxWWk@dj-9X*8!~u%1A9`;8h9pJAH9!~=!mk% zBty@M_GFWgJdihJX2aaq*wS)`HwM1!?}hw;am!_luRN+gJ-M33d?Wp6=X6Bs}fas=Bv6 zfM19W8&t_Bxj}k)%WaN*HxNfWLDpcMaiV}prY$Ot5pb*SlylaicN5~;ccB52BX)aL z==~4(_Xs+eSGpUYdGa{dH~evl2n*IvZHDNO4P>qs8Vm-oiMXwNu-0MfD^f-nPXv#HYo^X5>Tzext0xs^oLP+y9K_s7&X7 zE36cCy%~M1f=ou@B{5brozYy!LHB3-#*iUA<)BZ~?nSo1cIre_L(<-Vzf>zow5{R+ zUwl-_%0{a_#&Kg)4oDMqjWm-))Y)1JcbAlH>A@m^aU2MPpTo zbm>7nmE@81a+Mkh z;f~LH9csPnu`;8nKqLohzHv&!#?fsvxPOcNAZkNK^<}8H%dP`~i@nQ8+vKSGf3wBwG3PV|-4%1g4K#5t%t#zPIoOX0Kd-bN6Ks;wirV|HiPqhooQu^I(W$oOxOrBjUnF9N*N%~v5USuc+2qR^SHGZC*< z)Hoa*0a$h z480}`@o5V4W+j@QQ|Xvjt*-N?z&c}a={T3hmQhPPB#{ba>q!KIZzm!M=HfA)C&gUc z`3k`uD<6*~1f>Ug5c$kpn$1poAyqdDS=%72bI~>Ps_ny_$;2|Gy$!DCqFnMTYoc>t zPao-IE}~Ou8Z-84(bz^WJCKr9r|eDxK>yVx>Pwfh^_>^vLpRz_ zz8byFq(L9g9s!bs?9yN5|37!x)&DnS1H4rKc*_I(-J4u;m$Dd+iN z?RH`vDTNCdSwYE@l^9zzlYN_iBy1EcNjrJv?IGtLFGhUQE8_MZe0!;J?A0oaQ5YA~ zZh!{uQ5!JZ8z|@{qlc(~(WFkWwF~ZSpp^>tW^P7DN z>vo2FQ0Rcl(><@bdAo}4qFR=!<^_Ur{esPp*C6WsrF_Ls3>d3v-!b4(BRmaa)M|b9 z@t)*mqoCVEd-uW(lxd(2=wp=KFsX?4+O+-T3aT7cjrpyAzc{B?7G}9TG*H}n_dg## z;dAFd5B>z#L-&1_`BcI;331=k48rCZ=il#Rnvuw>Wp2i1uvvE(j<5D)oA#dmlG-8N@A<>5G)8t}&4{3Q`|!$( z%bRN5N#za?FtTg-x#a7eHKOFRd;p0+{G(ekX zQ(hy_1tAZni`QNFRF-nHUkc0;sDmb*Jnbk%RbT0o=+!Pv1rj5DG8$wJ%9f>|jG#8m zWfl`YM$q@xUJU%@>}8GTdCaQJ4JJ2Sfz8d8OPTY9BwT!-Q`&Zn{>I3ECRz;rC+Gn7 zTB;yMoJa$#0ktG=wnaxFeMEI_$wr!NSZ}>XY{SNa+U5$fGI1*QJ{U8k->Jj{=+9~X zeJRq{m9Q7Al>!GU9OM^Np@rg#((zNA1l8N}S@Fl(Gy0!qVVm)wDB%El{8`Os&EGbI z44_RSe)?D+ppe%^#ks!kuQY)F@L-+L?Wwvj8OvL#Z>&1od#vlUpNcBQ{0^}iSX)Ym zzoa+18F^ifEtJ9h<;XaDAQWAKnnM}V&lY>c=D{Lhr2BC~!IxrKMEF@D4m)nk$dW zlR(;KG$`&VLS-{k>TTHRLJ@bFcke>c?x;wr3>w~FCHdf)Pj|?JP^=Hq$qiLgr9xzL zVqDt*#kfV|uUEWaO|UcJO=nQ~Zqc(i1VU`EL3<8%<w_s10td7(%CK@@L$y z{pZ5aJgn#?wts>cEoFW5Jdh{M;YnhTU?r<>fsu3)iPod%(A^(cem8e)Bp)%sibUBc zXFjp$fPqWe5%z}1hUy(jg2-Ssq!-$HA5Ddlg}ni3t->L31K`AC#T&j?5q9bchD&y6 z6L|F1M@ZZa-)uw|J@?Ux2#%135RRjr--NbWqBC>y-XU~hg!Eup2rD>7v_hP-L^ZTk zhssy>QLZJ{(H>v7FbUTa8cZhfMn;9D-cRC%m$kO4jvTWhmn!Xia8Vea+31SHA9&|A z(=9MiQK81tDkQzH)}xU`wx%Eov|C>@*#quoT)0A?c%;%ezYHkm*)~DmfMr3sM2r}f{$oK@EQ)c1orb=;$Vbx>*)PwzzPWnT%;g)07~~zET$U)0 zp-uuvd*JS3nrN>+R&{H3`oFEG0Ytqlfm&C;WpCby@x;B*%KZQuR&SP?S!;Z^V`*7IOo&)E)$c9@uu!*=P4y(|IjUK_lo z6`pzJB9cfhDQUG#Rb;bVeOeTE?PGLi6iui(`t|n6s*-#;F+l@lw=;~5abl>BW!#8a zN~0Z~q@5$p_c>&}iw;Dpx`u=S#hbeAkep9esR9t1y@u^JkY{pw139fu0n2IIb|#PR z!?a7)-s7&E?fN@GD1Z)Opmoh7W~S2|ortnTRixV=QlK~ng1KR4aidLU>vDJ4mg{|Q zIXpQljZ@pBYIGM^l_l`OGsHJT$}b2%lTmFtny8o-9kV^&R)7tQfvw_}(mfsdNAiNM~1%F-s^?-<2&8lWS;x*ngva)mZ!D~EmT$|*jXTbwW!qQ5M~ml4~N zyls%CwO*<e}iVItsYlQ{=m z7kujd9|g{GXuEk!jEh^0sD#aM8>$Xo1vZ{u$n~n$HD>%sjW`v26cq*N`>Z?s=XNogVKN~W~*rK$a?($68Pr`!nJ@rQ@i$Ei1xG?3VIH{ox1%@7*na8 z;C|*Fq+$py00N&5sMD+r>LoIyQiNVYe|-zt!K0a#O~>LQadG>=I=F z4$_F8`@?a$IJ2cXn~mW}$Q1*w115|-UBFubUW7ifBQoZMw^-^dRf^I)>2xG?;g~*X zb4_5d0sv0e;r&-Hhfu#;AGFNI%6f$`kytkEj(y!N>j!LGIlk_PVkVYA@&L7`-EsXw zJhr(WHcAI&5+YnK9>=B!$8ZwGHhxVki$ndAttj&56@|QW!$}79F@u%d+7z7@#~Bc5 zelfIiOUKBlz@ek~u}NXsY@mjptgKA0wKg5;8DUJrzCwy+z%U+8s9=j~xdi*ZAm}$>_vr zn~)oLIq1+eibw-Upl=kThiq&<#Wa4d%iP=vDc1sGHTHEZr}0w)BV8ALc+gK(15!M- z!_RH9)zbnlIBCT%9xX(H+1wR?=lKny$Fs|Jj;i#)hdqu!-;jQqV`x_!m4`^5tNcCL z-4|UjwfcvDQavhf2DH+}sNy+W<8m1GM_vCTA?E*LC8-%ow*{W!{sAM@D6e$u>B1vH z)o{`prM(ve4-bQ_HF?;KPh=Tp3O{XrJ;oqobkbZeEzA^~qR1o)4#2#eZ(EW465=jL z!5n*dOUR4VIQhD2$fXG!4D9P8NvO7VczZ&EPlGL7EVUs-Jm@hCmw=rxZpnl9V6c6X z0)jJ3cEl|q3Ft{AbqujL-#~P!l)#b3URO0`FDf)d_v%{Ke+EMJARF|yM5>7{K>6}x zUN5gXK?6v+@#;mKR?XLD$`ig;STKf`y=l?$NCG3%CRTA1#{sAwRLQ~?hN16x44L_H zA#UyXs)N|*|3}q#$FuqM?&h@_D*SjDxRfhA?Y{}`4 zJNbuafvBx31AngwU78df$IOi5@{$a0RSOZ$J^!89$Uu9tLmLlxu$E? z^qDp$)ndlZJTa*Jf#shPK|sAY#DY{2JjYaIULl+q(tNBDs8P z*OTdc?x*ni`$yFeA{LPOJ=Dv{VLpkJ)wq3V3#em4JIo4hT-1LUFp4r>*OQ(azaMi<_YRX4;<=9+r%U$h zw_AY*Xd-geGkfDv=yZj4?<6CDHe9@lR8iSPNF3d-nJ6Q#4LEA@H}%Cl#4*o6++uNGhaR z)Ul@8Q0aO>ujUL7Xa!e?w_Kire?{H9Bb`Hf30TVKp~mPQI5=1`ePN1T5EuOpT>KbE zW~%Si3exq7v*95#3KK#I3y}OmV^>$M4n6#=yxKAI^y{d2^bZ$YpKRZA9~YdQnRBzZ z;B+sW>(wRiJ`0=p$ZGMF#S7cy*s=f2l5Cp{p;-V2RqIZR!dF0^uu!XH2}^MFbb<#y z3U`bSZi(O07hVfSh(T&U`yC|mdvxvD;(CHqJ$O6Xy5kGcGYLE~Hu$lW3+022bgRpK z#V7cu9OEHRV1(edIw49S_x>mHgUI13#`}(W08nWd3H1yhdK1bemiDD9sNzUxPiGvE zc6U)fCBj>@&~mY|!8{{Dv|_#GSRqt8v>F3+O-s?o)`SO@PAwOkCcpN>ZT;Lpri>-m zKv3Z*TlhsU%3<$s*MDX`khQrA5N75t14~V_dyX9*MJYlEJf{tGFJwOG=9=c1zC#|S zB?@%Z+T-l;Pw;ArlNLo8si4G>zSMqJ(9jNul`dn~{sC;nI#C;8I)3JZ9{vd3@I=)# zD?SLiVoi)B1|jlH3+nMdOuTeRc|)Xkv+r#XD#l&tn9^7DucTMx5aJRCFk6!z3%ngV z!6@x8fhEQqZ;RIPKt{=Ip5WDixT9N*<{L_~RNZ|0-ln3rsuNwA4(BkTX{ z1xBvrUXS?QY=PF1M>Zg|fn!n^Rm1n7xgwFb__`u;q`CCnu+pRqO~Gn%%o(ZWw!7Ua zSDR?&m(yyXPB~YFsW4$^nQdM%y>gXAHG`)H9)+3e>dp^P)pJ{~CvOWtkxN}z*1Thd zFMf-sWl4Fmi;itSO%cv7wR?w63%ZMs&rj2ia;A`N8!GlSr*HYj zPA_uP)xssN7cOtL_<--Yq@p)5CsMp-<3D_9vIoHDO3yFg4C@7Fs9Kw>#InOjfk9nd z)5U7Tw7f@``(TFqkrTm!UiwpU{RRZE9=;15wYK`k(IczX^Vq<^^DJ><=(sSY8XN$4 z^0dt7*~+m=F0IxVfM4`6Yg`P~*);I1>>?XGgZCkude3s-he|57>5m-YYOq!E?JI$c zc9SEFa~vOi;+z2<66`sK(Cp5(@iA941Fe^*;M#V2zB@L6A`a|ZkP%264DA~Xa=|1tANy$8Q%ObOyZ%GpQh>H5k6HAeV2KY*E16@6QKTc_@aE*@0 zLzMXzcHoPQ%EG{h7MZ|Rc32Nk%w-W?z34OOr!HvK$C&Vxfa{JB!04y3PKSQF9e<=c z6teUuF;6mO@P{FyT{R|tBK;-v7A5ljP0@CHhs38b#gntt6CI7e_Yx3B_LGmF?1Ucl zxBydfa|}=QA_^c%2)!#s&L5x96#LgN)bejM|b>n93s$I=A`S{^@=A+gCQy8cYd{ksCeBI?K zBaxvXk0!<>3||R?p6P)$<&lPkT3xL1Px~p+5aKn@?@2Zfui{s68%ghm%XneMY_~%| zJ7K1tiHJe47*DuN;v?oiQ?4ff*3TI*V=2T9#LtgAoScxNUU5Acq~;7X#AwGV%I|qp z-n`a)iZJFtAS9UM??otR7262r=Q0F09m}9dFZGEv(uBR7jao~d96iRn%5TD$%Djem zaOr4wFx8JzS}~HVZ}T|-7l9@-xVO!pd!q3PQIN&#rK4|G1$Ig^e!qXkZQHOfP7pa+ z+1FQUtJr+pKD&tK@VbKAy@F`u{cJvB3_Edjn}<`K7s$7@!-Cj_4UgQbJ)$+6#6$B* z<){G9JszT%IXO{k^A$-qoAQ}El@%1t-B$|i8Dbh>jq*B*_@*tPN~VVO%N?@uZ0Y_; zgoDuX-YIBmLIUBtNoZ8WRdtonR8ld#9&%)l{|#q>K$-jKwx~UoAE=ff1=&*q4GKxS zSwV^(NZaCpYy3_17_k|u;#OkzwFtA>*)$WYo_q5sgQVENzS{f~^_98ClP|=?AcX{K z930_wQ9^sqz6!`iBwWJ(=?|Y?;YTl3?+%h>0T;sw8M{J|DYtFiyhrW`v$lU+YIBBn z(s5v-kdp~O*^XidB~hlcLi-k3y_1C}_<>I z2K_~u&S{i<9pS;m@iM**LrBG>w3wh0S)nYR0iG{Na1;D{bDV=JLPM%%Y!QmfMfYB( zn0)Ij%7^X!6YC*%z_#`Jx~T+x-VL2IbY16xh5$ZxZiZwZ^$wSKmO?E|#m-INbz0B_21#p;w>%yHi&JuZ z>p;Lzdtizu<3``hV_8H7q>v6;vUfgE*A=;)gt1RK2=!;uxzRl~M2mh~h}%mYzpAK) zY+)q9Yt3vGbkbYqf1h`5q1%ig^q5KSR>h$*(R=_YN5Q7a6tTwC2Tzs5y| z`5aIZJUKl1h|f(5ExGMY7Q_>He{2au9mA_@ zlxy}f1v&KdDyj4(4LqP#paJ|njNb>Te^@5Qmw(Z0I;l2==e}E8Y~}0b*`tBoVIy@X zvW&>^o2lGB$XuD!<0F$t4N?3Tka2dWk9!0-+0y+fLpK6-?XT*x z7x(EB1eAb?;EH#d-?*ixK6T7`&PZUKWz(!P((0;iwINsOVtp?y4vvraOCWqZPLlicG(?MM#qYJ z&NC7cSUa9k+l{5O5*R~6tF69ddp)cZN39K)*`wl2PGxhL5D!(*WK0h|DmeSGMwqlUg;rWZ!ZS~H+OZ3nW z0g=R7c5ETvzDQFai8fJBO~t(Y`6^(ea5!ZsT7@eWbb5SRH%0&cdPjDQTU0avG5!_K zk}m-pi7NMy!3TtV=B&^XRN-4|copD~A@Tg2`V#M#y>078;Ig z&JY)rx#Z6T-k@`P><*km6=6Jiy|#Rb`kXM2H~ZtHTHd73kCWD5K~^GQ4zdnn?+YoF zQJ)M|w(zn@#aaCDo*mlhkKodU-l3jv;VR#I0Nx%yh>z9StRsEyp5AMe-Y8V=qA7ff zox8J?!+RgH5xp&JX4k6qfaUX@|4Re@rOeHIfV6#9CQtr6#`mqejSSaO1~d8#r=Ipl za#;LgZBm6=-VHI4budw-pMj9-aECSs5sFkAlCMy`l(VYjNatwM^^h57ulryW8;?{J zzQxuQUyaMM5$qq@aa07{v$r;#-&jF7XA(^D#u90t8fW-o=E%nr_bSXNoGAOijJ2|i zHX`kum(HQ{pIAw;7`I+h+9|mc>-!X7edZfp6%#<-KB)P(T1@`Y3R*1B<3?-Xp=!<=H3tq80eKr_S-&Dr^iy| zi{*id=J-a`u#{0aWf0|wqzDZ*ka;>eF7vmCd^?M;#n9P5EQe+Ag zmu=GxGA?Ml)tAF_L^~grv|SP`s#~GD`O1rnM^81e6NssMbor?vKBrGlDA6Wr1^!;Duk*F_465SwS2(7>3YIm4L+BX~P^Nc=Kj0FdS9`K^LTQkcXxhS?!fmCV(`j;=jw~@$>5zP|W~W#{ zr#_wFh*#@3ZtwtYn-sLy^(8_T+$*yW^D*X0ZmG{cGW9dRKL6B;PpcyP*6gYNWpnW< zUa()vs(#!T2V+6TSBA^uvy0-?vBO~r%BzBWi2y03`7aS>%y$Adyj*t@1LyGqQWCZ_hEX^VCum(V!T*@0gWGA4tbu3&4^A20 zA@sIqM~ZO>v(E)}>vXtmLqq-Nn+Yk_>mbh07q-X&f|8G^kC<;N8qt4Vn@3V)5Z&D3 zzn7uCx}q{`Vo}>IifDOi9S?d>&Vhn zo2DyoKjK%tw$AT$;-Tyi)yVWvGxH-|=C3VtLI}io_8!Y(I}=bZE;*^oh#S<;DajD3 zdrM|Tli?*(1$)EZkUa6Cwu*+m z-rB>`?5_5)DJhG2T9Jl9K&8Tv-o)CU>lFQGe;Cydz=}vXbmhAnaVqC-Q?>-+-&#JSLD##?%83i)?!ETG42g&<&|CA&$0%rp^sfLxV!@bqy$ z?NH5AlHk2IyG|zzDPsG`5y)P*_^xPNx~;yH2c*MNXJd{kDl&FHmH(Q&dpw`F00j~v z5Q6RRqd#zDv^61*{8!ypo%3%!P$KY?B{_d}E0z2}r?#*UpFanBSWiWC*z9HU5{o zSMb;@DS>E;Gn)X^-Dj2{#|9qJ=YU9>#{nK?;tOtCx5UNi1D@R4^NGK@8+LUFgkQt`w-trp8LeYLpQd~nP=hiuBR+#@OusqO0`P&pgzqv0SB|4b&aSDdKwa?_B(Vke*msK& zHxWrPG(FU^1`~^VNxp(83vdIyMXmf3Rjp9uk?SAmAcm1y(vND%Gmr=(u?au~A@JP`Rl-zTas1gmTby!zq)}DGc zAC5bU$Cs;mA_~%tc{&?{C%*MlkOw!1iT|N5fZ%uLZvlX@UuSN`KFG%FrHxi4G zWw-j-9cK&JwK+g4nfRn@6WQg0(v>pvRXU8`hh_eYoRE_el8F|L_6 zT2s0rsphtYuu<9>TFQRWf$4dcOL)8fqHPb@&^?+vzMb;CTOM)9&VA$&eUpuPnnD*% zNa$?-eT(=A?e{|dN$ZJoDw~(Y_7vIW^pX<6x}Z@IA1FZ%`GORNEp2R#XU`9|;c(zd zRgiD@Fe&JK-KA?f+ZNp21~2xQBu#$fH!{|=!*9Tj4e;K+eN}n8-4kd5c>OfdNw>i) z8HF)`%}+cIch$!$!rbJLdw&G3n&!@R;nz*klTwKrZn3TkIT5LtnQo1NMmPzMe1R#K z9iGaLxHdDG8M$$QgvD3Y={n$VM^aqv@zB=G_^6+qFGT!vhq~YOL?u16~~!qzdEf906TVeV15b-->^p{W=Fi5eGz;X zDT;WI7f!o;kgkvSnwav9743CxC*4Hn21cg+6OXDD{{n5~Lu&<$s8y%c1;}PRapRcK zvTi%gpm8UkwJS4(>oisO289-w$g~d&jdttK3KDY&Hkzh}{M7IeM{_T19JClqv!5}V zrRoC9+zdA*vo^_4iS2n#N(SO|sfpk$=W*bR+Y(g1eQlur0nj9WN%ljlwqq(_kLk(c zXb>Rs<=Rvymhs$mKCQu|@t&ODyKz%cDlpL}PJ~d3Jw|%1ri4t3mcKaDdR~8%fB$4A zn}&1($ko*BLK7_1E;-T>%w#hATsV%5r#3XNGohmbTEh+CIg)TaGY)db&^wLLfY7q453c@`9)K4TqmTVvv z_W^<%8z#jQ$8a*((i@+m{Jli?YEvI_7!h=OG7g_IW>}jU3*Y9{u)rhxL&^w9YGIic z)d#4U+T#Tuhn#m(*KGp4DVsF`#i2JC7XOgBBkBw?;9K~LQN_*I+rD;t+}N?zGF@@h zJj#QIMRivVlHg+4spv_0tw3&L2z^9yK9y~Y8Tfq8ex~rBAt(fu(pyL+j&THXeDsU6yQ+pc>V|PMhwP~nD{%){ONG6$x;g?M zP+ZvSyC^wv_&HtqVFCxyAFIn)f^Jm`H6mTeZgovI-;-vsDrKC6j4B5CpRLq;+VxuP z24rtWr$(D^jJL7YZ_!1FPH~octCQBg`Z?S6I?a61>v_SV)< zQ&?N&2ehGM^ZowUMxgz3M0-x&%X>NqP}A`xfgDYG{(-yICRE2sT^ZzMO~>|I?TUv} zE`efPD*IR|%OQo-rMb$Lg=YkKNdzwySF40v-T=^iY| zWj*nsar2AA6H4a?Ghp)}-Bgv;Dx4m6EF@yH%aih_zm*;2afXN2(0+EZvg1~vaj;vD zaCeSSk|}H+bW|U#ne#YB|DoaWicNJ%sA`in3pILBGUFrS>CNh)XS<%w}jQb)GTnow&x6<+< zI>X<|ufE~}(W1ru#~(Rf>A4cu!bptRxN{&Kk+7r=#k4aDhuF9M?>=J{e^h2mxB!(= z>4M`2E!Wt#j%RYJlU(4ttI>hAW6Pq{qmuh%T}Rth*>H$r8=+$+uIyc01(`N*-*;{8 z)m8GYE|loj2Itl&E^lsp3aE-Rw>CiAT;e?&bvr=<#5kPEJd5UOKpw_p%jkNE{{9U$ zINkC_cIHvN&bcL^$HPUTrgPT4Vo>liy*3U46GF3ySv7>I$k|15rA2>*;(Prv-a((( zt@aaF7r~b1m~lV{w7s2hA+@*m+2eKec~)l7ROZ{YcG(5>)S|AhKEw#ZuB~<3_ZX-W zi5K^>e+@#|;I=IdT<|Qs79pGy($z~ zX949yb}+q?O+$UGu5EiA<8R|^pOTX;T(5J(>IFG?OnFZ?QQmy+e?Q-Fhi(JZhdsWu z7y%$8W;wILOZe-Wk_scn%bE4N10V{hanE(?aN-NDmF-Ur9kN+fsE4Lg_?X!_BVgi* zv2je{i)VH;O3(vk2HdTF?QKcAHLi-;L{_UBo-{>>B2uPohh`ZFB%hCUbMqMkm^39o za`bhwD-dWkQU(z>9qiys41@09j!cdmgQ(9gbne8#*b|axsF(11`j?*Kqxi$pb(`jW zm5o@arHr>fkV(ECf<|_kSzG^D_ zGjE5ADmJohcB`etzd75hTvuzZ?-pNJKWp-9VWH+LttEQ$TAuxc80|LG{owl+(g=Yk zc9@FGPo7x8=n=@v*iwvej{q7mg%zcgtTxa9xidd%X~J%0k{xdN8Zv2S+F$0%kaWu;OD- zkLln>(JleeAR0^NR`qL`{?#(ZINtPUgHfLA4zBb7)7$1;nY_rGxxzI*e*;w2t~5G= z8%0~R9#>#Oc*nX!u;)85Nw`Nj*)&_w1e%oztVq!5E)J_1plQjvMbohwJAWeEq9qvl zUdAW7d~bU|+JhZ4+h_}i!a3X=*WDIynw@hS-POE$zBxDQ%(Q^?gw|Gk1cmXmSa^lbtfW`3@| znEpO^8PP?jA*9jU>S3wBu&A)&fs4ZZ1ii!c>NY(lT{9mz>iTed0^68sv+F@fs9y+) zdqHX++Wj3*+~(U>?RfG&c(V?Z$dhjM_{CP2!USm~=>gpB?24vmJaP4A+9Cti|A!!1 zJnbw1oDcMUC=0%I@xx)a>3%cJISwRtrKJKO)Xh*sqfUI~CStf<^AbWgXXlCl&5+oQ zGq0eizKQ)Bi3Ou6G7|Ttc$EQTkyAtpFHE z@yTunJCM6M_nqv6{Bm3^d2?jPs@#oY^8O8f+mY`bdz zymz00?7B1iQ?C@Q;?N%jjQe?*MwIRhHBMj|jBw$7L=xi}kIaBbI#yCnb~Isn?>T*( z8z=Ypjvs4(b5{}%O~Q;N@dlMn@(u#`(Wt_)FOX2|(FCx~NHkM>mz!nYPe1@4wk}cQ)N~=luKDl$8O<5#I z6Iv{w|M@d$tt>E2ZNs>vX79X3m7bcXB8=-UM3zL(AQfwI5OB&yo*a%DI zGPy&772QHWjyYq`b-!NP#A2dTZ(g_8f!h%JI6hwXsqY#fQ+(4cVaF(`@^eB>L2$}z zj}&F*$0u2n;q{zy=GnM_cdreq7^6X24%n&I<0xN>SD766uFAkff6tAsn{yd_ZhcZ? z!)qW~TfFH^Z*nH&Y)NYmebZCSJCp$`K1f}eajt(e`~-1>Em0>iWB<0Kc#$|zE*bDW z=I=uJ*9SA0IX{zz_tr%-g2QJ^YTT~%R&R6&H91wH#af=I@;mia^{FE$T;ryX8D6ra z8gvu~_SyO5$_MSvW)Dv5w7&o7?6VX`8kAj$!&zhV)?PwZ=+ToPa!Zew$C|R{S)>3U z--KwL(Yn}l=B3r`K9ZtLJTKRyF(_ZwqO@Da)aNF?nTnKmV^ufeTXWj@LlRwkfVEUwq%KD!reKfsOS&?22n5#L{V#SBqoN@u9e z2+E6(ZAwj$rhwy_-l|Mh0dXe!+Y=uVu_u@K_4)CQYYj?9rx3QvM~Tghr5RUZ?*OCr z^1e;;5;swU(7o5D^MB)*<`VJqsy?0xM@*k~894ucOXeIp!30BeZQ$;KAwf-=;(`=^ z(0YU5NB9VnD|AJKP?an7aSP>(iVLs}GUR7O^JO#ig`8ix)hSr-z^5-{xaAl~YgFH< zwN3kN&Q9_LcZrTq1{5i#o~$1^bQdqHDA;B9j@fZS!@Q-jrQnhk)SM@jF0!>;e_Y}H zd&A;(LhZ=K0u^5FYjKx9d}=xmbXXTt3#WV1%F8{k&2P+v@-bUB^sHV`rRx1CV7ets z81TiN>Iph}5HiHLqdJ@xe1BI>+3r8n1opv6PZI<~jI}^Ey8~8j00e=&Lg*)lS74XN zan%(EUY_1E93Z&C>U~_-{ENNm_YFA3fS?vg9}|`H5};*suGq+O}+$sV`Nhk@&2 zq|toz3gCq6lwFgl09@+%ErArfvD#hqt&0yyV<=v6ji;YcaH05$yPrZ(@+g->{nxM+ zzlYYZT*TLn)E~C|Z0emXui~Fiqy00LVF=|0tH$^|7-Dbx)VXn~-!!#zNM8!nvm9O0 z`uZl0i@^E#jkfniY+^{<=m4vRKnz%;7pg|@)C=9dNDM`M-tBq=TNV!nh-wxcog@cMbe zE%<+L2MwFI{J%j97Y==a`PtP$v#iF1v>$`GrCTEm{Jh^tp(D5uEY6L4h7# zl<^^Q7H&;dQRE3QL_2h7K2Ql=gQW2HS+tulAcFM@j7XE^ej80EYd@RdAGd8Y2}cyX z2QB@&0Y@uA0H6OBkh*EX9C@%JUdB_` zQ<^ZgSCRhz-QZp(2MB>@oz^kMU(o+TEzn;*a7hZfQT82TYmW_KO7NqU7t9&pDsT%p zP85Lp@Q|8}oM};s6$((ayTPJ290_g^QhLnQhW~t2*pE;-5oKD3sYt%o5q+w!* zoF3o6n*#N}rAVljP!s%|;5o{3>OywdkFEi&m|(&e_P#DJR*K#IA&ACk1-q-n2@+o(nE zm9Z(t^(@s`H)FiA?<>Ucq7mx3`9OEJF~c#e>1=2_1`*(04|poi+_{3^_x^kyN0!BINC-PQ1Xw1p{iN6pLEs3jIwn`^1xsc# z*M-EwP(H2f_eEhS%*$Q%|3(~OnT|dY0HHCQO@Pru9BSj!R?2|pX^8Gwwit1NrYw$a zcw0fo`R}w*?0n$~gdk|nD=yQ7K&LNp=Ttzm3Pcj@LP+SFY}W`?yY_^UAG%^fD9oW6 zB9rfLO`(Hf%@(iZS2T!c35ktq7j!m-o9>cmk&D(D_S(LbX^!{BeiV5SLK56=d~23m z&khD`C5Gu(XQ^x&&UoDf&CN+8Q^aFv9}L@JL?Nl-EP@`XxN57 z>vbsW1`4Onfnu5(BN2v)FmpCJ$nCR8+c!_w&LD2^_GJtQ(z@RV>uWH~DWBLj=QOib zTWruNv^!*bbv^ES&|+sQ&C;X!*j^}H?$Vq$BgB>~J*1SbbT*+)qbA;u0ACx?|0y~< zO)FGp_Kl+>4q_F5^@mwp_CeozZjG;XwWO#w?_}4hzpWXBBE6xqpZv}5*Qe`p;mFS< z4o6Kj{`C1$-p(c*qdJqKSL2JHYdjv+D-v&16W$xz-=_26UA)#)bk%6kG^xdKp-nXAe)&(ev|nb?Tw8Su(;>=ll)~?tX_^m|wh9ji{yY}S z=^ak-|FVY4gV)=xxRiwc>f!~I(K-u+%dW+nEU3f1zUL5M9^H8Qi1JEju5!3n$gB{TNF^8r(ZU_!xGVn?%8o$!mW zV(5w-V81{MXlpf>}jTPO1= z9Z|;fVAgBZ62)p{eT=!_2w7AdNM)?$W&LI!%&;UgBPLj9md&V9=jup!yoUGo(7Ix;m>oKPv$rSU8DuaAw8vuyoB&s_pv- za(bUFvt|e3DL|0?@?#yu@%zWLDY#F}o`H1@q{WNW5Rx;|XUaG=O%;FX)Wx6a5U&QL zr)hG>9z6GRT#_nMvpa{mO1JyX@BcQ{k$?`XN#dK-zJon$Eex+FK0|ZUHpDfS}&NMXcSKCfN??jQ^D#oxu4~$5|ZN(wp|iqV`B); zYBezMyW-g;@jd*;f{hj z&(#3ISBCuWEq)6{qRwf?XLP9P>gm%I%#RGEu1Yz8m(Da0AW3e4V)%$wr3Vle$>P`j z;cxC>_X2p1X&jq3W9NRdH zon=$696g~u|K37xuBu=@nvrL(ilkXRIE5>D#~mytGiF{9Btn!y$QlQ1bly5o6vKKj zG{sktE{lBeK2{#{K{p^J&a5!uD*MCIQKZHoTD7$oszXh^#4_)UvZ|Y%k4JNS@QO=n zsE$TU@+}Js>E~7hw_3F0zU*E&%|98+r!dCAKKPE^MR?Hx=X%$=SH1^>iorwGI zP+;`r#vKKFzq5FJv}4WpYia!NG#|)FUuS`ssyIA6|IOM@Ctw`m_MHEbBGYxf#`#pc zmhQZJOD%;yApSEe&;BIHKm|kQO=!M%$7!x!)_e8@%ZwVT_l392Zy9m^tx=z@59Fog zr+1d8F$LOR{cVK5hl@m0=V#FDSg~v%YtR+*w}**3NNYM6Gf(1t;njppg$5lc<1)0$ zjqv{3rWI_6w;dDrjQ=F)!>&gQJZr2wX2|b|Dit{Uuw7{Vvb}_K<6c+T$8@U^zSa(m z19#=vBvp++|0-zUmY<~XTg^9GIL?4E4#&Jc+xD$Oqz_~@1#*yp)?u22nmE{XdRTiT zD7-;3y*UU{KpdNxAAkYINd2V$fC?%(ux}15QZr}Fza9-O39lX7HRay@DJDIza?fZX zo<6q>o!&bzhdV?Ijv-X6hE`7c0N+{~&}ck4%=V&hV%7>8~#7ojM=Fd6w-$Z8nt?-UCNoCRnzG$LK;E+6V2^EFOWf z5SppRSLd#JU&4o*>1&jy$sDH`&#&{}i157mt^JRMhb$U)eu>fj*VhYz0%e-t`Zatr zDO#b<^&yf(TTiC4lOIQZ?s9Ct!elV({T^>SCd1cl-9DJ@CXD}#@r;AAUP|6YML%j; zv%$@g=BDm{I#l5|!~6>I;hrvje+Se=wtEB>437diLA!uN>cE zm!|stJ1-Nyxs~;dg-UG|Q%~oohBll3_q~myBS6Lj&Ve3hSDc_fe^z1_SAX@wMSdar zp`S`FV!YaI`Ia1zj!i7+gyHu;>CN~T^L`m;hXlPkk2(%){BkOOzySu7AmaYJa&wL6gA?nX3K0%XsNN5d_Z#{#XyNQmQNjcd=oHykBBK+8&ReHmw6 ze4Z*<{&5+nkCv!!H8<5y&Nv}9-u4H`>{q*%w$Fd&zW*HtKar?tINB6?QM_tok-y`m zAN@hvi&S@!@Dos5oKf4BT7dEbyNFdd&$rI!0d;*`)1CaVn()2Gl0NKWTYTWIfrh$v zFvX4_j=5!Vn2xSI%!~M4WQ>Nb$N@si()S9H9u@H?pv{L&cds2m_m`+KjG;R(vd=Uh zmyt>*Zp;vR-;y1$?a-2YV%T^WAw9Pffzn79#G}70#GOU*X(9wdc5IaR5JwT{43h2} z|6a?nbFGrh0PRBx-Ywiz&}ty@erSP)8~z(Q>Pf`ynZ{BeO_CmMYg*u8GkjAI&6nGX z%yfD9etJ8=z$XClh}&HCGx;Aaz|RvUvTy+h@%0tnnUefa#{BLyb@|NBYjFg(gxt3H zVp7i<2@MG7vr)0I5u265N1=eCNZ4|inf6C_(Hu8}&dqM^#Du$in2N{;??=VzCQ3*D zWs?5=i8u5ER?w}$4Qm^VMJTcY3*~;aMLX$<7?A(23)r1KN_OFuHr}A;2-H`C_ZX$h zbuj?!eR;~g1-%#g>v<7dx@Xv$c|o$-@5U|z+6aKM5uCiN?{=V<`i?YuQy}xWjjLDfV!|+QQ`))1^mK+~h(wL4~ zTIX?_V`1#y!n^omD$-cDUd8a8lir%^&~CC+%C?;I>FrMW!xqkUm3>rZkR_~?b|JI) z7a#PS7_@v0krURyM3%csmkw!o8Sj?$Jvmh2h0*S!S#~fgCO5tUzjrFExgdPdz{}yFJL}y z(>Db_`u;x~tEkcZle3|9diXP*76g%+&u;jS8;o*(aaI{Jc@YALLmoJ_HDts!IM)AZcN~A zLT}{Bf$P~Ir!c!+fkNPqri)D?om(v5SN`;u{fM2|aKK+8j`@a*LJf|Zl*#uD{I0&q zS68`K*F8tx%28qjSh|Hi$gL0-z=MjEF1pr{f|)?E@?Us6>JcbrmD$bf)DhT=_>y^S ztKwaQnL(AOtWA~Ubg*LAq3zUG?`esNz6f!oYMX@0jgXx@V7!opZik)zX0|w8Z9^z1@w-cr${b4!iaDPI@zTRwK5**daY4kJjOM~dZi@||5JD7uGFuUS8Y ze7mL^4ca%4z7UOY&U$~c$*R8Jy7cTyw7vsM<}GS*`54IYh7~uDZZdE6xenVT{cE9L zyzE$F0E-8)1&=K#E1)?*<^bLQGS9&R1cU=eV)stk7A+cAa`)P%In;dVw!Zx5yhk4o z?~cd68%hZ0;Xda-qoa@iqObosFj52_#B}tYtU3QIL=&{bB@zknl`w(NE3!-=glz_3 zCSz@YKXv!=x)StZtP1o`WOsnTlW%v!HNNg|pZ!|5r9u=X=xzk{WWCJLxe3}=+q_8d zClB0?zl^BR%_EsoobyVa9qDc!yg0JV1h%Lh(G`Fv`uh+bz+KOq0_^C3bU_Y8YJm0` z^=?JrJB?4j_;V6gXhoJYXGgqjGOqS`>1-O!e_99gi`I)FB<-f|%-gG-#k)($OK}gb zonO&>OWuXEzO_!f9dvtwtaGu!6Sz8F0`C1<6W1oM?DtV04SMVoDUsNs8<7o6XjBjq{%OrHta%L36pjDs;q1W!8%@w%s zd2`?_`d#?EB+5R8Vdvd1@b|>8o>23fZBcM+V_;h{h9PD4S>nt1n0gBI&9sL(ldj0- z#rst(76scd@kzg8h(^kb36@Q;bxW)Dw*B2qUp2&#>JV_@_|cG*f{(1AG1V212U0C6 z4qlXU8?^5eOu0~nVBq4XD`aO+0mFvO|H<3}-}>NW^7npVrzBDSNy{r|zxM&Yx&kcT z2}XMd9HEfVY?60DiYxf2BKO<=AZ`S!D{Nmp=ohGK^2Mqu+qNU?MP@?O3XN?)PR|{m zgtPLTSEWh{RjpsJaTMsMfAM!$_BO zcb6bTN~s_)q=3>XFo<+_Nh>+z(CVPlNK1~Oprnj+4j>{*ch7&k-@V^=|FzCyd04p4 zIdAND?`J=IKk?i+aP~F!hRcV9s{)WM$d;Sk#T&*;51xLI)Ktu8vNT^1Yz1tBM{qTF z7p{%PMP3H)TmUN)cB_{gU5C~}_YGYGkkv}Oi+WcZPUn8>Z?ysM<2^x-6H&!@P%5Mw z!iyG`0TjEAB#YpAfZ|QgWWgz5<1Nz5f8OY?SKAT*0t7GSSre0&KSQ1pM~x^5DnM!l zJsEc(Fp(y%5USdnK$mV}p4&kE{Po$M$ec(VctrawoaP;u8h_k3ZMIe56H%$PmkFDP zt}5ekQ|0JyO^brFB6vo}E#6^0P9LG_M!ardRt<;R)4It9Ep-Lg2;*=C%Bk=;&&UG& z+n8W949yl+X8-Tk!gQeiq~b-zLHmC9k9e@K*?7EJ2rf;^o^)CyYE_&0oIEOD@-kwr zwj*nEHPIY%F1y|}b;OLmKpP|A+iq+bof?J_uz1+5(xWpsfj%>B%!O5M1RhKwz`u(k zsjVJGEIgZ`H3NvB&MTQPMF_xX4nI!84DBlQaW-~#*!OU@PbU$Iwb`5J!4E4O8q^JN zPiU}6jIYRU!M>->dglM;6^8It`LmUk1~_daQ67G`{fTzKk(=6)q{IS|yT6_`sc_P} zMX0^TaXe%P$_k}>jv}IDqmUumT(A{@6+0pG9+hnVSsc@AddXMCvwj~IqHW$Xfy+S1 zw7pX*LfK??ebY9t|B|ac(Z}>0ng2FlvE?YZG-JgTrp6PHjf_(9wd*>Pi=-M^Cy(Tb zEIvS6USE~^vGL+vhJhM}0+Av(nJCSdZ1a0tz*!X*&+xub+kAI4IX1G8k33t7kr6b< z&3`3+zppkIZ_0 zWJ25}M1r^$#KY1?XpEPa*`3829^|~vcl%ULJ0(AbMYMhi0t9l^ob8|-< z+umu+yKbcgkIRVKP5Axs4@P}hlW>`LGB3Mj_8USu>7Y(HfuBt{Ay`A1@Ov5(R`!6h z7P?crDO-{3e4%e{aPvx>u=3IQJbS_K`!I&g$!$K}1=KdjYG~CqK#|y&a<U-(s5>zMw;JgIjX$riF%mZ1#^Utdi{isAP`t6CptPR!ZWmj5* zI!(Gr)V(Mc*NCypC$butfPv-7=Z;kMjt8ed^qQDj69GSAc0)(brduL{mQtFj!tSCtT7rH0C?f{!_Ws%2!N;KU zkuAk+uk`*Pxl$Cz3sklTxu=PuHL84CH-x z+fY!Q4!GdInNr@U<73xcUv!X*-qi%47{7jHg~n1q z{7%stiv$FH{mo@RFN^M=st@64W5?<%^lH{SV@Qg-Y6R_S?v+-kItSk5gVul&xo`9o zyhUB{5*I$L($%JKjs#mwH>EX*dg)aWT29<`Rl+`)wUJ>q7ri*PZ`qB|ogM!)IS|D`Q_S}9 z>7Ji766M0m&t&6q4Mmc<4B~&PVHkrRx{s_L&#&t zMINGPbrq~V%wpy$pfp0{(P*d^x68*qM7Y!W7{$*Ko;YH=Lbj zqx+RJAmW;NUZN7eQh;@(0}#LuS2i$5;WVTAQPu-MxO}sF_bo^I49*|c6RGMp34JYf zk|}XL`HLbxtBG|n)#Q1pD`oW;H+98H8&enATA?MW+@yR_^~}1{>w)bj(FGnMlrR?R zIP8}wp#Flu^~rft_A9?6s9OZ*y7F>Bn@dLLdV;7igD{XN1iLPZJ9jQyYWul&rvp@+{LIb_rY+tsaft@6E}@j1{cmT}=Y429 zp!LY?L!R?tbaj)ssQu-O;I2(jAJ}BJ^97_%1&^XG%x_w`bJT!rlN4_Sme=YZ)-`w3 zffy!GMo0zOE5kJK)~3QMJ{MWfjPMnZnX5O=hF=f7kC|9ybQe2!SG63d;a09Na#Q)! z(UJt+i|%e(B+z>(R5KB{kR}z8QPwPm6FKCm`=DribgG4^OkT5xiG$*sFkQ7YJ3h0r zSz#29H9D6D!;I5a;yf>=T08#b#h?`avSIjIVdF|~?`@1bY;nCr{MwYIdj4|gNWQ(z zcZ2g>V(w(I#KxIplMUpmBIZnNdt+Iyv+nXyDNe*z9~ObfFEUg!bJcL%=$7x@DN6QL z-E$40re+#)Q7G{}tU1vRCy9LoYs&#@Z6&QC+ZyU zgu$?qFpmdhlvO9RQyeY*P1?TSnGioJ9k^Sbn>KJfXqqG>DBbPqdtaO&>G6zve_&Z{ z%(ce$Jl$LG2*S@d%n|v)ZA0ekQJ+$kh5nk?}Wf)ZeY;&tJwj3}IaO&8PnY0A!;%A<;aur{$fXvf&n*TvwQ_`^k({D`E z_uo_DmKZO!_vO0-rib$U`~~DkKo~Tk1!Mv|V(S(*E#KdNE6&_Nm7phc?~!__d} zy;6=~eMpbLx79kDkS<#VnSC_Zj|X@QIY9f zXx&7FikGq&*Sa5f-ImRK<=W3AqG)@b)tdFrkhNE6i>5_zny>JV6O1N1^P(p!;a0Z> zsA4+2C1ZbsMAZJAE|NM(K87lyX2>-6Ep%b3#_Zz?A=-tUCvlUIm(BEt>o+hOsLQqH zucpB(;v1eei(+^-r4ktdo0&bD{MdbZy2ba||Pl?M8;md=` z*qD8+b<+s1;bO%4jm!;UK0-YL|JwNls8#eLgVGHG{)~qBO&_hrIJ8ZI(ZO1 zZ@rMqu~Vjy7NAP}Y$h;(zciu%#ePeuql|Dhj!Q@wjF>ojZ^d}7#{HZM{SHmw2Zpgw z6_1;{B|*h@f`^<-`W?_SAEBeNsj`<7X>+*ggDl`mKRLhQZGTe~+sOU=l&nT<_FKEo zm}^))IWjfzR@rk1gQj_1E69SozJ`;2XA$p8x;0Dnr(NeY;{`V%VYr|7?++Ic-7bpK)+vuWq6s`Z2VROPL~t9nd0$-7$lyHL-&ulV8j{JCwb z&KOs2A(Y=7KQUCf7Ru2A%-Klfh-)#YvouzpEcKa-CzB_&-A9Ew0a{&iN#*psQ%$Tb z47X90`Qy`VsEVCuakl1m8!L~7kAD_T;{LCZth0WPo8HK%ePXAV9uQeyZam5LTLV;+ zsUB%kX%bi4Mv1&`l#l?EC+Y$)$vE!6Y6$pDl^f=ZqV~1poai1uXCcz~q@tBa2PAI- z?-{Ca7oJf8L^_wWyxp!~-B$LK4AkQ6RplVpY|TUxuIus0hmzjt82j1pO)A;G3|=Zq zuYcD2J|DdGu+Rj5;zbZa^@!kVIWIYw zJtmmVF`4n;dD#oUR=tU$`11B9?a9>96`~XWB5PO!P01DBT$mywlJ5QntO>AQEHIT# zHZJzfW<)%93xna&+jtc+NjNu8WrJsrz})6i>vx{2o>cUaPgJIv{`P@2`FJ@J(xw zujTL*@pKi^|H_C9#yVr2VU*Vib_)|iM$BS%FY&Q}Ow~1imxotsn8nDT!~`60b{TWe z9P?nhYVJAQ%(cRVmVO_ZM291qgzMI5QV8FG+khGz|L=G&EhpVpecr!)k%NLJlHK?m?i9nb;+M5A``@_*>cjp7@2H;4&$Goa zK%h=qssiZWVOsT$VzyX&h8j@VwtY!|?10WAM^Yz;P}@ByWNy*HFraN*aj%kmQc-MC z1AHBKQ05WDZ<%-EBtu7!m0&868<__+>QzRwssoQgyC_f*94zYs&gJH_41D7r9(77P zX(%?=Voc&C1!P#PF{_x1Ri3}J@biFoN*HBJf}DQ1jvUp4Z}0U92d$pWQh<#`_uULw zw%EDpcGhsi;CbTvf!^AKG$$U84OAi$Beiz|QeI17^P7k>}AnPjGtT zqj;_4t(vGRHBFvY8A30T8wV9tW#QDDR^>E;H>~|~hsi28-W^|8?*L)Gq zvP0A}FwuT(QOyR}LEDr~VWg3$pag23f#$alBcMCxtCuN_SG^}aylzCI+G>e_!qqyr z53Q%JWAR9oBkyH&df|*a59>krH63D0YwOG)cA*rC3K|2f3Ehec+Fh;pHNgm#UNhyi z`xDdVu+W>LvPs(}#;pPP6FmL956&qF%1dL0Ik!eYU5^i@0U==A6N+FJyoDQ=HLx>x zd3vg0^rYqt$B7?}AI|ptargU;cNiJ6sfKh%^wD*g3!Y83H&lUUwana$geO}uq{#EW zd#%x?>9)wes+{k}U;@Q8{mgB@Dt@2Ku_KiM`DSLXk@j)~)pGtwb*(oKMBS^zqWNbq zmFGj2zJH-w^Kmnj?JUP>Qbf7m{O7UXw607aEx~Wj7AAkyMU1BGu}pP5Ji9_HL?mpU zEjvAgliR8QC9??#dqG4tSnr)uEu;<#dQR0lsvu1INi#1^qKPCIxpdgd@$S;!t$;W& zb~V6F#rk(XOJG^+XAx)iS#jT`o!(no=JS0CGkp))n>!o?dgWPL-l#Q7&m7@hIh_yI zDY2*fhb6|{RK<*;rJHiZ07lS?Yt7fh_xHvQ<_k4fRbmpp;;J_TguN*t+7EveYb0=QtXz!1mb~m>Nmr`&Wyh zF(<`7$4B4)gW$AgR4YE$Jc}e^d^`ypu;~EPm=~sQ)c?}sTju#ECTuH3%052T+mF3RoZXy@$oIM^4fpy78uKmI!^zS! zOjkTu@a*qq=+SR9L1U9sf@Z6XkY8jDH}_8jJNn3;EVbWt0;efn{>@PfnepCbs3v7; zJ==*(Qqq#snWUQuO8^s@4ae&|O&&3rhZ(S3a=*NBV$@OTgE$~)JG#SP)Vp1!QJAOI zdL@6he4-w^*FMcwJT!9lv+a_WF=LzIe@1JM{Bq{++jVFY0icU`8(@4K0BVyt2el}8 zihMjxDW7{)yZ^fMYB1w02VLKbp2Qifo0pV?z)r@pWhSpZoqe8HdwtSo-z5FY-a7!= z|0h-m_|K>TIdfs9JZcln9W}8PzhLhohryD}?=3{8F>l>2)pZ@Lu_i#Rw&Qqkeiw)k zmN$PSa;OK`U!a?0%F;9?!u>AB7k#G2wioZVXtQqd>}}%}ou^;Nwf_g4O8)rYvt+;N zIY$|MH?XyvJwCv)eqoG6okrb3v)vYftR5t7&`M0$g$Q~w)Ebhe7vt6A0H>I?7BX zXLjXlUu-tId1yI2oJJjxb4%WHeGe!v@^42bO{s)*&&BQk;R3i5HvN>YLX1)njxP?Yp>s;N z#b(82fB(PH>$U9NcESJqc|dQvlaJ6PiCG)z^=1W1*2PYDZFOf&d>vB$H+oETf2wZ&+<$2qIEmSf5Vn27U4Bvi$f5VB zFDBh-c`uK-g;FlS7kb68Vwg1@nRs%cTSue!p11Yuz5=S4zAlcY`% zL-wvsny;#t=-aK3NEBp-DMAUWACn%gz@4ue{VI~}`COpdX)58f8#UTzc8&$Bd{#C| zSL96s)pX5xl(5#a101Sh-r}H(Zi@9p!Baa(I>oPF#@B{DuyrGXVK+$6su@Ol~Pm$ zSR8LeyR|_M2C^i1Fmn8-o%pmh%T!y{?!S=xwm+!XUyJrTDUhbQVzIk@e(zP!QBISJ zz?0}=aJ$A$sY80i>$HYK6dRF7j4t0Mr}NdbDS1S-;AR^&!N^L8(Fi*lXiS@uN>5;Br44iBS9O3w8h1VPer zrV(VZNr|Tx>iIaM6Z|o#-S6HATO#J#^Ra_s+7^&0d+xjBl?{E%VgO5Zv*lhk2TKTf zR&K8U_F;H+$%Wo4^)Ts<0(IYc(&#M;1^*temiG&{_<>CKEHHmV{YjbJPL2cAuE)5? z(t0dXJU+Y{R=<)@BFA*%$W$L3nz;!ZI6q7vx&+_Li6vGIiY~@ext0xZt;h?EzY|_J zQ=fPj=I*RODEIX!scEFP%4hy(`UM3nX@rq)dw$-JhzHnW%F-WtQLA6+mCyc$m^4Fy3hTdS2KebqYK8|yQ-AKuydhsjsr?jeAy^$-c*(r) z)cj{qw;=CJhY#K8i+l0vV|(W4aP+g7rBLx%hQpUBN*_L;nO83dV!&Ia{N5E178;>J zt`wX`)AnW%UB+kuWx^PaJDlaZ^V~My%LQ>>G9;9GZOAGnLqA}L%&Y2guSU#=2CDa6 zq@L6~IV{t~nrjg@3O<*wlY+cEdX8+dV_M%_$YiN&2rS*s6S+ei9lHiZwt?z4Djw$4 z-#X;&Hs5s}6yN@qRKpZUvGA6C7VFz_Huv~^(QVLXd?i}_S=eli^sQ%H zp=<-YbwR-o{ur(pG$VPN_P> zXNcm$6qA82e=zJZJ1$C6gE=}T^{SeGX=sd1Xo_LU^j2_zM5Hy`sx@^35?cR^>$>rO z&ziD5sUGq#539L%JY&Q`xa_*0|2No6cHijP{tC0jw-~|boi2CQ zdLFX!_F{cZsMz-f@frdnzx`c-SK{^5>YK(%2eU$Jy%N~UGt`cHf!d(kEi0(xO4lS72;0#^l9BT@F4WKOsq_YW(fQqebAViAsIb&hY_Ul4)Q{WBOJ} ziF6Gdq8)sIn^xHN6e+Ku>{7X-_JB5o!9oak7crl&P)~irHoz+jEPizoNEzP9Lc~Z<^;Eyc-!_CC1Qj-Uy38bkLa!0 z{Pvzo{Z8Jo-n9wI`rYI-k+sE^UG#5s^of#q^CG((vcH$%Ug3LB`=>eO57tR8R1K-_ z*@pijBWVTO)~(6L%<4KjP`Qboj+Sz#hB6yxGvx z5iIb;MYt5Y_3q-H3n}$AzHB@KSyPw(pJ`YAPt@k`?XF$1V-bea#4X(?BQ4Y?i9%Gu zq@)qXufJCtH;WWeyvRXbDr^FjulElXwo-44+d`q|@6DBn&9^5Z={0o^;xh_wV{wn zP&}9rdwejr(W2_rld;cl@cQYyz=Oz7LihSL`*9IV&hRE@G}^ue6|gHvr*HCBk~y$v zut>{ot=EHcg@E1#tc|+*LD&uY@0#L#Ob>tT2L5|lHQh0c+lUu=`YbGq_Kpum?w&0$ zR>Lo0OkIT4LZOnb2|Z&l&hEZ#Bg$T#mnfijk&o=(l=S~kyj z$S;G}E@(^@8k?2bVI_uwSNf5Dyj7fl0Hh0c)prhH%xbNjve-J#1p*zqo>$h83zdez z2rT09CSkuUS1fCC8iIb=``O|%zZjIMH#q4~QMgAAI$_y~LRt}SkQSJtZlyQK6;<07 zD+;4gkKj1T`mU_u7i^w9MdnL@MlwLN_&O$r#z)AcHN>IL`G#f^t~g}sf!u(&B3~aV ze4-|*=YLz#wl0wf^!Ji#M*UP_J?8D8ajXm)G2`<6&frai@R#k@eMi|iMds-F}&I3zAI zVz&e@P!+cYqrwF6I)*lQV6%7;_p<63rK=iR#Su#qL|@EDf;D- zeCN?w1bj~LC6AxFhqz`d$h7pXP3ltFHFV#{B=keL4EJUT+lf>KPV$iawl{LI-22}< zmshZqflQLOgTPn1UY^+ucNYjyR+*pE+>sbhD~c+*M>IgP$`+OWCFHF+OFpD8f0|&3 z`}>1uDCsDX!Ae8DDPYah^Q{_pGW~oeqPK;AW2A>uK!4D>CE!L&j*~w0yfvyxV`myQ7!&&8Ks6f=D+B#KdjFC>ZS6jm^Wu0?oP6A) zJ3K<$>g1we5@@4EbL693TZwd=f8Zt~i=fBTb6OURF3y|&k}T)Vs3r8*ugy9-YM}od1G#!P z>vzY3J{ni-->7{!ph=r4M>1k_N$?fFMIR8wzGFQ7EI@WHTAt{&pE{QPNbL0mp+tQY zug4)A&bakZW!x5Cyv%ix|12F{Y;Jf;X$ueAk+}SyeUuodCIA+;j;!VkvR|u`Ww6qt zyq=dGPbSsNxq=(&c=z}K1FY27L@)&E-L>pE32;M>=)eWOt=+h%$% zQN0l%GuzBlE0rdGi^ARi%b!ix>q+Lx4k*XIy?bgEC>%|=lXgnOM65HEI~{=VC$!E! zNS%Yq#KQ6k0~OsWv@#=s|MIWvwcTF^Z=C=dLL5kZ+tA5!H=+n>mH#lG;inVaq~U48 zpYO-#ZG=z|ru5LAXZ_ls0J=sw!0pZNx6^+bTu48-S<9cc_G*Eyh39$Fjy?=0U2kD- z`ME@wYn>6xS;DqM;`tUZ_GP4B8T7@$5)?nP@4hGe-=JQI?#B>dL=aa=_ zip_+J2y^cl9v_%hf5ImNUbp{(ehP1j=;WPNq0&zKkcAeIG%PQiFtc?&61Xm<)l?QU6gwuiUDGb82dID z+?P2TD&QNA6i)=ahIn~T)4V2-kmUc(v)+FmS!fca z^qd^Z5*1=hKWhVHj$6xer-DRgzAR}&&S!1r_d7 zX(-{vw?XB%UMXx*JdvwA4OGBfE0t~7Vvj_hO)R5>;r^;KTT!WZB26MiFpQ!z))b5` z@MxC<6@5g6^u>HjJyNNtACL#v6|zrjApQz@Oh`s>L%M#c%vH};9vX7PPKe8(l4fMG?*5@U++VxASx91d zu;?vjIPtau^xR^`8p4>zg6A|ctFdkw=irFv-<=%Og?FRI5i8;xfMtT7YhpHTPh#Y7 zql4C;f7OtMrbp;!^#%>S%TD!yp5MiUuD6Qi9~}#k(eYK0ZzM0SwGD23*kA?JXoVJ> zc&kW#1<9EBF7Z>}Laua5w~i9koDb3BU?UO8}ZHqWx{`Uz}E(y3es11 zt~XG7%Mj|}hYPHKY%rbtr3sLZqo(}@u(w0O)l&gUsLi@fH!n(ztcBr&Un1}JF7Y8d zu>-1u8-dVSwic=>fr@%U36)v|lFbg@w)ET*qUCl4ZS-nK7TUs9jiwdQduALVc({)Y zccM9SWdwg@;h^C zbGFi(aG7z(kWa6h$EH0abLb8B*$r{ zBrLj%Ly4#Cr<0522Q9-hC8GA?Gb@lO-?+kcIU-rZK=LX6j#tLZqSzHFh8m5$if?Vl zHjxawnu3$C8Huc+{26OvS=w7Ew;&0mo{;#flNodb-?%rm9C(VW5D+iYbMC~KWBrL7 zzf}3vm2-5hQ@3s-#b&YKcjR-I16|>W;X(D~6_+=au1>ZP5KMbXz1Bm(jG-@U3qOM3 zjNj4!gWgGFAUh+TqM$Q)PU5wSJ1g|oCGKXp*!i0g1iA@bIesliiUnw}LUl#9LCTu_ z%!K=%AMDwv#TRZw*37Axd#<YZ-Jv% z?(JL8QumjS=O&s-X*-B~Y{ zC9VUgL3UX(5+gmO>~hR~p-fkxHy_$a;qGcx(6@oUL{C3-7(|lmml^`>2fwB;+ADYb zT4HzfUMS+U)j{GW6~efu@3YmI((C}%e(Tc%HxAp_0~`UG?o()X3NB0iQ&bumyUC_yh8@(M&aJ;Lu5Zwm+!3~Cz%7k`N}A$lfd6ah$%l2(CJ!-Qn#>})@R4N_Bx?uhXgGo z=s2C}EbWfScS14a3-0h(@2y*~SDvds&e2`@C9}T=U0YB9So_K;w(fmYW28bx_s&gW zmNy)!A+Z*>iVHor_ZjxI5XNYwZzfQv_TdeQdTqlj?YAQtaR0Dd{uY++r)r`)1FFXY z5{FyThnGq(Ex`J@W_*szDd=^$v7jB!tZeD~db`3Q-86nGUe^sp*VTpN3W)wP$=4{j zF(c{s$z?Qx;cBa;u6+i8r95+yN@k@Ow_#3rKA?z?bXoGp`O|>*fl5m27Q79-{i#817HLQ;lkjoUGd}pfv2L zLg>s7ZuBury2WV3OxM-VL7J_2V)ay+u?wS_{Pnzw?-;0bg$sQ@Acoz|99`p!Z$~1ioX7EOi6r{SvI>wi+ zUZ#H~lm%-AofXQmxjS$9F5t=j#)Bh>yTi`?iSGs{iu)mR2}{!m%TEOdWIJTaace!r zWk}{u+K1DY7=HLsF^QvUy;qZ5`1UU*(bwl=EOIyJ-{gN!=cX9xwdMQKS7YOGF}E)h z@FAH-_>zB-K$alvJ|^IVvFtF+Q=-;}s^d0>Y5mw)*U&ezzU&c}`k%%6jp|PfAjR~h ze)T#(MUSHF)~dIj%jbu-@EUD%I!X>9+azR%S^0k89kXXRp@)LdN(W7S z43|!&?n{AB5&eS;I$G$}9r>%xUQzXC$H5I#?9>;8k;+EhI7?beagfU&17%V(+ZBhxIIl=Dvm+{{4-9ZL_jfreBsh%N3hl+)=QcF_{jQcB6(a5UUhl{ zh4NZEDcO+71E#grT?Gn#AMn;`(ZG%h_Pb%1ww5`KTwEe~zR%ui|BfJW;oIj#l4W!F z1vW!%9Q=b;A|P24L1p5IIDYBmku~%vg1xV}bjfV`xP?orLxyh%@OXsCLKb?-%geva z^L@Dtd{-kCcMI>g1C`94U!S;_YLNzWgw{VHiVnqJSe#KE-?*wxQKe|Z6>shJtxxj7 zb*1HZti~`x6;R^AXW~+_OwL}b26H~&qblD*i=cJ%o1PvsyC>4sxy<}RI1Y4&uY2*` zbil!#4b`|*#Qp{?W|6;U270x3WvtoN8@QynFQ10Ugc_Xxe(fqnlowf@+5VX26umX|Ef>>-<2<>R1`-AM)Wlt?XwGBh)_PjVUW;U`m+Zca7 zjh6uo3oUejE;a|&di{8(qxNoo@@CuMTFc!%QAJ@?E>Vz29*@Y-ML?|RO1zqUA%C0YqdCQos* z{$hUL8~gZTelOH=z0l};p^b6|WoUtA3JYjM?F)#r@eqZS7QP#cJj_{BR-rM~!$_mk zzhLb`EKdVzJfES=B%_m}dD)((4xPIQF8eg~WgY8lw|*P6t~B%j|LShaK{Ci%pW~-4 zNKzrPd$VSLJEpVGtn^C#=4bNnHloQql{=(#|GZ}%dn==REl}=q|MQQcgV0dUGS)=U zh3vcl+NdQ8ZGEzx_Rg$OYb7+w*OD(r{ zL7B9G^wa#EwXhKqM++Ep%1A{GUfABv1dBT_|NLJBfrjQUbH%6nB(p>7Qn5DK(OS{f z?cPXLS(@YS*G%2JO@f!~wN77LHdI5Ss~o+>4N7NBFunwgLw!Ai#JT zWUpjv42x}^*aMoCgiF>}2;6E-dDmj{NHtE=h?LEfZ+<6EnBWd6RHd=&cm7iVIC>%- zt3SNG)Bbgl4?kddLTK(N`{csYO*J`d!S6^oODtML#a!TcPajwOR3y*@T!io~Muz2< z7evOJbC`)>jH)_aJeAoC9RxjX_`ivv#r84@k5~G8mA@!lKAv+42*alH{!WF(J=_iG z%X;FMCxn~Cm+9~RsbP38?jJ4yW^<}zM^b-*?5wSA?&g~2Sq$_PXACV9r67@4CVy{e?u5BXsAt8&b;()E^lN^`3T*$=tv zA?c<0Z*LCAWBbpwl3onU5rDY-hZ8^lR4`Um>%` zE80+(&-Z@_FsIwJO|+#brk*sS@!?16jWUMJG2%O!4`RXSWAY*0Z`H}@~?Y;1k3b(qE_q4hOQY2k} zCwaF)w%&&Ku;-P}+*6kC50cLu;3`_d#K(JGK*~ZGe$*wDCjSpK#s8mqe{z*1evMAv zG6LQ4@O8*4j&}#YrO(KJUgi^n5X>>zEVC1@#Rvn1AKfLP3BJBlg6vpKyN=w$X<#XX ziU1_}wJzd#eH8uUQ|I^HAP-|FAKR}E!LRY}NNgGnX`*+&o_ArN{SpE3`h8M$6ek=M zSr5kc9#D)Cn($H*RO<@eOVK51Q{5e7b;?md_>xqsg;P>;-T1Ze>Iu_LQ)BCj?YQA{ zX2p2_7uXA>BK@m-bC4h-#a5C%#a{y}cEdTK1)+PwCn^0wXdkmw^x`f%-c?a%cuwy0 zK+EKLC%OW$@Nw;UemC^sc$t093ggFt&uYNs4S`Kqc$MOEU_UhKB(Maz$gsR$*){ut z*pu(49imstXR#=^NT0!tIN!NuSnqGo*kcg1A~XD#0nj?4c}b|!m@n2dr$Nkt03L|EwiEC#y+zNtmEcc(rB27;V_8F@q*#*~Q zeN!~>WV2_KuAda6RPv^E5%jQ0J0QbYI`#wZjQb7Cj`h+%uQ$p!(KaVBX+Mr3?q9Hv z>O@>cv#612Prhb8eLu;(Hn3#9-GzUv^rl}a^02ROM;bBlNeLH!-zm+=rC>1`*U8H1 z465E)q)C10#iU%l-Ahi^geJe`Ek6W!e|uSd4xiq0TJ;(2-t4@6E7jup^)tG+<6AbK zpU$Q#E6uyQx@$hol)iOu{4Vz9cCD1&g7C3`vux;=8D0c^03=1So+_~asWqahZ*4eP z_)D&r;!cU;CmR7k( zL~2^$6eJz3ZVTt(+a#RJR?LQfV1Vt#zW0e5-^FhhklaoY8Qho{8?HwLFTZeD>|;Qy z^z1LuC-pL{s5_jez({)|@WUw&2(K~@N83zMGJ4~f<(JSqK1*5b7s z2|}|RPUV?6U9X8IYpezfj4MQ+*{w(5HD&lZ#`?6gnAisNC4<=Uw+8zuKNyA6UC0(% zd{}B(B1F@S1-TVRhm|g4`eSW=Uu>@PX!NqUhJkK=5D|m);k8EArWXCRDoc9b?XCCk> z^SgrpcY-VHRVLeWky6swy)cxEsa-+D^EZ+w*SoT9uw62`o<(iRbL#6JO=@ zN2z6cBQiuG1$JNi;*Q4Ja|~UeRVyJ$!b4_w>zR>Pf)?*j;g# zc;_9E;63n_x5vo4AvYE10%gDKwkqoOQkHFSDLzqEGJFu@616|Lu}LBc4vk?^`CgFO z7@$C-;WSg+8X`*@q28sxb^y7uxDNfzv(Bc-*X;#AibDPNj7G3RC?x7 z#86JQcNaQ=oZN0f*+YAh*Rd5VL$1+qDsN#vF}SrITzbFdbt~!0I&Cjr7?e_kR}8j_ zKguvvx$x3|@B1R?q`W;)(Aim0{PBmAu}LD>bG(WNKUe6W=Pg{P0CIOLt$}&#y&Q93 zc{W0R+~zut;-oq%_|?vFnI>2QsoBbS>`h=IsYq7v819k%ODr)&Hphph%NFh;(^m39 zDpm2pg%jEhKJkkDvyU{p<$PhEnkxw0DPkAkqB^{dGXTib;!!X)}^eVlG)KH~MM}Z(6r1v0KL8XQos!H!j?}RH-11P-{DIzuW zPI&R&?|$!lW4tpMjKPm^&d%Ov@442RbIt82-cL70WQA&L;f8jw6${bLCoZ-yMct8= zHWa!?b++x_9T}gCLkI(Iy|!)XLgPlzE%#aH*)aDo1E1saDN&v95Ab1_L>iL9mHAyH z{sRP1@8$EtslUAsbW!Ntk@ZvYUXPe{R9Mwoft$%NiHU~Oi`%pWZ=o6b2I^3;dW5SI zqly6?G#pW9I*?{1Xah-6C4BeajsMKA6a3$stBm52FkC=0kkOw+L9$lsZ$=1y;BIUi zrYOFRLkA8jS;D4SbeNMwmwCi}ma|UO+nL=raAtVohM4AP(wOE^r0oH8Bc2%ZbF~$u zr!gzbr$`VWp5pebB=-N_&UW*2s0$fBV){O+;Y?!rfe$K?DE@HGhsfqC2QS15iDM$a z%0*JR(LBeGmH;jUmq%}#L31UIq*ckL>C;VUFj#<={ahsQCy(1(5VI#Jx&skr2eWBx zi&kQMet(Z!ESTZ30hO%>Mh037Dk4|_&+7kge1V5l=-|0x82$~}p(J+@2yZdKXF~1{r$r9jqmvV*?Us_Ob=Snos97g^1`w`4fw;p$Kd@f74&9dv-Uy z1nEFpc$ZUvEDL{1`&~1f5j8RV24!(OwVT}iZx{UMeSHc3pW>r_lcc4tw2e=J%+TBX zX3ln_*~XZB_1c|bgnOE}8Uo6|zJX3&WK(nxg&^#J1=8`y>-@(bW^;B*!i zskWQ!JU6+7!;fki-!Gt;VSX+LSK+UDv@_XDKIB(!h-szNs3v{VwVTc4bEzuJ4`eLv zMCMD6-t0gGQWbV;WSC3q(*}~={N1%X&90Ho*>)|&-f1Vk{Da>gvs!53U0~j}Rp!(4 zwUG!KZCH=L4E|vho`}~dJ+jmsMU=ED`?xOupca0BK-$3u zI*}fdwd-hK5ssYW_{|i9mF4Oc;niqrO)ByFmR9qI5iy3O$=neR_MI=9%sL z5&m1R8+u~SLPQl6^ybOs9`fWyhLOoBFUb8MdRF^pE$codP*CgBND&X>bum>~m|e{^ z-UQ;=r(F{iJT*o1rAu+g!Oh?0FXfKIsU$RcmH=3M!Qm0+9<;OS=?Rzc5&AV zfRgs22-C53H_VXpdt)dcppig~+u=wS^%z588=W6$FcA*$fY2)@`-DxRX;AJZ?E(?; zH9@B1GW$o1$InY|Oc1_>MiNo^Q4!BKTIQ3pd*w9~=|-2HPuwqh1*+KE>tksJra6A& zCQvU3Lih*?OZ6X`$>e^{rh&+t8~lwWZcE#wLL6xuz}&M>D714;Bd#O1N?Ij70IVrk zC!%wIB89KLs3=63kdt(X<^9u5W6YJ&4a`=Ee4f$$tK&wZg;o|ZfursyJ9eim^7^mJ0}|jm_nkDdHwJzaf>N%XY^!0 zAUUlO-ZM6#pUABRy1bsOGY>$Ns@WBOlChdAWlN_}_4*^99-#0kQOoCSO_ zT0Z;;WrheUR4pxnrwwgq)21~L!z8|=;~v%OpgyQXXk0Jbe3nw9ODV%{5didB~(V|5)IflEa$!ivJT9?HFOB!(r{$y83u zeMhUANcF~TFvaU)U1|xMqfXE>Cot5j$7!4+?;qck?^d2&FFu@;6!P>gRSa&Sl|{~g zHdri4vm9Yo=xqbBIrg1gssPfaN%ULeRw?L42u-zj3wJO7$Zfg2dkjO(fb%k{BVw?~Bhc=9ctlyZ7tv5q6D#%R3_o?`lK6N4P`hashPd zW?BryLsZ-Fk%g~t-#uw(smf{o-+-%c=(mj@U5EP3nh>`w&pQi|6oRIrwV9B1g6){j zrTFfYc)dovAAp4e;hr3B+ehzG28ge^PyJ~R4~)l)uaWXge}z&J(h6e5#gdMgD>+q1 zOHum)-Jg-Ab-uweQH*8DtdT{YEmCeH6y!q}$GB0oIX+$yr2l&+R$f7RH)9;NLx# zzkN&2Kw%o)qZyQW`?QLn-Sf>}1jYCqdB7w(2O4@+6mg+SSea{h9gpu4phn;O^Kj*? zE?8Zz;9Dv}CN*{vy=@0Ig&^Hi>jE~hi1D6}N67mfK%8KS^#$^N;3pDK!#8#<%Zc}e zYxN+p-6{QReRhrnprP%Cx^@~*3)sgHZxcLwJ4oyja=gT7nz3$;3s3bS4jUUD%0ttRG>yz{VUGV(YV}EFb!3WCo_S=&sn$ z#ZUn^%RQr$nad|VHF^Q70%&Q@hn3Zr z>@FULP*p-WeFU9z_S4%73M4EMc??A$Do&w2^#}!+1h0IpH*)5tlxd2TDlpvT(OO6T z#9p5+p9yajY6qo{um-UZSBliKmsHSrRjua1I}nuU&%FFX8+YZ}&i$HxC@IUm9*G@+ znhO}lq?$3ttNnP!(i8i`I_>Bd%kz&p2G%(??UJ6lJmyoB0S`|)mo;&hymdGHo=>?f zZd|XlDX9oL*|mC!Y++PC**ElvWK!eKGDcNs3$C&?$S`PaxlASqYj50Ee&n&l;bRTR!F`k4}8 zhL<0!NIbtrU3!7Od@?SL>stS=mMGWN3JH|xI{e$i1vUbkpzQ6e9TxKI^KKQ28N{Md1He8OStI*Zen`sZ^d2W9sdtY*~m2eu=m$FBP zA!eBSd1@=++}RlO>EhY>g8;!}!@jEx`#wCM^WWf0_}jm4{A;BA8=*>KdY)V-NL5BT`Lj3~^yRSvbc4qeSQ$-R8|(c_v9ssYXjYud|0{y&Xc)laf)DzwCnEzIZD$ zn0#ZAVK(#-STdpq=Q9X6$3g^>pR`haJsdc#@|?EC@XEdJbwij4y(w2DH66E^NoazY z^jzz}GZ#>LGNtH%7VvO7c0ZjoJkt-0ih)P6yAMuclI zykQiVBV%)d$~{qPL_GiYv*~W*gUA)gj^U^Cxe;@2TtN9iya7Jj2cPNqtCc| z2$P<}{t@z{PaUVY5)?Pg&u!y74i%)$^c)mYe)Ya(obm%kKja`R7vaO~$rr{vFdp=_ zD0ysO#72TEs0)2k>I2VT+xI$`70Vp=GV>I~wXW-mf&gM$+)hOEXCLLmbQDT{=!Rcq z99KM*VCb~bgEXK1yk9+`f~M$mR~a1Qa7xa@a; zHw2+&TISlLvjNt7&r4jPmi;Yy2KSTd8{g(rjCr~Ibh_J-b6*Kxe|DDBzMw76v?f3mTs4$xQxvao4jSC&k$nVT&HZtx& zsBDo-GkNvxy_Ebljm2FU*ZfnTFXE@5d*s}de^YS7s=PYdIo%R3o&n?igv-rC51Jf8)S=&y&J45!r4n|_R&)o4lYUy-W0W%-Ks>(ZK|o}H*o6#bjv9@g8I1`pWs>!?Wd9g7pa z>Gss2cm-TtzBj}zabTC|B<*O+2TP@Ox%nJMl0K84Z(n?orF+{c8#2#V8Fs^e zw_o^o%im`8@Z!N28@JlveByljqI=pG;kS59gAU-kANbI7E9_hGT{LZa%Pbh?J;ILqs-a#>;8~+HQAvB_QuM;x#nhz2TDl#Vhc5{nm76<*v zT!{{2OYtR+Be?zMM*b{#wI|>x@(TcVl93x8O;^QW&ntW$k!2jCN0|qsLjjlG$TmiT#K%+$^d|Co;9RiRjE#h*sAG;HiI& zjwVfl%mxdu%i!M-F`zw>3!o={d&`=bqYU>CBW7jghMJSaGwJ_QL|LHdoMb!wKoDl+ z1#tR)Q>@Gze=1u&3@-nv5czX=l;N#}j`(0u_@ml)qrvGjH>1y_sZUSB?@~F$BNrZS zG~y`^UwgAr1smTJwVB>5D~Ghv8il+qlP^N3(XQu+5VJ}OIbJS8=sht#f>y#IKg5AoIse3H?jU{3{{0Ex-8#2Rb4WWxzj`vq~1TK;o8+ba{lrD+D{G4{f~S& zrjEpHb$2;o&K;1R`e;;(S2cGvSRUCwr%j;A13IqT-5+D$bu!w``W;XnEZ5&g*HIhHq_daAeK{hWb< z9%&Nc#Jdu;lFs8EQGEAJG+Ham^W|>8hN}AV0NllDS==7yfINv#-xqkE4=rFd&#)b$ z9_eO}h}Kq5e3^D9I^&SB9s>=TWO%d4b>T0|M~q^!h3_t&5t>fBn~T15do?O$QTyaa zJzkqde<@Fd_i1btSh_sQKGfr)T)!c6FBemFBIFc^P_O@O!ak~8n<#g|r)nMW11;#m zBmMg0BaJ2Rs%2`E{~y84+arN7j(@ZhA1Ux%KjX{w!`RKDrx}jJx@r82OnDR=dcI&W z?0CqOt_FSoW|v}|J~m2Rp;Gm)+pq8n5+@JPAwC(~QZO3N2F>==>mJ^y`kB+IBrG6G zd1j}@d($QVYhRp4pi2m4?PdnF>_K-Bo;dw-hxN9fW*VPUC6HTNeEof_UidmVca(-{ z)b?AyqdTTA)d&a5A9qd}EyEK(|2^WhAN{MHp+K~NGEE=0%-~}dYpw8tgZY3Qe9gL? z;7?xj5%hVdBp|0E;jmS{TDDqkc7nC(%ag_Jl2{A$wh7+wa77IeE>e4_c`W!%ncd^r zY69hJCmONV!g`07?&xw;yl96Os{gc9?Fo`rxHi15f!qx!7EB%RrGD+dHOiLGfc!6` zuh8rLgfM{WmJBzod zF7X-Awf()D_{cFnf}Gr#9u9SjJ-+F~+g&*MDYa;u&>(PYq8FWAoie_)yIbK3xuXO1vR(ahP)f zwgSVuI_G`?b`yM_^YzizvEzk2euR_+L4Xywx8c5%lg&OoC3^byi$62>zdt$}e~ua3 zmaq6AkbxqGgjj3S9VV2r1BhyaP}yQnSZcYNU;g7x*()eLNyV9awd#*AZc zw(ru$tREQV+7bt*2o%I?pBG3pf>_?y-BJ>EV=E!~PD4ep$Qm$=E`QR#1jt;$#y4ip zTng|wa!eCEn?t_^Xvk2X)%dD92XWT-D&w$ovo(Z>x}hl_LDj?G!(sDMybxBHkqo>p4U>KAHt~+Rt%}bvVUd!yAXTlU$cHLaYVF zg!XhlXwcL-Ar8VxY$I!)v%23pe~WBiB)n##;LnzbBA`Rg^cf(35=Wh;#9h+}e}4V* zCm8hz)?fw-Z6sje#EbW)<%?&7&7}+*~QzTwqwu&09=F z{27~8&ajlv-1o0;IZ22KIet3oLcXc;IN)7h^`SgD;Tdr;$t0&TS8 zxfXmN$Bda&L_^nl)TzOYHA)_K5;`krlf+n4$4&;S&6xREzN5461=_oZ7Y9?M)bUj- zu*9y0+KTV_V}v)0xC6(~g6^0M<_w8mf~m}zL4*V#2s4GdJlen)={0AGrrDSeMZ;`* zOYK0h9Wot?*!GZ`}@pNpTK!xW+3+=n8jK@e4Mu zu07m2Tt&1+n)um6t0^tAyq59d#U>y&6n645b_?G|s0Qhl)R3lkFibG-3KMd4+a)ar z#()_Ip~JrD?bPxGdARz}HW@TKVr(B9sx{^DWWgxh_saUlNN3W>gA~&^BZlvi{YZ?F z!^y-}QmmCXB_(&Pbi^j;gq3KRs0HM`QsSim%pq_mp&Z#A8pao7Pn2eJn14TqnHKIy z@7;QG_;ckFk*r%V*W7)`{(3&Gzu?sYkSKx5)2{btVO~WH(TpT9sX-4+WL~X;+DZDH541CZ5n;b*?5x9RHDZ<>b zB@vV5pP2c9o)oA*b>Q7{f{|c8B$5;!1V`*>iEb0h!C)L*H%ItduJZlEfiJKVM_bi- zOmXjDw>!?l>8n2=nQdX}88a3FLe7zGag5S5Oo$Vm9rVMJy!pAr&v!mkDcx=DH69re|QiZV~9PMAGN& z=`0F#Cp@Rm$ce)aRoXAB4_Tv>Qr5itrV9L6a(_%DA?kR}11l-2n~g{7)=sgh>sE)} zHJf)=o7SW1&a#%=$p0k z>w*)&Ur=_s-vR?iiSWjkg3+i11S;kFn{X~$kJNPj941%+s0$fCC1UuE3lq) z<6)&5H@=+!r>1U%&Jsx_dI1Y9;PsnDZ@+XD#84_GkaI0&fg+maz?8gmbQ~auG|4YB zOX}U32zQdo{1smlx4Ao_cY@#K&-4LK;JR^*^z^rw$ zk1)E<(KNAvDFt>qG>NGhV+j@EOiGJMgmD!SN#Nz~nvf@M%24w&2H}+aZ{X!G11puW z(TXYht0O?I!*z|Ot$ z=}e?yu7TU{VksXwSz|P87Y34zEfT9HQc-Rx3pUZw_c*gvxM<1&X(dO2YCVl^(B$CkkR1j7OI;lIN}X0tCqCOS%sUpjN%WtqT&og*7ul<+%xk6Y&A)DAZx*ap zYBn=kz&@(^YfH8QyVlJkIokMfg<|M1f{b(L8G@ljwx@1Yr$-hrpws`w7?2DJNP`TP zWXvRQQHlZ#YDJ}A9V>|zUzO)`n9mnQ!95VbYu|p%SHIOGB0#cA!MA?fpTAazZZ6H| zM_`vg`gD3i^0?>7`z4<(=H>s{T(2{L2z2fD+HI9)}6A1yXwY6og!R+Hym+(rj&& zA?LOxqDr45qaRq2ey3y~eBU{_QLB>&XVti1I+s5-;l5lTDF-{{4fJ6%R5u>1wq=$N z8!VlgkAAJxN7fXOeT`t23DlY7Q17}aIBHD{>`NTCA`XTeb0o3C*p}8=^i#jtB0W#rcqk(1-;vcwm1DSXolHA2#C;2-G#cXNm)c ze5sMUJ#8Tk`J2W5g_2|H^Z9jE`-yk5Ez_N{rwFKKHg9gxzCzJjU@j38D>ap#ZEIE1 zgkFbnV;Jv2-~^&r@zaM(*qXdWikGoeF&U1EFg2x42`Z6MShGZug1JGju9vl9AN;#R zv3L;y#9ZtpFe=dOg}SWUk4J|Deh;>-79ag+pLpze`lhwX=E_W4ulH41u30lrsDRnQ zLFqtYZo*;c?yW4Yji3WAuj8K4Cx}J<&MD1olR>PtTIyf&OlQQ>x6x}iLxrwYNd+%m z-X?J9b?X1x$fm;+n;}1rvwmLV{a`}JKZNcaw6^pwt&Amk-|ie=h--IvlA|Yd%?e8@ zB%-I&#wK1I=8>#x3A}vNL=qKlVvvv`wHet@LSWZtpM44hF9%|@p-T=Sc+YE4jz#c!dF>gcmjhszR&?o&VwZo zwAqU=IqLoD{Pw>5s5cO+TiaFyXmDhloqv%az>FZ*5!4wI-P^ihIJ998y()_UA}Hgd z&5er$BDDHmovSD2t-A~hUSASQ;b&eewK&*4mv=qLCV~kP237GfPIOj;D)RSsa)I49 zUMzX{by5g|h_z%&C6?ROMjHneGEGdXRC4?~If`1%-)VCdpR&G^A%>3t8~uKyEtL9KT3Cw9PJD5zqv2itVPITwR{U6kF^VCSYFuGn-|Q6XAaB2M z#cq$lhT0#fP266?zL`Cux+E~-y}iBg`~3L3USA0rZpPN)*gHrwa%5?-U}*(Hb&TR! z_3!0dJ6!;PmzAOZ1SHUw3~hz&0do6CQNxuKFphgwlYE0?qx%eHv{#+fQdPV7Qt3Y@ z+`C_df7XxWftr?2O{g=5Z*^#5QGz7U?$;P?-NbD&(31OP7q4W2I&jWdeJ^Ecgv(=I zS3MQl4rd~ICU*B(>lF^FG9KU3LW-9I(DfbM^gf3fwlvc#_Jz7s#Jp0GgILi*<~qWRDugBAOWIs|BGcMz(qHI_h{pbnCyQls4eoe9br;l+ zRbQxSDq(7pID$NbBDK!Dfd7mRt{hP{ZUqX}P9;+On4E%lxSoK_0A8`|YQaxAme+aqocYgv ziL2^AK|V8Cfs~HCuhCO$6c$9uM#P8aX52fyf+mR}~6qpJy}9rPxO zRs+r2PsNIlDmDp4zr0Y!RJY(wBWSu_XNi77hNsEvhEa)^@{ez<8;ypniMSXS2BzPk z0-XZL68mLZjT=HUuUeh%iRv%!2*w@C2-oK~Gh8tfNxStxsl8M;P9MJFeLs6xOmu_g zF1ir@XGOT&<_4tC1TdftXOt?8oOaaS9%tpJY|K!s<}j6wVZz&^1JtEGoI{^tSE3)x zd|Ocv%(Dq23EX5dR^WFm{RR7=3*K|&uSP{1nKK(4k^-6FF@k{UtL za{exE#*sI&6N|mkXBwkBt6SkfX=YS7Z@fixNQFt6?&Z@$U=y-@b1+VZK4{A(>ru4adpXiOc zf%@o(CZit0Sm#2--QLIa`oqA~9E z;a-Foc=>zHQg%#cQu|5PVrre3rx(4~jh}CD;Jhsci*V-vHGcq|`Xv#X$l@MAWeHA` zc|a`Adl&3ZiZyjN_v{@akP)o|4Q>$yC7EOGMz`-&+c`P%V!qWV^zl3xepoeBLG9%q z_*(~c3xm6hSx8{=3JWqFDR6IY*zL6+RT4nqt@_BNYjDX2NU35Y-6nvP(rC--%{Ruh zb^TzhUNOXMTso#ay85nk_%(z5!S3LykF}%LY`V5M@}1Y%+t^U5hwr#jc;p!5tG;Nm zHgejWZa_jwrOH2)GW@`tMn{`+GE;0X_IDibgtf}WSNZxfP#D+f4@zT^pdRH_Tvu}+vGZUYv^`umXc^zM4+V+l+F}U|B$(iYFzWRpW_3w zzc2OfoyMSD?@GMA5^O4s(Xf0lEe6I}&8(lId{JK!IUo~G^#xyJ+)~Cz!Vu!*Z+bF} z5&R{J*)~(*^Q*6hU{*7A9{}f*sMl+!%6){&eKqSNh$)7##4-9dnZ>-r3`b6Qesh0d zr({fYJi~VIUFq3yUD3VHP*Suqo_yds@YiO8*u$>17vj~<^wgGER{Mi-H{Y#Jkeo?a zXR23!*4KWvOVQQSJrU~t2ai?cgq+MUjP}cad!_v74o*(v zt=~F%DX?eL)6ONU)=h#Kh72xDS?UlcuopQ6lrmk?LS=t=socbC%GPg9(M0TMc4FC! zq^48j);3*m+PW!E$$Av53f~sTRab>q>2fDA{Nl11#3rx)WfrlNfIV#W-H9P=D2=TY zgaYOOBMB3LIF2I8R$*{YN4P_0RZ_$e4O~&BTM@FL$Hi(C`oucT!`#eYMOxtxhMD0z zY|Ygi4z>}?C|`W6l4Voa_Kft*c&CkR@aqVGNf|`FU!1Sn|5u{Y>dl%^nj4)~(3hhx ze%9lNAP=D`r-_IdtrzEXD|er4wySl-O(j5CJqSJ|PZf7ueTzh$tU6{#pFJI&+EhsE zEZYtzSmE`HfjH?NU_a{c##i|Bm~};rPFk$Zm!1=?D5NE<2h?BT=2im_+068p1)#l# zX_f|855YLS(YyBGc({kD^^$Ug^BY7q{b}GOg{QK^TyTuyLexL&ZARrs(kxX;pMUWz7;Vstu1yGRrt#4csdJ7G&^w6kTZPFn%*{kNmx5cO~8GvP8$2ND9?E z%3pP-@0Z9e0;C6|xM=rbz8j;usP|PISQEVi!Yh-$&a+V4Y)r(>-mlUI?kUzVJWV^S zYb;iD1mJ@`oPc{HE3*4(IK`E-inylvOV}J3RKFG4Q?o7rabmEIAkI`fwk?g$X~5f% zX{m&?()Vr^R*WRQ<27bg?>3A*@i54|?(dHF`$SNWe!#S=V3-W@r`}XzNi#T5% zJBAaB1{UHCd^o}BI)0i&$V+$<$BRzC(_Va_cai$8nKto=OSp!6KNU}g0HDi99!jz~ zx>s++UNA}`VC5a#SL~s;Wtx0Zn4d{1Wz}=qVYdN9Vsx2y#pycn)5=dz{ zQ^A};L55o6lui4%pN4r|<2{Ou3QP6)-)pcqFdy`&CHi-Hkcvmc`MZ2ouBg)vqpaUU zBYh)q|CWWaeocp@;nK|i*=JrAI{TBL(dNH}ML$|!pR;;;x{*M=)0*{ev{J)DtPS#B z#lv8eFYwLeeUkDo4hHMrbL%Cpy~zc!q#Ui8oPMDTVWQ6CSpF6*^%p;V2+TJs`YeB2 z?4-zbwqV;sLiJs=8dWIQnPz(o4Doxe2)O9*z;>x03bP zbqQ0`#?AU~GCT;Vf->lm#M|>LAZ`}FZdJKwHoMLlj2`W5=KXUk{I5sx_wbXYho}?r zB(Hw1B4;`y&g$vtVBg=_hxmNh&=3WKnQ%BMVFYW+_xQ568yzSM0P zcsLcF^zM$;3|%}9d&o(_d5`fF>R?p{{d(CUzstFGWf>P zuJ5@@SUnZ?fYopF)p-w9a*4Cd)wsANK}Y=+z!`dPn!4%EG-(qDSVCZ~l6aD6*iFxL=uh?mf0ff) z0#WFTEK$epp4H!d3lX^{5{i1Msn*R`{KRten+h4o87b=hAeH&=L+&F4d?u+=JKqHB z@!6(#6=IhJon@SjW~?+$&m2+6aYyZ`T3n8pW4H_N?G{T0aB zPQ?UdGLzV$Vxpl|PuZy@(9@Dp0OO`ohcl37dQ9Y&Mgy7gKnXT=MZI?>pOW-v5ww6w zHg*5ZSmVM`DF&&!@}Rrv4AWUxt)2{`i9P?00*&Uf`zMjIK(ac7&1iDfgQxz7^MvYU}HaN3|HkhG#kapgU@1pHW$6jR`Enl`zU+0T)Qk1xMs*TE} ztU(|Pd?lUvYmn!2a~MJ`8JpfDUe^_yXA5(Y0iTUEIln7+P|1Qn@tOFJCLp{k>& z*}#)P_cbw-;RJD&QKmJ=$J}$UOqAWQf%Gr(h3!@tvWFCE2+e4}Dz4GH8IGI6$T)lI z%~r6qmaWye{~ETAtZ}1+f?79CLm3egzYA>)(^hnszA22ItOlk|)sJ1?qOgvfy_EEI zjNeeo{E*`9Z1&~Oe_VhjT+^8Nw7*8)iA7@;3L0 zQ?FkwQ!tGM5mG-~ARv zv4yi>t^d>dpS#qpk-eV?;w1} zG=1lcFun6tmQb=ChZ7V-T;qDgZBLIG+Voh(*HYtkj%x8QR0{m-3*RluL?5kldM>98 zzhe)uHU+;y7%d5o*s_R8Rad3WuwlsN^zg|!GGC>;mfDL&y7T-5Rp7R3V3=b26^YuQ z-q(-ZQHEQ=ml|3;BsL6sF*iR_bd=$yyo1;TV}Qbk8vw`P$OnXpNA(U7)E}BrTbUcB zabdmCLJ^^#Vz)SE_7y?PeGgukBu;|-er|al*hb4q6vtf@!a&-_zfnB!TsQ4#=vCWs zKel-`taD@Yoz`qcos9(xK+b~9G7Y|*8X9k5Hf_x~!iBH5 zZoMP%MW+UuNkYKn&A-n>VsZ3Mi3t3(T*_SoT05X zSW|c~-(0v>@8R-ZOIW$!hG@_)O=ww4Zw24R(LjR@FgVq1ED1ZP>Uby&#s7w(Lziv?DWF~DRztS63 zgoIYQ&gPbXH$1$Ybu2%au7$YG5A8d$jYJX+EOFJ3{L;YiIMf_H#qb>X2BwC@3JS#M zDv#={`Y-Y!;x>NqWIygb{neytgSW^^lhf1P`6Z=cemkIz3EMMpp@hI`p2zX6+YdP) zCM)^zex8-Pv!efOzhzzoaO5#0I7w2kA+0X<)zKz)P;W>Yr9W`)*$D9%m1Ck#GD69M zS)!vu!OQ*84``^V0O5otmD>#@dr{F+0^pqZ=qT`uk?4S8TmU})@2XFXpx&2|X7C&v z2(uZ`@$wf^kk2I4xX>s4=+n^NnV%;+r$8iox3~(vFM!d+aAJU>P2$agB_VoQG)>XPu2eoVz57p&!|D@2ZIr-r8s$n+d z;Lb*ysw2D8(Ox2WJFn6(yFHi-_0+bkW@$ZQ2V$HgvPA)uNUT#aTLhk2no%K>kBDs5 zY=!B`YeQlX-Q%4uyqxKG(oFewsDAIZbD6gX1dMai}&LU*up5-K6g%uO&mMIN> zjX=Vi`@5&P`=-jpCUDwRAr(w{4RTf+bK`5$!$vt{`}q1#2df5gUfR}Yfj;>80=1W0 zVD613E?l;$PQHl=d$@Y@V=(Q65>y&-%8rUJ_>%V{9Nl!vaPX)!n~n^0nPNAIcqvFA zu~}I4XkzLmDMpsTwBY&0KttE#oq3j9Sx<=1d-KYNYx%0fRYJJI#EH;HE-Kv#2aTH7 zUmS@#3|SPZs&yP>5hol;>L$f5F1I{Iq*I2s7v#;Lcuzk-D!0x0hlttVXY4+5;YC7< z51Ez1=*GDfr({{0c);#Fy&;VUE!Xr?;$Z6!(Mb4lL@W5kQ@ zM@WPl-;(^LQ3JCUm-Pr~`JB}OfhU8fi3)ji^rrv()PP7K$GyPeO4qWEwB+^qPZ<&a zf+f@cz!LB(gM4!5$s*IN92jRbvp!nm#$oGtPLS2JQssQto#qwB9wxUS;l0))daT=5xQUef1|;;ediafsKn7Yw%Z*Rk1?+prQ*f*}j7n5m7z_Z|7KE(s8|XuhG;eS@V{D@1=xV zi?AUGf9V-B0wmLvc|5v^fNkbiumZrKuL(-^iHZ39K67jbm1YfUaJ7!%cuw$rbmjoI ziooN$i0wR*HJR;@YHQL1ki|@mP0`dU5^*1RBi)Z}@Yf91Q|TVGdSn0%k`e{y@NfMh zq2=t9oOIdCT4V=pZoRZDIXi~0a4h2?HV2q88^xodK-iE}_tMuv1rKUT)Vf<8CT{h# zuUjBUNv*66Q}vJLLYA zG-t;6)9x-y_@d5|0!g`PM{t8avgM z6UCa?k*a1B`y+~^n>F<+3Q`)AYKij<4T=cB}-E_EM~pH`zQbUkkCeB^#u zAo8JvK`#CW>Rrm(#CY3=DBXH(+7xqqjrKMzDs6K%s4g>#lFcJkQD=n_Yf8YKhQhY4 z{?5@+@Q!kO<#S)!0Bvp_WbIVw(S9rAL2EGEo}U=iENIF&EVqE<=5)ByAa3p=#;gxp zI2>cT+471-UcGm8(q$ZLF;?I-ocHV(%Q(> z-YlKCfbf!XYnrBlq$spXM`5yrLh2C%v%0>GdWXASQolQM;nDN?z%Oj{tL;_gHqlI^ zieE@gOp~e(<0u-Ala3Y+E(Pr$H!te-Ysx$7*tQBKE>YlX;2`%3x9DgW&gi%x{5zp9ROAc-=OYU&Z%j~A{oN5lCZ&!c5#-yU z0N3xT#6+u1QSP{Q%AL)Ar zdFNo$lFR!^j5}chRLMOu@}=c$UgzcVagk3B<_e6oH7pbLV>_qcsG*|i1P`9um^6kl z9MsluBJ+b@(eRcx3pOW3DB?@(P=7_^ZEmCFJFXdr>mS@9x4R&Uq#j zaq1?Z&EXvCA2ZS8oqre^IUFFwLMhqs6u0Cql*=Se64A!Vi>EU2Zt#dceb(9|%?BRd zsoc@r3r~tZQ`fuD;*v){Cf+V31?2S^+&nroEV=dcb!-|SO(Q6+yg}5O;4x(5XH#@Q zT}_x^P0f=>PcN)6{=V@x3FMjzEY!K0K?zJ

|ZcO99|zD`*s=zl+Lbwv_0Gy~k5bB(bG(N!IT1RVj5( zZJP~!#MeWka|Y=rpQ|R$ow~BuXlT&h!hFoWH!Z!O{9Cg3t(38_3ygq@rY6nKugPvv zuzve%G!q*V@=F-V3GxYke|003O=U4!^9fH6kHSSk^=Du09W)Fs|1f=!t@63;RjTHW zjZ-OR>vl9ZasJnLV--KY@n+hZ``Niz4VUvp4p$?i8)Mnw;1 zB-eF{q44ovBKroD%A*{rB#-fduS)$4=^|j&cz%(YqgC5slE>q6We2;68B#JK3F4_ zFTz8bea~it_m&u6Ufl)7jJa=WvW3*&axA^fzAO)&nEvn4n(&k9mMNXN`nitNF(yX^ zFMbkwRP2|TUU2XTum^-YLf(vhuR3oDmlum%J2d^g)K?jdjSbIVif(1Npgs<@Ws0mbb{rJi!&ICTm*PU=jb1v_pIlSD?ww zFQ*>{*UFsY+8E@FFVLTKD5ac}Ydz}kz7+b>S|sK7caj~_4!2fHYbC+|br|bRcy|AI zLTr^3 z(xuYCJjE=AyL#`^iQhpDvd9_xq<5pi1R^Qads;tJwYc@~bdUvo`j)aPRZa6?nO zPfsaz{11zN`;)ZfO>?@wlumK^^6x_O@6ToGzAa+(>W_|-n5G81?sG)jRzfMWKKF0o zcJu?d)tY+y!9{ywqf%3=x~jUY0*PZ(dH!nLBK#EpG@3E?Vdk z^al^LHs6uZe3dr*9}bsXgO{dcWV^liJa=DWXhv(=n6}Y+J|io8{&V)D=%Lj*x zWcQ9(DMB9go=||<%F*fHTv4Kef?bbx?#_K^Lvpskubw^%Vi~6x8kL$)-P<$ur(*Ww zvtp}n6_C_rWyLwi26O7d1ZQ4k8&I=H98dmL8hUfCLTOrp9(puy<-%n=6A+hV8qNmm z7W`coD@B}dmL3|kI7M`m`x$x}s1zHEpF1=yGV3_wI$Kc$xFV}l&Zt%=tlhU&LhD;z zru;J-=@av-(9~{sUV4M+!x$wpTU9-H$&)$Y_eF6u8do3t=es_QWF;GLUS<5v>*fNb z!!|Hu<0wq~$~sq4aA*-`K)+_UPEIKDY@0P9Ks)?TkYG^gZygPioH;~``gCzY5&Oza zeo1LTrb?5>L+!juO8g~NZKqY!4;6bh3Yv2yU!MFF;nJL-gs+JW&%H$>dy#Sw8(d#a zQzja2tVv(1eOGUf7@T+~*#(zDKmjrS7HL6{z{C z40HC7#OhnsN|~mmmsknLqQbH3f9O_~Q|GGIgr6#(Z5ZUERa~|a#wa2h^6oz=7&PPy zj8;ONAZZ~CWduF#I-5@^P$P+HrYj}FoJ7?_jL`X~;V0VC_`VofUok)boy(vBmFO-?_UnA~PodyYIrrPcvXd_iTIYg6*QD#vRgSl*;!8!Muzmr_ zE{n!YoP6GYDZ-lCN+l5iTui9t>F5>X4Nn8Bhc>siDkevB#-drV()i6zS<_p{{dhf0 z8Bi&pFk;|$EBzHpCFT6QHtDyE0EgXWXR+S{S`U?zoyVI3lxzZjoDm2&w9_ba6%x$V zBDZ*%3k$l*Udr^om2=3_xL@ahTyd_g;1ONf`avA|j^P2>qPww8eKY}fTvkSX3T54& zLd%-4XrV^9Nc3hrPK&AVa4X%#On{>dc0#Q?1T78|VZ^X+P%2xaZhrB-fwEvwLD^p` z+l|_3PxTSUc5SYN#p4c{!#iOH`|+B%JEfvv`cPeCW@WKG^yFLbT_p|KeoeEHpdm?1 zt*QMXQ?c^jB+!v`J28vV055RvG31_Boett%nKh!fl0H59oo6xl$#&rya;bzf>IfTX z)>o=5X61kbaUTvHc*3~9{gbMtRvPS^hCN)vKBa*dG8TogUcmHwsCJROknQ$xy%pp= zUh!eWLuIT<5X2H`1USS`GvSw4yNGd)kDgTRnZEhuO3bt9_<=>)pErg7e%!7ZKt&cg z{2uyJO~1_^U)<1uVb9!iF zXepq-bArEr;8PKMH4fvxE|mAGFlC_{WDAMXN`u-WNB_HFut{0PQJHiE)uKC@{P9ioFB8boqUs8fyVY5pfHA3Mp-mTms z+$1a#ZJfTbxVG$2O7_do5)nw^AUqZ6l++<+u#a6uau|GVx14t^&qeBKTKG;vM#PQ_ z!WW2XKH&#T!ki-9p*1(j{`?)QqbUn@D8C7iA91+u(3ar%<3Tb(&xe;(zheTXEFOV+7N#~n&3^2v19%oEEVk4lU z|D1bdr~w^LcX}yH2zkc?Ggyo^?w1iE==EkiieYVs6h$aY3*IsPuv$2F6B@tg5e4;pQbur&WCM#l z?s{iZY19^z84w`AuF@5pc0D-LBSDyJsyW@;^PEcD15;?Z@_SIbx0e?}nJWtKj~RS? zl~AaRx8Q!-;eDf6qDqQ?o_^UV)24U=Sh;W9Rk+qS=-S-lX`MrStU=aEeO7!5Zv1> z!{XePv%d@y}W6U6kvMH2V%7{XOs zd|LSjIPC7m{$XrD`lRQdB(&%gIoS-=CL4G@tUak~Z-DmeLV3s!`!f3i{1;pooN?aM z=dd>%N^Ge%mBEydY9=3|n!R%Y6d!E(L9F88@p_K0JJ+;iT?3p(*s@WO%%4;)qrT(G zodWaKgoRLi+Xx3CV_Cig;(mu{4jpyb$QvwlkEzq|2p*}SN!^W|lYa~I-L;E*0m`C2 zf>|S0t6u5ZC&6zN)s4~{pnFk_<2VIeX6YL1oY~9J{@>X9u>yuZa-@1hnx%reEMDX2 z>lrvs3^Q*0foAFDx%-$w`+0DVG|V;0DUB3Pyy|P5Hto=de{DeMpnkD7Te;@2h%PyM zEy2~#jkyVQ7@r(+oi}l&2ez?eLPk&}k3;WRFygp?@drUrkTD7MTR7w!e^8nq|Kgk< z{P?2)6i)~*j404^tSV_e|3=rHQaHfE=aA3oFa3!m4~|g8a2(WNw9b1WGrpbAvfwf? z21pT*-6O_S9^HY{rfVp|9%kVN;$ugeW+%Z8!Pjxw0Cntik`n^#?y_q80VWXk$^8t% z*u$ORxfQQtHu)h=_9x%bL){Ah+A=2D_Tf5;fg05d$qzUXus@TxAB8U#p8p+=5i##I zZbKJ(mBrOd%8w>Mrr;$WVl>}bTZ!GTr310@%QKg8xU#-P^d7Mv(srE<14E&dF0*lU zRpRp=M)`S$fg@-5Fv=P{( ztFnRefeyxXK&8sgx^LN`85{%2e?>4O5BI@~ipw=hF^uxI3NYbI#8u%ytIK^S(NhMS z(4_vUPeXbmg?7L?~!-ePraM636)DA+mU&o zC_BmB2@~Ewf|GKI-rz6TSrgNHTe=P@=)9(Yjn8DC$U`~62TohZ^anp-LByItD3kat#q?FdVN>q>D-KO#eO4nF-nFjA zYtLv=ELyitxZnn6S3|)>{VBUWPf`k` z|6*RIH)v)h#)i8>OjJQkAo|GtEHc-t(#%R1UR6;))7JHQC%2Ow^k7gz;*(>;p;HjR$Iy#eGv1fy>{I8Zw}!vF*$1^rN5|7`li)j0FXUYeS?oeexoqIh zV>i|tLKtgmvY*g->3I2d_=V&Gt+Re3>5xMPaRe#5keEfVCh*&wJGK)jjo8_8bPHi<3lj@370p=09UGkFfAVzx#7+6a{z1imoS_e5ACtSSVsLUeCEOl*Pg~0u!5Ocz-a~$cAF4;tuP&Ro)4-GoIeFBnoV4!oy79KX&YJbTN&53Wcaq(%B-o4OCt^89syAao1(({E>L1C76>CrKMxKC`yeYoM+@6eUx%7O9Up^kV*9NOX5=dafrpM{38)b3aE z`%OG_%46E$U2r*~l>W+KLF+X!9hvT3Pm15V92wu&4xegYefRr>I|97(w!h^Eh(2=- z>gGpemeU&-rsMTXrOJ)9WiSNz%CPWqm z!Z^H$)AhrBZVa`>KH^3l!)x-pA_fgK!;ijIZ0W z?TtHT>WI6;l;tZFmznsP_%)fGl3bAv=l$mX#EK5osHXOyaIlgKihaWSEnYR)IURsr z!4#%*;Pgs;7oFbro!%T&LxaWgkUYr<2~L?iN-c?rJ=qheR$^{kXIm8!bETg4YrL~T z5q}fPNOkG?dL-q?5y~Jo3Jv?fLO1j&P-8XOutwM;SPWYYEo)r`zZ8xpKDET4RQSL0 zO7>3HZz;j2^O`mlwa6`DJMEB^#*cfFEr5EE@)z1Qpt6>gFJgaebhj0!gNDiuWwnzH;H4}SZgMOXPEqBQi(}avb zCYXzJt*OfT<1cM_Vp?LXoEb#@<86|pBJVIG7S72-U7#I!q+*}o%pvvL!-FE{mc!0m zrak$xk^|MlWG{)}4C$(LXN-|gs2+5tx-_Oqsaa_>|FR?JVAYn-dwk;*t7GpW`a;`p zQW0_kQ6M*3GaG!hb`?s-`z`WM-_I_#w>Nj>UD_S~rgX&+XM?$Ucy%6G375v7z&3x{ zBWQ2@VZP!r#s@Zq4A9QIoBJ8BDy`DgmmHeHX~*gBb6)S)-B`#FiQ?e6(pvwd@;z%t z5sT6R5t>smYx4sPn!(E#akhJNAMH)F{d~aa&E9*GR}Nz&(~LhHIMDT~Klqrb?iD3k zw)07msuwP89}gX>X#+%DLTg*65~jjBd@DP9gQwnhruj6_UpJHZ-3QG3uxS z5$)!Mwp)?zE}*DRdD}Cr;A+UqoSv1nvvem$<@otQ+m6*w2bq(o`yqOPK@lM-F1kdw zubji7DHWOR{&|#I1@AONC;sYs%B0z>HF;3Qw!;PE?=vosfxs|03O`QDemZV~3n4S? zFtbr~V>HSr*Yg0QRGxw?5N82dxb4qHADOIi%r{N2paqOTsZw{^l+#7N&9}_P`)QJ?~X( z804tSqw(Rm$!hu9**(2)23t5){p=sKJU@n9kfn2xld*T?dq{BkgI66SmJFMNct|Mx z*ox3JC%qApTs$U&7R}!)e&OPcPd)JN_~GCm4Tyl}Jw?omAO;f+fqVZ+dwdzXIeYmN zI`gqVET_*(A_5)&lNKnjp7UHjLwBU-0U;x3{m$boz_>nfz%V3ZApKMsd7Xe7hgtCN zzkdvky^slC<63e6-g;yorPhP?LOz};s77tG7({;t> z8FQsD=_3!_{UsVNS(GX^Pns#(cKG}C%z!gMh;c;2FXQ_iYK%$i%+Z6o?q^?{L6f(s zPsjOSNPqVO^N%Uyk}_|RHdm0!XyvULv*MEOOW04E$Q(*}txBfx=qK2bvh$`?>F4CM zfsp-y9D(8`A2oO)qBHr16@gTBuTU2IwG_-6o$Y9BcYnZF)5hY zY*haJa}8Hy-se%SYnRAD@B2tr_053$(6zGqoZaQ)z0yk~&u%0^?9?X{9_)F-R0xa$ z>v+UH4FjcBGtNWhEove>`K(2jlm zg}<0WGd*OqJKP6|zPHKyyCFTVtZfskd62gu_9%?2f2f`urUrj?YNuuaN9a%%$1BHnbY{R8Q z6h`9|=@?iF9*z>76a>AaL`M?AdziHr)6I#QZf7B3W(d(a(>Vc6nQ+ZO`RNBII3P(! zKW*#I9G+{*BFZQnJ4_u*Qtw>Av~ap|O(YH7M>$#jt1~Wt46Y*yZJ(!19ap$6$y!R= z4-W*SHZ}VC2%0s#eJFwp)UKz!sCN)U%Ena6O`juo%)-j>p(j@U8uOFfFVip3F;XA< zV2TP3S7aLz@i13J_FF9Xk~gVYA$)Vhy;>39;1KTKxzY&;e;(%wpIt2=?~g9JfcUImZyAMGzm>p}vG6iZh=DrO4#^N8oCv5G6ta zmYok-Pe1sVCB@KR=yu7*Q;LIe9>1A2K**x;F4E9taPiZtfqF``=80eWLe)Y~-k(zZ zVsrtJc^VtUCYjA(!3pmD?8kq2W^xXPBy%qH8(VHvS#hZPVC^H|Yu8^WFyWN3DX=RX zHyh)g=0q&E`k}*`FFUVwd*&?L4jDo-k;yfQ97Ys#7^2_(>gV<4iG)=PFKJAN(wFxf zvl>@{RM;C(1@t5|_YSc^Zrk;rAS9&F^!QJClsTe760}`Y5v3(HJE(}8-?tcJ1I&4a z!k2p8UX} z0Zr_a`Wv=kG0)o=o#`o_EK%EfOTsjf{fxd zS0KIWnI}mfxnx*k4@hbB95LS-8r{JjIw$)a2^MW+*B3g=M5V1g-h#9l$L8BZ`EopT zMK^gksz=CvgRKmq8{Ao>A@|mhU>Q!pNWu^KYr4%}nA$qaYFlU}k8Xl7a1aBFF)QV? z`ro5h*{Zay{97VNpf@QDp2@KgI?Gmf(74&RS$ZAc`^OBiq+C*)#DxCQ$7CQQgW=6~ zIT-c2ur#f~LQ0jDvpahcmi%muRDK>{BG+1<{ep~)dDw-_V)xh>Eo-y^(qZ2A-Bx_xo0LXY?odYVGf4Jy6#h;=VsmZg1J)7-Z6 z6gp0_?a&kXdq!_L2GN{&YHK|?d|PbSc2+{32iNerS9cQyw8DcXBUUZu&J?=vn7DBe}SKb~-!`xm7B!hE-TNgMsZ8ln^e`lKE zpZz({u7P#-e^{Ucp1u2 zG1AomNVV(8flO^fPI2NE*O1C#Y^D<|=G2nBx*NF=PXBuDODnhkShW#PxD{4*i*r$V zrqXbTHh&3v1fYgDpR&5+pUcFE6(Pt7ZQiowI{MI1VIlo$$bxkDoAITZE0XQcqvnhwIiN{k8+Z;GYrO?g_7S$J-en6gwf>0ayr9&mP(#7zpeCjT8O{9_Q3=yR#3Nmu zfv^WO$RXH#YTc71M(6KPYQ(x#sD_{hk&lS5LbMc6oVdj@x9@UeQ2>SC3xx0nUW(Yp z6#93w_*F<&@|Yyalp#Tb@(Ax*A=hpESO&51h}K~2(5IB`r@l|h&Zn7xWvlysJd^J+ zqLK~Dod!Sb*cz+N){O;+co3rG+Dk+F z>Ta8F=fKdL{3o~9&$$U@qy@Zbm+tn+Bw_c3XGlmWkwI#KUZj|-j|}*A4pRA~F8d&3 zCVe(#7=i+y$m0FBuYZryd0Z|xa1_17@c&WGJT!^qH!BS@?NI>xk|x^DEgZzTV&%5c zhljJ^!E;d{+cL*3)ws7@ak{*y)Ck#y3=2)p?0Fo!4f$9i+gm)2$>4If2V$hID%)Uy zX3k-LUH)x!3V+-*m0Ul6gPfS?q#*{TQ|u~)_stvdGi(4M@=hV_pgfa)vVs`B05zp9 zwtY+XC{>QdJI^U&R*7R((sZ}B<6*) zF(XM4tl=^6$~+1$m*h6CFuyj#HassKo%S~-7G(|NM|N@#oC6y9b+$=Dx_*hpa~fxX zsPJz`&YZ@$a!T@i<&NieO&j{?hBhjs)DKkAx9{GR%eHlrK417r)9?Kh-I%j8yTD^$ zv_a+D$fL+@vBzKBl)^_t*I1tQS^JLHkW(UcoN$Wd>j=a!!tUQZ3qUQeyZ)aDf9ihy zjVP_@6iV+)iYrgrjyg(lBHvlkJgETv=YMcJ?%fouLVjl*^W`u?s_tYftn!bAvCaEb zLVnWPeyTr4+VBswv`uu3C9_%Yj5cCCRK%_$#;&7K>U2I_dr|4tiF`^Gavau(WSS)H z3cNz1L0boGJ!ToQIZM2rg2nmDe%0yUkc_=>R{R-{>xF)rC*Jezu-V=C0&7%THqJ5$;ssX*uR(&iLs zNw%(pVur;*(33Ew68N|e~ruBDkgg*@XFa-*()i0cMi)uY5bP1yJ?>0FuY`oZvpd#z6Le z>_8H7;p=}Bo05JU>}tlOh+QRY!b;xQlnY3;!zW>t@C{vaR^aTJ`D;_@wC!eTJ7`{o z!IxkK5YqH)OB=OKZ(nc#{0#qyZlQB+(`(!O5Be@&+Fa$<5C4CJCQ#IW50wg6gKKf` z)RE9BqNqxG;Wk$%zLVt}LVqVIQ%M*@{+q^rT2Ray(uUhumZ9eOW+UC3K zI)OF<41e#wEw3}~!)BOBb{>JHE`IZ$t1R3^ZMoStJI!n0s%FGdPdO*}*Ro~cTXX4b z^Tv2Pco;KaXqAd2z_4T1+njDv#=RNP^OaF*6sf9EQmzut&)I_98Gf`xro?di1%+%> zZMG?wXxbYjWCPAWM#)%}p0MvR$J8ec^`fxWrI86yj7;~&_|;a$Yi-7j%6RX5N*t6? zv>?7GrV>(#t?&_qHHBiqE%JO5?%PB*k4us2B*Fzs@b(>j#LL7Hs7;A`q5C%%SR=J4 z0rye1dq~Q8NvX-AEaX%8@bR2W;eekrFjYvY<&xU+By-q-7s(N`05yWBioU$AM^|DT z9!Mx(lxuyfNEKp?KUV0;mYFdpcTVEB;yC=jYzq7($PpCb_6g^!c&5h}=0m_N-7$Wc zofo!2DBQ%9Mh06j{MJ`=rgd;1dG0&3{r!88JSeb9skVQfZpwPjJ?4c#&Fx+QN)6|J zs#gbm_yL+T<<|%I2o)b0TCK+=|-{vC;V}SQ`N) z*Dk^^uE&!&_TxQj6BT&a0tiW{I-8?@q{_hcUiL^s+jULE*Bk@odTUg?;(51?YhE#% z5xnJl6saL#8BtB)jV`suZ+?Uz0@JQC8tj_!f(H}F@rGFF{P`6>8iS$vGn27x>DvC8 z-2s`&Z0<-N9q9`~Pq@G4Q}SVyF%n7w;e)UTI@aPxCOI=qG+xK-E4d2LzIVRmt1ixB zG*Q0zHON~!U^;V_Y4az^gLi_7VL-=Azx5-a1ZC_~(TE3B6L7T!=16t$@Gz$+?dd4` zH%d*-_?vx%OhkfjoGNF%Ghk}{X?4?nh2yG>!w(>MY8S5&Jc zrpUVx;k(1PeINiHd6Wv}HIaK3hBq0}gB=`^ga>(b6`1mPM{^;1A3A?ZVC0_)9f>zWSDBAzzi|-!xe?Z9W|wBffsSM_m+)5j+ZIpj zRT<^qWP{buT=Py+oZ)_s4tf9wt92U!Uui24=+qA&eeD96$2b8fKl;^j#ddVJ6 zoD=;vW#v60l)K>J?I zT1+vePj{tt53iJCTIDB5`+HZlHpRnuKv;p>8x* zN+7bxfQv3ncF!OAtJ5OHxbU`|H*oNV_$Iu0|M9~hm&nn(YMiMRs8KR=Fp0UCPl>VZ z7$?{xv1dxJnHu%MxnX^_9mK3N8(|B}}?Q%WnKaqJ}xNXMKf*OLmq&0J@o^c1gMCMoVZs>-$-w;!;yGrs1!QpwR0 zPe|OGkifhfPKN#&WufSB*Mpn*Rs@Y7>}XB!iWk*6N)-ZAdoL`weCz3vit6XA;}1VU z5|Mw3l;n{-3ve$6axJC<6>5P(%|V=`^6C~?##8sv#2b{F9LmP$Kl#(9@$f&_R+*?K zc&k^V<3k1^bFr;BrxN9aP^>J@G)Yol;g2w^eHc{7*Zq~c z#}dHUSuc zVAQ>whL?oPyjb$^8)=8FuzLVS|Dh{a?6z}8%`vlH+Isez>svle3nqd#_yM{ zGtF+a-GeG8`v?qEymqc!BAyqgO*VRrRT*CW{zK!=@Kk&3c;8VrsnP6w1E&3ZJJCjD z{y$0$ih3S&0p`0t#{N=(c7{d}O~PFeg%$c_=IWs>^jEpJw91Fpk5Kdow7IklX>8rB<^xhy)y^|T71l^$WM zpRAve*KRL3o|%~6!tGwisB1ue{gHn7)9O^QTD#<-qX#44ru>1Cd~YZ#n$zRwzHl!u zvXf)k&)K=Iv0MwHM*f)FP5x}kfbNNP{Sd^84npVBkyV`?I$l9;m{OyXm7fb5AN%>B z#DV=T-G@(Qp(DubKfQ_$1=e3=&YanY2}Q(9XI*ck=;me4n5{n=;sN^zzlm!09j)A3 zxsX%%PImT-guYr2z0we5RJ!_a|5M%NLEVhur9}V7aK*)A!g&Ft0`szY<{-Xu%?PSf z-+aJUgxUYGlRTtso{o$I%rkT!bl>_QkL1p}@P|QsjsT6*YhaRT^$}OI9FiZ@6m`1Uw^y9 zV|NEKHR&q)Z8as@$Yht#_sBQmWXx?1%Ghn`Us&PrtHAo8Xo!z}$IpxiRgCy~C}b}& zB`t$8`C~RWAdOnYJ@E*iK<1d1^Yi zCx2|R(iclV0$P}kLfi6qf_HSk4D6^A`;#_3s6bsLcCj2U(S_&71lI0r#s4PCB}xAH zwLC5XZ-nIhe3f>|q3K@fmBia7Buhdg(6MNe=d>r>7Fe%jCSq)Q*B07t@_o#-SdEx* zhsx-O$;?k{-lUuPV>hK38N1eCOG<%!>bZW4-zh6*eZHPJ3HrXQT_K`@;?uV<*Okc5 zRY>bIS6m|+gafTfF1@RnwjI$oc`R8A%Knd)=dz4{k5_0NbOJaZq9BhwiTO?PW9cbU z%&0Rya|jRlpzXCQ>BzNLl!ZyJ)sjk@55Ce-f%*wtC0gc>S-bc>o|rLM{CuvCVBO<>(^frD zAr>;h=$T25B4kFJ+iCzzud44((ohf>Obk%{@TAPErA;bGetIahi}*1JEnubm?5)w8 z;L8ICE4l10e0}|L^aUYn+H4o*y{Fc+GFd8CxRZ>|ydymH-GxzaVLy8@BId8`hi7?i zd!)(JhuKO?ffbUW-$7+?It{EM)oD>@dBcZv>3yIfV?7#bsc^b3rbays)`L~L_e|?i zMq1RLD8!ohg%<`S+&|cVEu<*ku0RxDwdc3jW^J|)-3{pS;A^P1VmOVUSI7T!BQTPb z+bbPzdvFun6ciojq23&C%!1gjm97)qP<O(0bhGdGh8hE<@-EB zeR>5Y0W0R<7t39JT)v*3GK8jEgROtMk36$H3Hh9USFK@1mb3FHC*`44DDw)#biQzS zr#Za9sAK-hUbCD58C~sp!XZ#>3t1VeQVgy$VQm2fHQr8**-u5kAe;Ng9m?ooh zcJwH4m81_3$4j(!0wLc|)+J}*E42p`j#M%O+_1%2UKsiWYOZfpkC1EEkx(`~K#KV`QC-u?F z{+vaxDBAqGo95{7Sn=IJu~|sWu@_;rIA$;=XBXnDYV$Gd+HV&ZZrhp9@0I~Aub+SX!Ll)~vxlD-?he>ijm0vHRW>K_$F`goS zjnEj!NML>>u?v&pkIleB^{9DPO;ddOqqHK^$Og!iRJ`4w@MibYE`O%c-rk|EUtCgm z*vdeI#q}!+R0*PrS0&6Kn^NS}qz&!cLTMuD3x;bqPvv626~xBKsB`P&Qw%j@yG86s zBQPjdw`8o7Kt^!l zQLRGd0YYX7ryRW)gG{xA^C8BWrxLRd9iY}gn0srr5mQ9rpL{+(g~&t<7{V`ZMLMET zKs=VK4V&V$0P z`6mdSO_Jo9=skD!9O+cP_uz?-D7-pp0tQu>JRh86n$g8vKHA%N1VsFaFreR+I_+uS zp&2JxFx(!wP#ut_l?jvPoJeu6Dyk6xI?gf1Pk9+4Co|j^i$bUJDOt5&;^7P4F@J79Rk>73sgd4K)k0&t6Grra zkPCfSxRZ)kKfi=+2OsZu*HZ;9%MIfPfdI=ZW`Ik_)Dsln4>&_JrI`?=J86$E){OYG znhKr=RT%3R!I`+-Sp*9Cu{(_-uC_ewhfZ3}8eN;1Q@|A-=`|SAaIIx9xePcrwP^M# zlySrVTj8`G0P}t19z$=EbNUatid2Hf1Wbh?>XG`w;i`e=neWrjV&XYX400=bL~&n7 zgem@Y3%^Fg{rQ{yd4KgBq+X0e?~aqsy4_aRco2(N@+Xz8iZ;1lD5kjT|JkqbO&pzn z^$t~%+z=pMqBS!$16ntFL%mjr=pQp*b44!2z9d9Z#>!7WI458Sbg4Ys@D^TsdPA$H z>7UIMST+XA4rfyXl>#N27v`&`>3(il7oZBYYy%mxuJ#F-y2OPPd7%c?BG#%YljgHFbR)`Gf}5sQ zss8j7*xtKZLCDJYZd%y5O6U7EznPv!HM4S^uA}%n1Zv*%7JEbky5KK1O^6P&hsWTxQA z_q5AJ@A}}P$M!_;BfAhk%}s#;Py%Zq`Wo5gut`B@N24y-+UMdGT1=4>*2b~*5DKp= zR;d;yZz&Z6bEN?b(d6K$5qRqhhxt`W0;NWe>cI-x1paidi0JIoiJCo?f)=BU{foMT z2>4C(>z?8?R8NNzQYvYvrf-rwS8PbR?P=W1VN^pQ<+TucU{{^nf!oVUB}&u0beTB8 zqHN3$g>UP;fdJGj_h-u&QD92}Lu5JZYH~U(?V&po@_ICg=2y6;I}z|=SBo!Jbe1xiA9T9XB@wPq4YtJ zB(-P(FVnpP_YYIdcq&i*0)*JCLOTz4bkm)diU)Q@~~5d!sp62xyKq#GSj8%Bi0?Jjeyk10f*^twr4Z zeaj;xcYr*U2Ic%HK^aaIit5zvj(1RhiiQmk z^_BwZE}5*SYkDkOWQS3m)ZO_<1r(`KIBActv!1<&Vp?guTPfXmi?r0lWb8`oKUc0X z{j$g-Gv}!<))vd{+OIkJ1?<4+CS*h1$=0hY>0pplSF7ny^U@>D{`(YRBl63c@rLmn zmE-*TAN(Rs^aAr*bToZwLAQMT&3jT^S^mTkj4G^!YvbWipHzp@v*o!ub*gpm(4EAQ zPRlEXf&76Uq=c)D$1+e;c(*ml5^tc8Q`xl4r#k~oNK!s#C9>&8S2(ZE8Hrqq4n0jq zg@y!i6TZ_hWxY#}4Jxsj3V3=ECeBP;`VLG6@&m#iMWLy_bepSDZy-%`yK@Ge^z0i7 zxmMtFYd(|69KAj~ywEH0M4(QjTb()qITdb1BTMfeWN)amVX_)4e!*iX$E9$?i#*hR zy5ee=X!@@W?&$$k!b^a4E`OG9l~O`H_;zXMJwk3mh9u| z=&gL2${DqHCsCl{H3iGkf1$+3m&Do7kzy?Bns?tKH*r0JVb8(@8f_AKtDZd2(ARUX zDE(E3IvjUZ8!nJf@my@vp_bf0~vTS4GhAmD&Pa&annN+db%co|H z0-5pPcYeTp+L4tt`ahhnF3t$iA3;ic$e11igsgMSN6D0g)e3F+>6h>^Z=!m3hwm&o z<#d&=uR+ed{#HR5)<45Cv6-u3=Jg zmi6l+YHL6Ffu1#bP$42I@~%h4Mm;0A6*2HFNWY8r>q9?-7c_(%f0tj)7Ny+H@f_G9 zijkV}Ae-c)QyB{*M}UgfY85Ap|8s|fFI1sWHg9may+CwKE58s*gNrv6f)!8`O8Xan zbUqE9!BudS7&T~8Cd>2#{h=gR!f-Pv2xyib{*Qx9U6%7w_!NT$s_tu=0aErrU)!1K zu-aq~*$rWw4LOU;WP(G|GMM9?m0!;%u);w4V=z}UzeE!+O?-EE#2mciM+8_V({)W336)%adK7M?pk$)p=+%9_CYgDBevc8lR6I zpnd^6K?Tgf=`z}S%O3r&ibR3$k)PhWKN6KTnd@1cllsVn*Fm1#t>N$+P?u`925R<<9X-FHIO|?S4O!{Nn_VFM#@nq7T9gU7^(+_^@~81Tlihoy zSFQ;Ko&)Af-9TruF&A5Zm&fWOj-PK}@UE#+uYmUWN^_c2H?lkOArZO^?9nC-;5d z<2AA@N5Z2Qo?=2tqmDwb??2H&@}GzwnL`|e(GHMo4kp)F5hReo4IAm+Q%AXE2={#6 zrzVMBASO?k+iIi>GYO`%LF}Z;z#(HPPQ>Xk%E9d~|BmLk;{Qo3KYhAH{1L-^lb493 zQ>G>H2`aff{7J`V0nU7foSyc+#y3Y{(>}J@p~m7*s{dezgK7?`A5NDF{UQWn$jI+9 z^R7BxeJ;={^!!%rzPRq4J19De%R8$EGO-5c5tcaul&c!QpTBu7t?=gVvuIe}#B?ik zE@CP-H*aXK#q=v04RR;Fj0`D{*FP zV77wPye(mTt&$16sRSZHkfx{FvzrNE7gMlM3{{Lu%$LRsdi*I@jKp}B$-$|C9eLOY zwk<2@CPAK{zNMl?e#|n?pge(%E_~9+U^9m0%Lvl&Z$!N%q+dBhPUtmWW~IwB`>F?M zs}6}FF6kV^SD(DolBLSF=p1iN;pUZm1d;k6{HME|yPC~km(l0{vFLq}AWJgneK#zJ zeuzmy3>r-J$lIVuR>1;S#P^`{e--P#M0+tI?s1S)F3Y07APzf|joeAYhCvzgi-+^D zioYuX^YDE@1BbFqZ5BRQ-66W0%te_GC@{qD4?L;}OOJIN*eI{r2G9T82Uug;6H2fC zNZ;aK`i17Bt~5G>&}fp^nWmAIkSYB+ZJ|h|BlCUZFQ{p9BS06{?Fw!)jiJX%7B-Qd zS+tmm)dt4_Zyrm7ZUDaYQnB*Ef$aRc{C`iyEv-h55Q~iZ?O_WE5+0zJ^o4YVE|JdT zUCa+&wpew96B#whQJHJKFb?+4wioO4_rXG}i|XSDc`}3d58O$v$y`z-yHVa$lqM>& z52D!iYqy35kwQ+5wEg8;+b_6E@1hIhp75}35=U%d_FgK*&LJmWGOjgu8f($U{`fU>jy z>bbAuQi1>J(U-hXqh1H1t96JwY%)nMsM?%>#j9ux%)S+?_%#<}X@>gci*a!K1alm4 zk<(SnML+Pyhz$2}kUV<-`azh-!X1>(r=JryAC4Uvf@cQ2pEcIKeUCS5Ajh9V4jnW$ zLlqG#--lz#jc=oeCg10uqfcNE#fLbaJ3|(uj7p1C$B!dULRctywUeG7sr&m@%mIg$ z+S4F)k4O4I95bJ+Y5y^gCT%X%c#rw}>MddJ7u_VMC+pDjRVwYDY1tE$^CDpu&&Pxv zrC0U9c%uleqsuwjbfWf89(n(%gy2U6_q`YUY7cRb<&#fDbF`X?KT}FsD77D?{d4>Ldv)FkLJpgdQl5|~)t#|1 ztfCV7TCyfl;L2nQGU_ozjY4gq?3!YyMyUzFN)heOCFXq9_*M3V&_v+1V+DW5EtPPm z$~B%lbK(P0jFINWCPjY}OI47gNY?D)dnZbFM$$#K6V10ypSxfe0)l4 z(|4`>q@oB1ML&#>!%SXn(7cvKuYaWgHKUH}DG5UABRCa>nnsFh^OxSP$#IO&(T?kIuI1bm#I&$((twiBBty!*E4`<%(OwY0+zD)1Y6ZOK+1}dE$66$7ZC+gt zlH2(IJbbl(ie*pSfP}CSIQT(J*?e+nz`%w`a;DJ7*T@++ z$R2W{*~c4S2vPijb@G*&h;14N{g7?`9~OXFxz#NG&#x#Ef)VH}l+kC9=Cu#aglf_z zyk}rzDT3qx&7VDy+_*_3KcnC_%Bkvx_)^qKycd`wZvc+fEzEA7{nC|1Z^K>vg=+XS zK7Q38h*rNxF)5k7t#ME4yGA-RX=C(F+yAaCX?@?lK)J#BmF!Yhv#qfkJ9_k_@634T zbX+&3sFV^H0aj4%E21AY-d>n}sY5vL8XMzI*1?fEyqA|DsQ8ZWg}*m(cJXuh^?OJN z!yDhSGy~)%mxL#Jw8@K=Cq-?hLIX_5eHG9>bivUv&nPxXVw(% z>`A`tl;%cRtLDYNcPGI7x2IY&Sk1H=Nm=N_U)ht>%txaI4AYMxrkT9h>jslNN9U{r zY5zuKl>JAL>6$wkpYQ31$0@5Urx8mv;mt@5v+;H*6)IP=5Fb~_*vc9M#b{5DoO!kr zon%IL3AcY0Qscp*dcu5Qg?)&F9DBHl9^mrV?2sV1HO3M9nQt3!wz*GsD33OxU!H;U z#*74*{w*KaNWPn|uyayP%~!jma^5C^bZt%IDP1TyoujbMnV5>d&>$&bEfeITxEkcv zC5mU2ul{|zBHwT~^meoiwm_nN6kBk=ry|CAdka&F>4F@3R?aoTg9(H)ofu-yM6#Gh zCpYBKq;hKr4jcJ2ZsO$tn_r*{hI9?TaD+f$<;9MXny~Cq4){(N^y9Y;W9f_-6ac$1 zRN*ZFYWh4Px8HsoQGbhYZ_W9*cBbjUk@P$rnBLYrBHJB|`yGl^?&p_Un{B2L- zCt8oU$2c!-du^6F939&ji+%BfPLKbw#$;j+d^XCt&KB2~qIjoCKJcI`k4XOV+CsL} zL?Pk-MuJZWmg}kHXa&2>)$ErDtJ~-?)rLY9I8v=4RUrG}U-EOd1}1Hz!4&~b%{f=gb>LlC(e%58SJ^oQJ`}!=HfR0`8UMMoz1~>|0Y4^od^M{{`@qq z%ns%NKGFWvOh+>Gb-TT6V%Egexo1mcchn z7hxsIA>dH3)|!+U-)4^+RB=1RW2_qWC6A8eJJIpi zeO3}?M_p)sa=yw9$eQmPAuiH=1K`3O5l>p|a4#Vtwv|L)_?~&b-*5obz)rFBwdPf2 zHWE!MEFWcw-9X!Qf6`m|Hau9N^PFI{oQaFZ3z|i0+R%Br!8x*Wip0{3Ir75!x#h2o1YqUW z3l=5HW7$ojcs^baGe__`VI`qkT2MfQlESenLI3=+S+JI>n$4H;E9|M)3W*~foVUju zBSL@Vn>J#WOJ5qiL-rP#6wGBW3>lrF})TL35-_d*&o zyljcUqe;|T@T9%982H)JV2vh^?!3w)FQbDfLpA+s=oRnZFaVqskwSnBBu{h?;VMPD ze?I;bqm1N0mFF;OVgpZ&jLuGKMc{&AUCJMjpnJ&G8g^>$^mxTAc_wSoEyv{sK+Jm; z(<9gQjU$nUui;a4bd8<(-IqW26w4Z3}sL7HAcVUq1f<)gqCjJSW6S?VL7++&HZzY z&u8H=NKG+ABU$3NbU$zC6@mn)Su=FH923#-@XE2nv_vV!x8im3V=ouk>c=a!lBX==T17ORc`3`lK(9Qa{)PY zv*$+CsQN~JHO)_)rJNRAwf3y=W4mm}&>sgkHDWK>vL`Aq6)Gw+6y1hg=^%^A8x6x) zCgZ8v&z;5Nc4j-_!9g!0rk2v4b{n0l`6r+*A&0>dXN<7|e}g*6{$2ln-v2&*Er;gj zlKQ@%K+>xVw8^OadHYlmh&YuVF&Fs*e>2id&Ygji??mUPb7A2U_cw z0Syly6fpZ&O}~!DD1+6OW{b;7ja8y3&ymztMWGynbsra;q=nFT5jkZWb|%?MCLfNg z&r}FtKDByl^s8EK>zf8WpN5<48&0worgIZqs()ui08l;CnK~qMU!8DYqB5|1tf5C) zb_8@BF0ielMxA;qt(0Fj71in46cV@Vvk(}-4wk8Z*xi)2PvbI5XW7=F@l7H;zbd6P zESu}=GL`^5CNGDjRVWDaot`c&f+zT_lQ;uW$L=(%mt{+S#e z-iJ7#ciRR}GI9V{33f$fC<}Hq%d$gu5cGp#zB(ySUBTUWf)!sqv(uS3vSU1gXnn^f ztwR(_O32^HGgzniJuKPcaOsNR%KFW#6m%@d7xOqIk{6j#@|VSrqWw+H?Emj9Y`8e@RBq5Ch$~RTNUfCoO$~cAvzsIXkE9sLAeSP~!Yk=DX>A4n z^Q8GVpR&a1|DDYrFD7Z#t&RLAOYs0g$=OLVA$*7}@@NP|K^HHJPD31i>wG^%Z)`H# z#lG_C<)P6&!~CYY@+~aQ*}+zjKmAV(ENR zZQ04_z{VURI+gn_16f;UO(}B5)&qZip7&idN`&y@O1RF;6o|9>VuuikZ6d>-{;B;t z{_(A)A`DZ$@KP=d!(F;aOWhOZ=vJe6WPME)Nc1q6vGPI7%}prhcn$CA1TS+Ik&^Gx zd{>7WY4Rxlx3_^$Nslu@|LR1MaqHnC$j(DJBM+rFq$R@C}@t(Ev?#>43c7p80RNV z_*_+?;b|i&{c(4Gi`{rNedr9l|J~fxfmXotzItm{0wNl*cE5WJcW4YCsZn?h-NKy7 z54`WK`6eq$y0`v`xBoukKfWMITfK_m4|>+_N3otgp`SnDca`$nYd9+A&XC#358y!B zVN`Zq;(TA%>#CT<{$*>8i+ju*}Ki8xj4AS z9$n=hxk(0)8naTz9UL2G8A0v-ivtJ!t>_8!bBGCMDDHF$WjV7n`;DBi$$7F7m&mM@ z*Y|#EiVEZv%(O#MTp8*vM$8QrA4n(#W{a4IlmtkLr`dO2gM`>iq+W3QzK~^rB}Cd4 zN2jI2sq7{~6I~%POZYLT&HLn;Vwt5^4*`bv96V!CmhdyUj(ySjP{0ko!*=%NPGX#M zVFWQm?TXC^Ho=_=VK;pSIaHeu^(4+>SP^V8N780Ag+JAw^{!z2bGW~%)A0N*@Fc@- zXr51!y%C(A&g_dLRZqtCdi4J*BEHEF-348Ac=8Bp2Yphqfw{gfkS25#aCZEra@$OY519%`tV&*FHqNsGr5Da=y~_& zfGE1<=4{G66PQ~ypHv8Z<~FqOD7SezWp#ospoe^~_{BY2H6Pkvh5G3s2yt=0o+UBn zrwd@0ZAkKnj9=>Y+wxN;M-G=~TSX1}tM450&w~rd)EOl0Jwny_`ZQcMbGR>R;@Ot0 zcwWW6UfRjq2p;I7-s36gcn7l*@Pw-Kc8!14uf2f?`PTaK72UzpLD*8vY_H2Z8_hdr za<@B_BYppzRfap|PKeIyMz;DTiyX+hBtL$SIuNd~|8QAwT-!S~BNG1IeX146YrUv` zNa<9r+p8%h;HeMhX6v&miApE_Os95{ndW%M<2654#`j#`PBc@&$6$ueYo_%$XQXtn z&F~A&0KQib695S@+X|)Bq_(fqfmH}5e|v~vdz#LmeKkl*kmAn2OAwR3?bm?3Q1bDM zORUJFWhS}bA!`$l?v@MDa9WuuR@HlEbtzKO0)+ zhpeiulS;yx*k(BT)vPy|_A4VH(c(A#@iB{6kWo=1YskjG3FM;pvqy?xETisRxEHtq@PX?_{HL z39?-hOLRYI0!K`!wrHH*>|gzPgCpmz5)u9Sy!cNmjWYRhXkVB5jq136QqFw3o(wOw zAs-Aaf{)C}$Srr_ef=Iu-_Q!z4$p!Q539?J^nAk#Q9 zHlc)kYmK2uF8 z!Qz&9X3Pj;6wpRx)zz7`jVKQ+M2Q_A54}$0lIgQy1cVsj-{3!_r?$14J*;WSG7H-s zfR72!&|#^(8N7WUHzas-C8|nc!ZWWWF7TZ~W!`Da_mt2>Ku5-NeO&8m1JzznX#~Gv z6M2|;F-op1$kxa3-G1g_?0WQGv0)nCMPk%YS%_rp+>YUC;A%;han7f$C2Em4Me{upj zUz6smKYLXcbvdZW$`e}5%L5LjKR7aPN9pr+R9jdMLS!xdf+do%fmP{tHm@^&cNKq# z8JknvIjL2-WZLoJz2Ky%@{n8(%^YB7GW|_%PAt zfdJ;_n~j9e>x(DOrR)(41&NQyero2Wz&_?z*>zp_j!U#WH_h+iB)mat%p_@&!cMGs z_QW{KUv?@&oosZv_Q%LIM%}TB5&sVeBX; zQW*j|Qw(46O>_?IWHkt9{^cGs$CjhTnw`VcfxTr!QZC}$n$e`PDSCHKGXyLg`gXyw z6`zlPGJoPQwPc>X;pkyjNxT+T?%%c~TybYO+bwB^ZLAxsCjxj`NFKOo*gdlL;L;V6 zg@Oh}Ieb&0P8BCSs2p_c9gf_zz%z#p9;w^o2M6H%q@#*&<1;p#DJ%(zM*JDv^HXn! z7R;q_8%1s~%hW`bqmupN@QnPJ8jH*B`b8*V!he z1^`~J@FF)0Uh`Pd%zoReU}yX+Q{<+3;xq7BxzbGzO^XQW!Ot6Gnla>E{-=--IBLK% z2}NpHcqLJ!xtpF(O6u&bpMfGZB~8peA>4d zdb|`Vx6$_N=~|${UVUz5{)S%c*Rx&v$XR1azSrE+Y{M)Xl&>p);$_c~=JY*FgIqv4 zG+x-p$ajlI`>MrV$fn!5@`b=El}j~pgk??KHkp_1^Am_n&_{o5S>Btg3}hg+l3!nI z*mu<((DyrG!lc$B0HL=y%P0aU@(2F8)_9@SK@4-aLR@OxuHoU5<-E<~3-Ma+GocQl zO30oN1+x!7A(Q=qWm=B}d+Fn*kNJtqf2pRoQs_=8Y`)CXvIbrE^kq~+2Y#|Di20{y zJ+Oh&>&IO|B<@_p(1k@0fV>*@fs7p*NM9wikE+EF&Z}S%auJGk%f1l@&k*dWDQi|FvhM!@*{TIe3VoV1<+fO=ON#y|P%kfvC zYGaHByjN>9$dn}QyRfrcANS}POVeaB@hHH$?)NcZzq}TR(4SN2^;i=7QDD~dS=H^=F1q>A)B1UqTJEd zmx&&ENyz-{jw4M;PXis)Q*PVY#cRjNt0YjSN&=)u0YR|gR0c1Y)33lT5t^$I#6dTkca$ zT^y7o8`chvpltYtt*nat^EwVSLGT)89J;A>@aJ$mxDSa0um)fsp# zsTlEus;Ea^tc|=rdFt7Yej~5Nck}GxZg}bI;GcQVwmA@NU3g=$o>bEK>T1Emf1A&& zqVLaXNDZcXw3{b@nJf@&*WS>HO#%3J1X72HVK*q$=`h!TA*S7|H%RN5>+l-NJNE(~ z9sRYS<;OSqPT6_=RpL{WfOc*J=lIPF*jbI^A8z#{pTmBfK#HeP59Bb5rE-rZOg`o< zkQbM!SPEL{3H0$x#!G97UckIuCLCH5g$G7xcQ+V$e$rkTGv|T7-MLl#C7kZqTu1m5 z06a#fG=EK-?bA**|3X?+(r5a-8Iupe)awA4N6l3Q5^m7qSwF=L5Ofxsdw zs=gOsiV%vXQ_cXLS9;fcJlfIYuR1_doX^z9IRYSIeXXw3sdKNiul@$#Bm1|^@#sCk z=(8TC0+_aiZ6{wNlTDorieGceqFsT>WPIdx>&6q4G3GmOItOIYB=xY+CVA4{eRoN5 zJqp9&@=;iq4qh3LoOz?J7FT&cliG!;FOkUa4pFl3#DiSmC|@9sY`--2!!6G14$`aP z^O|7xbTCj>Cr$kgj80%xmNaskYQ1OqOT|Ppe`IL?PT7}J7Ev9Du0gNw=Ymh}MAY(Otq`6Z#NMYGQDFVl-Od)zPg(h$F~{K7 zExkI|vwU4K+Y;ajM7}TiqVZnN7Xc5}|9g{SuqhQ^i7we(gI|qYAkJ13FiyBT{n%BCl>(2rOr4vRXeOsV|x=%)zvcWXgpGHkt-A<^EdKQJUOFH(q!J8VvYC*oQ zQ4F%zNZp^yv58%p;aiRJWcY`w=dg;+7MWEe5-c;mW6KS0{nTT{(M900_32};KUZQs zSwUxfLvJ-IK+FUyYXkGEHQ%w)J~a%(^b>PGv;(o;lv^77l)Nd({5cQK*mvdEM~(kC znhB!DlS`1R0ce&CjR}OWUZ^>6SoD&oD*mZ`S`CXVrH!-M{YU1dI=9FINnpts=%?D! zuiJ&T%HCk>rJGMdgEZ0ODN(_6V#2HCn97Em0}==;gR_XG_cqYdwO0VxeWEk%IOQ>r zPde1qWzdABl@rla{N_s_nHqR)PSkdi9vo<-YK5ah7={mpQu$Ix>#Y)q2mbV1y;{l= z2703U=2yxjJbA%Ufm5wJKmU>{Vo~C{4#pOtXAt3tTM)MiHq3Fx)s_t!fa?wHK0B&r zv1J6gK0VU~H?tr5NtAi7!Gnn2*;7uEy-K%h!+rWj^0Zcz5FuInsTS@BTyFUay~hzx ziQ(Yp^p9hXxNBvzSHM{%!OG6=n&2@5l7-X)Li+7*eOy0DXZNHmmF8JbUcO-9^3>|h zRS&SAL4@@`qQsKFZEbKB2tETJ&6}P@c7u&SO=Q6B8T*j6b#*Wrf5@NGo?DU4O}wd4 z1Le5gABJCt=3O`(z|bQ7mXPHwl&Aa zl?^r{2E}$Ha~yH)=J|<+6`KgfG z<)Gq>YS5)9YqR_;;SrQ^X1mUlqdo($H8`i1>0~S;$RYlMWJ#h@--`yx(`Ae1m-^*q6D`Nx1t;-1Wt1DG}xKT73Y9H zwCC)9Gq^j?4~Q8#1-wIslke|wYy93f{!t)j%DT3n9`pfKZHYn9GebTXwP&s+v^?~|k}kL|J?Qm0=b`VT zjSvG@x!cJL@8j2lZ}@Zg-}wY`z`<+$=FX#RJ@zInh;?R1x#!_~SwT|HX*IB@A|6V| z+!z0hf&Sg}g(6?iUj~22GShOL;p9sJ(%WpL)H& z1*9o2B|W3mkB($P<>?W{3Qzb?PRXVW?50Rno13G=^h>l7;UjXBL12|~`fX5X&Y%d) zi9!}#4lfsG1enO7^(T!4z&!vX)Ih&*@@@2-)kiHQ0>}N6SX0WB^nG*C`sc{5O~ccM z@SFGNteHpxi`8F94mx>Hg7-qzTYudL9^R*Xs*xo`B6ws8x4xQ7+yk`tLd^_wXq5pr zCY1!TBh_fy@h_I{vaWB%c*^6{N9sfPw= zF7_E7b1W~nUQNyWqE#TiltpS5SQ$P9kY#ok;dx%-qnz2=qm7UgGztZ37&nX{Nfalv zp<~$@VP)hsnt`!C&fccxAlNZ(I^{nhDnv8mQ*)Jip|Y|JHjE99xDLpn3Td802>$y( zJ@yCo7`mVw>0}A44FLIH)od$Yy5?UnIATlNa6?Hoisx@Kx7GlCOWG$Xvd?h*hiE1n ziQeWH$f&oIwpX2Hn2n0wqa zRQ zCvusYX>ol^R*ub7xP~V2Iv(nd*B0ayWA;Se&Kw+IHsa?&MXQzmAA_bQ7?6c2Xaa2s}&Bj zhcOK&^xqb`gumKhrgr`G+n$x^vCmrVS+uvnVYyR|4x#R5#G6ztkUG{;WXK5JbeX17br zdc{Z37f0y8S-GMLhIg5*e>*us=AL^G7)>QojN$8`#o;PmlUr#8%{SnU>u(l>>0q6u zU)x#wtT5*C2gXxT0YdN?Pbj_1$UadwAl~k%rd6Qw4Ym#nSQj~gE}w?6DkXgi<)JY@ zUP+WF(v-x`RVBH;9sPB#+M-$cC#UG1))Bc{hA513T)3XJXL?@IgY9Pzz}BnMF9izLw;Xy~?^k+X@y)j09w%uZiau-;ix1{IR;sr2h3e1GP9Kty#J66m zp3W6d=3y8qqs@y4>oA@1U-2=?&!)~O>R0OAJ2M_Kv!&nyyt!|TT_ldqQ$hmyFvux1?nfpk6_rY~zbl=&Jy{Ty@0To3NE+4Zxgo8u19 zJSOqq>*`CY4;QJ$Bv8cAPII*=cqvc+ zngdg$MbUXFAe6n&&LPzznyEll+WAm(b#@@bks{A>v2FG3l;*XDkD~!8&Um7Kr$$lA zHsZKxV(~&Kn(f;E9jW~FZ!!nAkf14ma~nRvFq!kB!~JePw>~NdiPfFkXU%l|^K{4v zPKM8dBY)Dh0#EBJ-(Ze=@NsXgA=bq-1FieF77beuQP9)SIaQrBlkZhaE|yF&&eD{} zTnOn-t@Kb}^c_RDhp`|_!To*t?gNO`+c6X}xvcb2py_XBua8H3_h;W~uYc({q|7P3 zz+S@acHvIftYaPZr?#858z>sV9BB6CN6YTrto(D}2#WDLxXlKoRsZSEXjg|XNL}RL zgeqNpDbz#7g=OoSve?+b6zU`SCgxSchubg{B04k8(+SgB57O*Ou9&=?ut&k4?y=N( z*ZJr9`TOPI%I-)Elr$u^a)I1h1)k@r(RI2F>`4u{u~%2C*IcX}gO=SKXdNVuC}4>F zo}djI5cJ&xcXD+*U0_N2oBH1xwGF8D#cPag#!+m6mh2ksbMM7)ck}`z-_+cwoF8f# z!gp*VN57J34o%&a^0{JjA2)Cu%=3cVRDQ1^E3r!JsuI&$f|k*%u}>^Y3)j?|7G_6? za_IV}8Zq*7L|Sj*)!;~JB`b)na?TTHq`|%i3B%IvYI<)SDHV?{i zCA8xs7Pgnsiw_xYuY6CQ)vCZbD5*1!ZXKWAR5$DG41Q5V=6n3$p|^{4xN6M^;UiVm zQqr#a+;C)t_<{E-^|@ie?qk;JhE*;3qg@zxyP_1;PM`*b(p@s=;eskb7;vR@ITBj1 zmL|LwbgCaz1ZX2 zia8Hrq)R$nAyafUSC1Y-aey#7 z=CSkG@SKl1a%dt@s78pS3e5_<=*J%V!XACQ*t+WSQ4TL#?8g#@4VUVBz0YALYqO+rdu!dVYk)S zw7t$Q_)Mcnh&yPh-Lm4(8%j>iEUB8f%+TS0+! zHSm2BP)_2?e-JDG8J?= zFk^?-#@I#L4AwUzh;l1nl9e+h@!3F2l+_2Z#2|=yU-*%SWN zsxNEdVe5LhCk`hzf3zSW{x5euxxlUdrbRI|Embhb(z}9JRO5!RpIeg$O6K2}mI{jP z5&9)AFJI#Mov&LHq+_6f%EZK%gM0bN{L#T@R)X~T`Es0ph01ajhGsNwRM^`~kUmO) zGZ)8Ko~*rSGZeE``%pDXNJ2XP%%sL{I8LM0`(YQAC?W{0WS${*9PG_ppoFHMDyvXm z2M~W~=?GW+>Q)q4DyX*^3Gbmnh^pt2Hg_M<`|nYy9(^L3Gii6z3rqun zohQVUL!>=Qt^s*^ot&+Nqj5wPX`I-9jI`&Lo>YnhlO zE&-!l@KQ936r9}`)Xh2!(|%(NUx zo+8NQPLp;xlqi#oe?$aT^A^a2-K(5+hlA}zMAp|3D;4IWhWiH8>ZriRtEP!>cIYlE zpFORdg5x!D(t=|!*&^41riY}eC6 zg{wcI8qK+9fIbMvPQ}}7%tc!EmEOK~;?{FU2h#Tvf)pf9l!i z?A{2>bEb#a-|AWi5TtA7>G;t z(kJ-6W3FbC(pi|J+z{{-B80za=WZweW3DHkTlG>VCIHCtn}2>xqcFN$+0VI4NH#CW zo*weP_{NrjI?&`ucrFhy`YEhVs*wri`)6!Q#nUj0I=V{g?EtyTI{RR~)vS<`3{XnY z^MosvSGT|R)3k6zgIq^8bWhf2{XsWJNL_ z%jXR_E7^4?L_XJn2jkk@xo>&UxIz*sUM;HJ;3sF3Ll<$0|K9KQ4D+?|cN>r;192z7 z2vH^4|MbeCeB;+_INPmL z2OvKl>6nZsv@sFiHGf6=I5C9tP;O$v`bv{H^#g%6=%(Hq0nYQ!z~)AW|vMCFQAHnf(`eitTTb;>&lbL4^jGE;u3*!<`bIUGp@-1inkn3^HwW z#o2vP*m6|0!(ExS@fQI>+YO!PEdRDsK@@3^#j17Iyo4)RxSvA8hX{sv%d(657&IIY zWX!73jz3IVB5+iGhk_ilj$#61?9!(=_ZGvy>6a)vQ4UHzAG-wkzB@2O1h8l_gn--tM?7XQ@k)J)N_6qSU*^nFtWUnc0R26__k(fUBN#-*7us z=7Mdd{OCPXbBJ-4NTir!naqw~IgKxer@|kW4RXw9$KEt%TYeOz+O8Bc;Y2xy8_hCy0$v?o2exK(^oa>g68Gx5`uQ0)4;m_s4&?mS>t&leJb(iXgod;T#y!qswQt#m09qb?Qg`- z0FObcrU3<65p8^Q=c@H>ZFl;wUM?5#jxADCo+xaJ+Er#vsCA2iWtJJJ4QK3Wmh=v` ziyII9=9wWOrtfE!bM&b^0!)o^0AU}f<5~s&KKpo*!%k)pK~5yt3>%f80tveQKoIo3 zPCR|=>J_j%S@wina%OSsnDV@A3%nM++jeaaTD*Xy2 z17{uZep2Lyyp|RuC)>iS!)(HiI(oN5!gLh5ts0_Ir})Y0b0-v&Gu3Z=8p%>J9J|#dhW?8=~bNQQK&{JrwKh@d*v$+iKP2nBM;t zRfC+FxcU-ghF-qs&VF zXHD;f{aAYe{@2a{M0?1g&&!KBV6nBvCQ~;nyVm!NLT8Hz{q!1PUs>4}3zO5u@vQN7 zc|tNW*>DPtoWQ%SU6NU|Fv?_@wtWvSpgJDKK4mI&dQ(nAhzMW+(sDd78RVMeyMm=@ z$$SSjCg-rdS4v4>2j zqTs$=&|91KWY#}SeyoidwK1y4>WfXVcaL5A1+KCu1+#Us!V@Gs+NFd7(FeE0*4Yel zw^_y-4~50zo3qlqq8%nqKOt@Hil8|Y4K1Hf)}8g+TM6Ons%mZDFPwLgB$dMH2Cm3R zJ9W^f{TcQW@ecG?w!oT>md!YBZ(1coUQ*CxpR7MWdi!+U!wWp-Cw4w7=0z#tX#zS! zJ;>A;&Pje0acjQ|zj=mfxIL6mOmOcp#%SnjnA^E$b&s8!A|5(;4azn1m&_+n9SJY} zj?8b|@nCqn6a4hqBUpfMtqs~dJUWWkaZ%&l2Gnp;EBh88{>w3_rRySh?V$HkPgKGE zSulG?QS0j;RTHd(6~Ch*uE{1MH*E~J-UX)B2onB(M508xF)G^fOo1z^`TG=yAeXV4 z3u<3a`zlNC|JybFNrw2k8!^x0@ZRo;?X*zn+})F&MxrTZuRW_T4yx?`U<#P8X+XDt zaGKEV0-ODmf z%UBy>`3kHIEbn1R$^mpPTGyq!AY<8ypBeVKH0 z|8~gVM71O8Z$bM1uyTH0;VTKxekT#*JpUf{58UP7jryji8wgryn12&9_wn6vN2}M| zm%d-ZTU3<@`P6WymCqN;{>;PrUKwit*`xdBs;|06#}yaRYT1HkPZG3o*Bac3S~~^| ziR7DnwUWBJ&9qA2&u<;!8;oA$-5&Zm)@-$JoyRmCk^%1ykRLaoEa=q7Yb7#+$^xy{0K+6{VBVjw9H*5CKB>9#USUt zSt9Du+nNlNrC~aAMvb@rzHOYb4p6FaDwE{jRxzo4;UnQ$oZ`i;jJ+f2uaIMb`iJ9uH&9I z5qMTiFgy@AL$Q(3@rqhoZqzk!peIX>$hU&NuwKNgjX{k+)I^j#NI1{uZDD}-M}lkPDOhW{M&D=|ojb5Xnp zJ)(ew_la1T1gaXU10Y09Bd{7%C(7;tjA{%!I?6`GX;l<*4( zy)9mL&UO=-sw@*oRG8a?*rzFm*=E-y(-cV*W%4jBnJScK1Ab2lqF7?A1_ICvBj*&* z;M%@7DckfUdg^wd+r_}f`rX#chG)%6gz()zl0YLF7he}Tf=OeexaY%nA_PydPEPOz zc7q%IYT?LsV%uH6mNTr`;X6ARO#(i$6*^9+RW>xZl$|iK9ITeG<3j$y_x2rH!P$oGOc4K>n+qDQNIyh z3N2OBY%@39*iM|Yk0aC`!{RR{&TR~E>===Wv(QJ3o9>Wp)|C7kN>6$0*SVZ&!zaId z-BTACipA6ibC9^>vb@)+$w;VR@ztfjl^D)rep@mjc+upN?mrm$e>TIPjKrUj;G2vJ z@=C@P3Gn;FJ^O;?^N+l|JasU-z$dE(Q_ehV$fI`909;OAH z;DiwcH|I{!Hy%=*GbzjGn>vHtkrQI^b$nU-&g#wwJqWAs$%`TH#V8M+fVJe%N;?OS zfi6$`a?|DnjYdLaW1r7ROvh4mUh5=2N^T3(6zn8&&#quDy8r-&$-cdCQageWRl>fOHHaBW=RV5}YM zFni-zD^fa?rY)mJr>Xwvd)3(Iu>BjIjKy1G*itZN3^6Jp&Lu%QNgmDmBQnj5nn*LJ zqi^^h$YX~KL)_5r`u*E=4XieNp|h(ZtIt4cpSv&7AxxdaF~;8u6tr*{@7xc9HKSaHESX0~cJsb!{MZk!HbPNPknugx- z5=tnd(mP5B1_(`Bs6nq93oX=8RhmjC^ct^7k*4%cq>6MxukZ15@Av(kKl1nh=Ip)C zKC@@mteHji0eW_1@b7}P9_w&~H!n~)t8cgM1O^pOH}o3!8c`yyKQkC?J)%_Xsd)NN zS|pFWt5JTPqpYD9`UbhQ-B+Wmg*WidDq6#nM2<5_=_xzx{}j_y_sEYfu7lQJ_c!-p zR))Fv^m_G?bW>pCh0U-_ z#Qhapwxb#*D^ZY!WM2!p8lKJhbriSPItu(Ec8B@4cIR@i41gG`$h;krx+Uhi>3 zKlNg4U#>1IyK&v8nOd$i+&O=XY`C8p8aF=DIp5L{%q5(3sDhi!$ovh2qcwOF6Dze# zJypy`_oQ?EUx=H{8!pu99i*Fn*yZ;MA-Y6~^rW}Dsm}x+)t)!RN`jZAF>|)*B=4Ll zqmTB5-@?75C!XFP1ABiRn?OR6OW8|cC4YUYI#&{xJ#h}p`p;!;jhkfcu4OkFl{1Rx ztEKJ8`*E9s`aS6m^t?IpOgS{bPn3EV1oqapnQzeG+4JLHU@dxM%WDY_IB62QzQ7?C zTjcPGtPZfmw^^`VhTFl;j3FMKsq>2`)pQO$w&`jchYwf#9X{3^X^lhBWZ8iE<}9Zu zrkmu~>xcX4<>3M{bz=Nssu`m$QNH6Rny=5W0G%-aVZvW$KTgc~=nrcX&p*zslzuyR z_@&q+-CbRp?R-MHc_CbH^xWR%5)b93h&>hKACO0)N42O{R?1X^yiuq$UR;ib(#d#w zKON^ilV&~nv?Xtcd>D4`NZm@tVnLm{phV&XC(>sWyaQNdup@P8xf2Cy3-WQ!EhWxs zNp8FTZww(uo!t)}IDSE)OxX>hnt@!_v&lcNL4+Yupm|WQwk3O7p9* zdl{|Pe->t4W^hkxftj2Xv!?0v$vIqT%6rA6t?+aAD`gxvm9S#?99i{q$Wv(bS-4cA z`A$a#`C8a%aoVUAMDc#_Gzh)(jwDIQE1ZC~AG{vlcuem`*O5H(aPX4Vyk*F-CA6ZB z)624!%lb>>-eYl%o}~Bt+rM5HFJ^5lUHNt@l>GVS8Q>g|{TsEYeB&@YYwo``6SfeU(8w;#TMs2a9G3m|0 z+Rfn|A-npcFP4Xk6CKi$I@^X}Y5}R0V1G=3F!aQvvO>=5zH?(9p7u@c?NGv;Yvbr^ zY^a?6@1-`#&Vn4tWx^-w0;CG5TwT8K>RU*0T>4Y8vc)QBl|U?oL%S1w&yA3V^$Z$s za5ry#%1&t84L+yzyZUD;+s>9o_n%zFEiZ;FHV7y-+`80VLDmB{3#;S7ikb=8GVV5BbNh_*iix)Qo6`eVY z-PGa9UZrgyTm8JiW7SYzFI?74)ASPMowEZ61fZI|JnuD8;qG*~Y$hzd<&f8^_UGoe zAa#U4;k4XmYX6F}`KXb2@lOb~@>&i8Ivs|rip`YS{Z7W=!4KyzLT%!>wRwg4SSUyT7LMo1a2wBF ze!%b4c2BPhQJx%C^=3JxDK$?_J8rbyXz*4_J#N&_N#IeAq}H?S8gc#$@_#2>BIhT) zm}%b{O-*VY`ufIqG8H@(vtP8JWyfL&=v*b+Na`0hTD5PloQWyR!JeasFwAK}(OQbu$8+W*J zw^m?`Jw`bEupnDJwkr?ru}q+4nnm#72cqgDFEa`UmY- zP`X>r#KZ`5bu~&47puyAs@V1vvm@rvqt&UmJBbzZ;&@CKT~YUgP_5f*MM) z-CjZ-(JajdGc+>Kiw4GquomCPu{Kh%LB#o??=`zJ#X=#$FXuA|JV>L`s^xlrDvku!>TRl#sYTjkT&6>Z%=gAV#X zar{bg4OA$TayRCrS7(!TExMCKY^>vlCG2ux!n$k(t^lgP3XeSz=eP7$)W!LQRJLyR z+(Laf6kk$dRV@69b6|>cb)Fpg?u^pkClJ6Q*xQ4@PYg8tUomqdOfz@%1XWIXv!q?N z?H-tS+=(Q-3>^-0Qft^RJ7M!dV2u;sxl#3F7LMNfQW9djJ9;Y$rHLy|@8E?4L*SJa zGSYcs;75JrkGA6#C7vliI6Pc_v-pl zn#=74uH!(l&&S($oR!~-bZO-}r)9mcnwsj`!hSO`5--*|Zx5Ep@WJOx6cImDA z(DpUUPJRhcUakl$rIv=ym+M`Yb;%>9HvXk$Xfl_0$#B`CPP$;_g z7B6J?u4`!`g*0%TbWx;%wm8i&lh`85jNh!O35Iq3qZIMF+<=NN&RE&u_Re}us?QNnFC@XV#mHLy{Je1 zEU(-m2(~9~alm6xY-N>O&JgcoiKOM?FA%LW<6YXLQXJywtj#>Z zgVJ*E7a07RT6*R956md5#0;oPggGN%aF{E8%v)Jq0@zC6S-o{Z;>RD-MV(|WFWVZ? zlc(p)N25Ch`d+2twP0A}U~7h%U2hJyRw_5<%O+op+4?Wsf8}(s1bR~)x`TD%Kcu(N3yS4a z(_pfECg56NU=7;4jyo}i%76-xVbN|^jF@u#Xp)y|K2vt7FE>f9YQMWg`?QtNpBj0{#me~+UMZY$+-ak@w z_ns~sglHBgvI#j16;Zy-y0nV5_e5nhN-K0HxZqjZ@PsezwA#|hx*LZc0h@kJES74} zFzfmKx@?2Q%ztP9Du+A~-H=hOB00-Uu_S}e}2-G;qMH#1tu!>|4ROOQ31D$o9FJDls%aef#^{dAko3%SG zj&;8eFG9Es4)ie{y{LsvbI3hoyD%0b*JrxT>BL4urVNQ2i&+qFE~BVCpR|y|&chve zPa?$I4qI{h){VOLl#-6E_kd1IAp7u{F*&~WVk+p&;?Bp0+=a)FH$$8FhZUi}$7-Js zb|)O@jk~qay!~m6digG^z2_xY8?9n=HCQAxUUdghXL3@4+Q)C5-L&1Ovr73z50Ak$ zm30d>sjR8@b(1PIVm~fLgY9F>efC$?VvB_19T$k-pS(R}Xeb@Cpl3$LN7ms_2Xj}92J1B5mt)~xUMstk=|+k9nc`EzPb+t#2tjw7 z720UjOPh~pFpim{sy4BoOI>1{I=ZhGGY(8yM8j!~2V6Dm`C)qYCQ?FAEqUf@Pj1Ie zQ6S#0vWGf$xP*HuqIH`KE3BICWN=MMEQvv-;>wvzinF5;&6jF3zR+Ta>cOr{K`BR# zcNHR!3ct^I^2_jA$!@Nax9wg|^K(Haa%Kv8!q4DlT((EKE|9}aJl53&Ai|>^*L46N5e^a}JiC8QJJhchE_777N%hnHNQQkRsu%1KYyH>4Zhb3%C>)HaB z&yz(iCECr~kXtvPh(SWAI#iuqXwi;1X<>sBgD>d~)Zr7pO}&n}-q_VS`or~A|GOA{ zKV_{fezewSd-q^d}3iFyQ!^bQ zg^*N|+hcY&;-u)}5uN4QZ(@`y{5Y+V0mSA<B;1Pm)D|d%s!E9dVxM`z#yF{O}l^J`Vx`dqGBKNdZzSqoki}a6vPNcFG00C)nU7|MuIjBSHFT z1yMRD{q#M#2!0#efuVNaZB|+=oupF)%c43qv_kSRkzX&`LbQif;#>j!^7m=hmST{T zcr+J??FLp!@JbA?Gx$0*gXvRx%9PkH?n@RWSa>>T^gTPBOU$94jN@6Vg>!ljNOFQ8 z%lnVHSoF*WZ6(L_&ml?4q_vl#*^nWi-MmGpu6?$D!VQUI$};*2 zojoiK%wbi~ZWez!{QUDe+Hnq8bDM~{R6{|BN~QZi1ySC!eNG|p(&&aL(|p743iIv> zd&?`9a?leFNB|q<;Bahwwql_7;w-N5uJh=X&EWZD`vT8Gd#Ryf=ro(7_GX>t%v3PG z6@NBI)ghomy&pC5r!CJCbh?5wb>o6vQzrOs*r6wz>i6j&08q>?bPA)wHv@jWXkXeb zqDYH`R(;*BbUI&SoVbM1A^&{jo5%a_do65$Se9743qRu+S{ApdPhEg`BV24;$RCH= z?onwm*XJFI-wbBzEHyfBuM|fkD8)7Vbk|=vlF|L!o(txEy z-7HjMF_4OLOqEYrccJPM=U)-7CoE<%o%FWe=e8k^)Tui(?t*P4FdS5KR1HYD7kpSk-kJ|^{5I!EUv@sRv^S3Mh`l`rx$S4pq6u5_=$S??cWKzjZl@u zJV0hLt1~VC_{%02sm!s5y)L#M-J3Xo&jjaH1v)LcQ<;!9;04|0IAV+bfvnO2x{%YM zPY(b+-w(O_Z_2KBA2jf_YLdjy<6 zzj|I0bX{o$=L&2p!-Em!3HJ4sMW?R`uf?MmK=K4a$Eam1{j8hah2--`HR?|sde5N} z`zzXpj&}*w@8p42SUHhD5@21MEfth30SESV2Bl9Mm&-WjU{o23&7%{0P{^6;YW33c z;4i&9!T8sovNT|Tx|rRdh6RGp0_Pz>CC~mE9)mvoO9AUK7kF@?glXiZZ;+aS!G1_8 zeaPQ@IjUEoCsw#H7~HMv36Y225}0);ktZu-O4PDSQu_q`Z)b@rjm$`~}^<-MTVBuCe<=KyJeBaSlAC>Q-S#O|KR& zCv10ayz>m7`w$N?Kw?O#zU^H=u5Aq?GJgo%^v08Ee}9<2*r>Ms^2 zPToO-Qoz-4sE21+kx?7uXJ3cvsR!J6CXmO(-o|s+IJ99P^yK`0W21GdF6#Qzxd^U^ zxZkv`2Zt7(S%@~RsXAEs%at_`E6?JB%@9ZV?eaXW zn^!gi4|K(`GQ1K}bdK`nA&kTLBX5(_DkfaFeDLZq<)A#qr@yl^$hh}5QDEukl-?5c zNIBu4L%7)i*5&(U{J;UROn*c-Jdu7X&){z4pPYWy5bC*UtLL9mF8ic%d~ZLTk`!@@ z3`#SssgYc-AyhYgt#oHsHDnSnym2Ze+2{YLR5E}r6I@9za1Dzqt51|pSa4y1+$yc> z7AMDk7*C!&tC%Z)%rfhTb%y7xeB3^$g=w#aq88Qysl#Qq1Ln@h19O~U4?s0M(T2IY z&evUTeqWJ$Z|ItZm%CsSui#Zo*SDGN2#3m=sMPjg*i3sT)2_aCy?l=VC305X>a3#i zeYLksj%C7)KeZ^gv6XXBsx<1`oH1yZn9eqqu){C8m@L|nF1ctl0Cc$ldkCp`wj}Kg zj6D`my5Y-w1G8?hLkPwf$6kMH9Pg{M=#}p=a|W%RQCX}ijT9roEX_q!hE@}{R;^Wb zU{f!mV_RDih>gHoanF%&q_i<)f9RSwnP=pkFFUSjc_m@R^X#~hz-u>9l_~w1QPD+S zid?5+SaiJUTIT`W>!M5)?b)N)YzHD8cjUI9B&K*&71*X2YGdzD%Wb1gzQS6)UR%lX z2OOK#V;{86x&{&tK3gmC{dMbNSd~yKg32g zA0_Ky`BlJG2||B=qO}>?%m6`k=I96;sWgAIvJ|y&YwmQe-OX4<3cCA~bGF8+tNB@W zaa@zkq}@sSz$~A`D^&sY+xFqcvE|ySD~}46x=`HY08nru{-b$PdXhv%1w%=I(w#AH z<&mFLmQyzECogHEw#E~i6#fa--79u7rQ0a%W|jGjD^n>??| z4~ZMIZ8bn$(9DuVG=FJ$)R8mWmAl`T+TZi0*)$K$gmMXX^4-0U!ld)M(bAaGCO)t` z=zP5sUv507T*0bz|DeM;Ly1&_A|&Hxml|i=R#qmHktxOUqlXX6vfDf6_Nzdrl4Idd zcG7kH@5<{u^3Xm^f4Ej?&jsT*@V8vGBDvVZ^E(#4sW#CA{e_bf-bh4N+S&+&mvUk0 zEVCdIqKgk5a|nB0xcZyi-z!`Ys^&JUk-J%MKvS%iHMh>$lK9`99Q&VFBA(b(Eb4-E zb(*EWmC-;$ap_TF@fcn@LFPoaH$H^{OvH4JHM&GBA2ZQkddVRVJ~dAH0ohoA_q>RR zi^u{&r}dFN^lm!MJHB#axcXBE#8FNe`y|5=+we8$iFvLh^SH!fy*&Nqr!WTh!8RWu zjKq3Ob|#|v^qZ=uuu4#ic5_@|k)_fnpf5`ZLe)Mu@*P~UI5o6Uj$4nck43nXV;9MM zh4#wK(J(Nlv{YXU-D%p_hh6mysuv-izSjDqnS3wnwQ=>TBkw9r=YmSEAXxM?jtW^`U1@5&Y2Uc=*Z-6zCtTgddBKiF0L%o^PTOw=6dKG(Prb zWJMUu>l7q8z9*GE>C{K43S(Z5o>af&`xuJG)!!%)E%6m*`D?MnBbdvyGB_zaJ;D>D zvJ0>KM<25B2-CCH?wI!5rTr`__lZtwk}x=Kr}&NX)LBIs)L(+OY?#RGW`hzf%W1!J z6x#0iF-Q||AsY+$E|p%vWiI)ak?YL1;UJsuyIZH#f!=HpK5FW`r+lm32VZo=HR6MU{rM!6N^LS-ft+Vpx{?qPGv`NFFyJuNc zJ4$)+-S@<#Uz#iW$gx-j)-mo#6S;e?hw4+NoAbXdg3|ijQ6t3Vw-J2&^^zkm4_eOD zw_OxoyO)dNQmXY9@R@a*36kTsykli?LJAt4vl{;Ud{C%XAuW@TEQQfV^2Vchs^TY>gRSU6K9}}SU1_R%=!bMd&{e71_D;z^ZaqFn(*6{C z3vECJV=Eb{Bj2XNubMnks62FEJQL2L)LW{;OV4F)LP^qm79@5*M)=jzpm1M~LSkqR zgO2+@Zye{1@ErNqi&FW-Q$gV$_?cgT4?nqKf4%sXQnoK(Eoi02zV2Q@YYNm@*UTbU zmahpQEn;AtK^&lx3pXp?+;@1|S#*=xPUU$^OvFvefD^8zSj?1Qad}mSPjGJN9sgha zf2|fzrfHewgNj=^bLfB5X%>FS_<&VvFe}1Qw3& zJG_CJgg24Pomn^cK2|#C&V2mU)rdi#T`r`Dv4PjHrs2ky02*ZS}pFYNaQKnJPBXOi3w~i#N^c^Dzfu%_0gUWdP-?|2z z5zMf{3zCVW*M_oMVWEkgk4pSyuUnn#vN->LT!8OgWsz_YZ(P<%m59tKtK9YsZD_Xb zB;zPrLaonBK_=Y8h-p$1lR*f~frMb>7@W4u{$uw#OucktDb+q-aXKG}-03_ukl!8tGHqkmOYM#u9v^k^$#O8_(W zJy=M@HtPEq?EcOTL>!s)K1MAp(o>oVfo})q66Vf&h&8RrKPmLc?OmMIu~|*rx-c?w zmHPQn)=scO?vL#Tj9K)W_N@f{bswY9{h>wc8Lwj;bz_<%VRcj?Cwfdh zRaNKYHk0xA@Rbc4RZW;>HtTz?LmB8_y|M=`;gvz-TRO*k5z9B#Be@T0@tfh{hjiTM zNr4-!Sh6h>k68Djdo%h-u~rOBUQ_Y6!Qn6iH8lf&y-9son>zGFY*7WZANyk# zcbG+Zq_7e?aV^EcDffFA=9hWY&kPG_!;4PG$G31{%w8;ZyRD($;9?x{vG04pQ_+OJ z!`kBr5sU_0rBi!$$(3Q!OywQ>)u(qeBwCj=B8q{yAaumPU3TLVx8~q#Survwo2w&( z&Hef!6Pz$_vf@$qa_E=3%?#g`8sURNYgoVzv{{oL`yX00_?{?0 zQ$c+yj%&Y!GY+UU3*~??>(#y}$O%Ltd~2>+-xrMXtX;ow3BsOO{(gZjRrY?R8ItD% zuLA&trM^Ukc72vlD9ZBbM5{nH9xn1_vQO%5A89$R5URliYtpTT<0Gyq(vmch`BKlxhee%DjlLO}xYV=!*_=y8*V2D|7NFsn;L8 z6I$M?)TMJ1nID(6%_H2U6Z`SG4bOzVhph$-KpI~VTV#<)dp~IsJjndBf>VU~6Q?{P zwm9m0x(@Bfi@X?Ne_gt5>m4;xX3_Q3!{4S<$07+J$y>mF;=w0SlGZ+HdX!t|C?Rt2 zrZ%ll)c9;<_>GSr-G=w+N9(5?GUJ&=CjMfws^kIPysX*#7i7bhv~%UAPVXUagcWgK zM25uIzbUSF3T{DKOF>sLk4HY0mY*mMT=U-6PJHEV_PO6w z`d^Z(z%LKvvVF6s|7ZXH)CCB0fXwk)S1!9BWaG^D3Aa&~m{ce8s$1(eNWnO2c4~f9<+f?+zsarqaKH${RGN1SLR7t#k_p%2CU2tdo~Nq~%o>Idz1L zA(|tdM>FwmB5Hz=Ut%bd94`TP*Q(=B((?o%emDU*>~(Uvo=|frGaR6 zCW?X-^bWuyBaLicx`^eGe{NJ>)#VDmQk}Vcft%&%6TGK%w$!^YyRU6#F%AV9{NbGO zr46)rme|ddNZ)wQedP6&RsfMdoeNoeMlsx6IMblDFO1?xj1p04Z=y>Z`n7zch;csA zSF{A1qqV3=wM0(6BCv?}bzeL5y-`B9UPah*PA$%{3O-uEvHim!%dy$ zQwyGqm5h}i8Chk!FUPiS8s6@KY{X|b#SA^g3Qrdi0_#zf>i5g!1^n*!u$n4d1Ppc@ zf4;=3vHYh~0?y<5l14sX{$nEDQx!xrE7pC9odUFn7Bfh3Hy(T*uC?f!8qN1iHRb#z zJE6 zr`0a2nJPCcx5QY6`g{&`V?Qze(t2L(!uLvucQ8V=Sfb0v8)w%;?*KJ;pVt4ow&OrB zwp;-hB7n@Db9lXDaNBIE4>^0darVY%YiF;2V3e0Ap5x2-ukD*`4d&`%(O@Zw%%mXz zK~a+&nyz&)O`NZ>?B$+aSel+&RM3gkJ5a}AYqAYbp}05Yt`a!aS49)e6%c78ov08WFw2ymM9N=FW@9?Z>npACIOp^{J{Zqg~g^ zg-Q@g9%8Y#*=&eIlj?E4LhEd0@$=WHsk0k)epk5_YtZ5DeFb*^naq1Nv2qVxTMc-$ zCO_23L7xv?J6+WqWvb4J&9^zqGW@@YQ(7SR zit`#+*Dw3TXScDDweVu%w4;dnd&iBNd$QE3ifvn+!WnU>M^gE@b*!VDPxFp{MfY>h zxZ8AsK)iQ(k5xvQhsR$;<=y0ct5Ym-kX~IJS;01I(RMI_eMwM(H59uS$G$p}p#B~$ zSh)3=Gh+gy{_5DdY$jJBOwS)JYv?#nX?oh$UGqtebkCsnryGTHwr%MiYGL80QDQ14 z8;dZ!I|yhZjY}`kHx>KCb(>9*ynWk&$}EcS;638R!K((6_0h|YRx;4vS>io!-E>Ox z48}fT&mnn<5t8{txxO{w==7-p2Q4eK268B_wU-a2*@>&b*-N%k{873?GR_CLoe|#K zil4fzle%CLRPpfYt6c74`BMs9w3^p5X@WgsOj{P;`Y@gczx(=9CK& z06JOcS1Wm}eILZ4-JC7pB2SLGG4$5rMV}wJ3299@dUt$v^Tm&fxhXk{-IrT&0Pifq z06HCgTtB&j|C6FUuCeE>(bo+VW}H=>W7-Ouef0kMb~|lNc9W_12dee2q&cRK?O&c` ze{D;>R{Xs}D}Ti-R=DlJ+W&#aX3I!<2739OBrRqw)S**5>e{k_O$+g(|Ill~*--Z$ zg76|;*%#D`zs^nl+ShznYwQ;T$I_OmL6;Qep!O29LT1C|udH{-kbGZLhcglbeX>afZf$7G?@wIvzdQ(Iy%S8YDs zR%UT(zo!toc!tMrurG-=N9dn5}x|`$Lf(nDt1K^W_G-+ z)5{#u4%z4-{&QN@nRdISv-A0xe_5{;t5@IyV+DphZ0Vk(F+w6bho;rGQ^*sf8)9RYLoxC$hJk}G^dCmN5IDu~Lv(U4n> z(Mw7%`1bpk*v3wH(&2Zx?-sy}<07~$kOzF+=hrzmgS95|+B>nWNtzK(cmsn^Sed2Y z#VDQ~2jAMOvz~aHN5b1xq(}+KhHu{3_XleXY>BeW+=js-R(C$TUkiFk>R3qbGXKAL z;=Xu+y|gF z6aEUGT^hY&$#teIYvVHYB&y<5s7V{oFd8saRbUHZ`ZK`x{idh+`Q_eFQRg>G#WiseNDcPp*JM`E1?Da{u@E1F88a z*C_=9<+x?pCVA+AbzMysK&N)J03qGL8q87Gq5%U}O)sp%1kk!BlRa=E+kLep^?4b`>I^ z!SpCCdJ&UuY! z1AAE*#);ZNk)@6k6v>7TiQ`jhxzW-~$(JDENdN&uxa7h*y_X@vw(p@0CxO5P>$;sA z7A|PTH0|#=#X00HQgUvcm)Z%WoD$}k?j!1@7K16pcpQ^=pGo_&O1NM%*59DFlCq0; z#w+1twuHO_5q$mgwL1&|C64#7Dd*oA%h!2<@FWt+N;*C^dWqf!lp4p616qUll~@5z zNvlEaDYNd~a~m@eXD3t@&JFV@+V#HB`R-Qv01EYpEf*;fSPygbpnAa9=M#HBIC?(VAj?LLv!)XfJDx5It)iMgG0Bq^{XB$k#f}u@rq&*Ma%()-`qsX^aY0 zlj;RmJG6;-43q5p%VrQ9209WfF&Wu;K=IuSk`)^vO~eftq&BhhnbOmT2||o3OP293 z3Bn@$jBggdP6vQ9B~GiHM(>`%gJQPsl^M1swe7l`+qWX$@OqNXEIi$VE!b?JsG+FQ zz(oJdwfH~y31}wFBrmFRtiUM1)J-oRMF{sR!!}%ou>01s9s|?_aK_Rq4tYwSA=;Na zC1be)cOwwmDf@E{;xuFWo!|3H0VfJoJYG%+K6;_Wb5v;}Xw;~g5<+#&3uk6SgrTsE zWI1pOn?R=rPCN(R?t{D@AZ+bY!y2+>I%szEAQ9}jqmQZET^$$N-T$QvpuZ#mw3z2- zk>SiyuLv{xcI^&y20G1&{2nQ!k>yz-N7k~w(*?+_WtA9M`kkn2VejEs=Ca3_b0y)3 zwBC<9+f{_*8;f#qBl5^waVv#N`b3fFFBbThv%B?TDV@?(6G{r@Z$fpsVJ0(RT(<6V zv#R~gK(f0kh&Zz8J)m4hamV=E8lgF^454^kAMEquy@@+Fu-28E<8aNf^eM=O1+|!% z2&!c6jxG17TPh9nrsKBVJnyA+^K7!ehR6~R-MduJ4C~4 zOGq}fx`t^lGCLAF4aWnx5(Awr#3Rje0;a_pi8N@9N)zH!V-RI)E1qRZ6pkJ z?Q0s%#Qryt;-(H;3u6Rq%m8A-NK}6(_E50cx3>ow9&P1IbV( z?4I+ch-2wzcT>S*o;@vv9>#T3grQ*bPO{lC*YMq5XUK*i2*Y~s@FwU#WHnf1t>8t;%ddY`mCAw0b`DWPDiXU()H+Uh1NX)x7(NcfLi3CbF-0jo+nVo3hwASS5rebB_uB+Lya8mucJ?j z@oN*Kw;4c>o!Q%StST%PiKL%omQ^;%qYsZJaH$O4NS#QarWA@qis~LkGl^<9gUOce zERJ72GJ>BiUy|c3;uHZpnZF?b{4!&v3_6Lk;{uS>fC4|YYYUrED91Y!qZAXP+|vt+ z0Nq?_POwOt#Fhw>e{&|_1Yj2aF~pgF226-6m%*7VL#T|K^Sxt0qb=;Dp5WL8h%wTd zwA_hPhVFbUSQ^t5m(%I$beD%fTJ;WuZ+c>9!@unPOoTfC!Pui-3%uC3*_wzsk#vS- zfTtN=Zk`1S_kE$lS|s%kATQ3s9pUc*2jaim)Zp-4w7BuAT25r^<}bo!%N ziTcaKPbEhDT~}%pz+F$eIYngF@1A7x0!yXKA%k|7`1&MQE&L*8ozBnKqio_{1H>obw$f<3DJPQvN-q}JPey{$t%kW>Yf zSeKZ}ch%G`B#$l=MoM~-k;)A5HpQ*7Qx+-P{BCbYsKF{;CJH@jAX}z1x=t3pYm4s) z)jlz!gIRLK0Kaz<<`W7l8iU zAK4`H$@w_MEqKt&FM9wamGglG@+()V?@ru-*Kp(l?H2WI(1J$&k9&aNCZKT(l$Lz< z%;=g2(C?cLXD#`wHG4l06fas5Bz93xogO%rhFSKUqrgLLTj?oKpgbg??)s3c-B(lcoTWXxv*%acI963s82@XyFlr zBMZ`~X+i(s;=1yB(`{^mRf=KM5wj4~gIWFDGHb{OEi8N~J2=9oO*7e3U-_(Jqw1~_ zGCX0+45H7^ zNv$u%5gifXdbO|ktXOU`m+-99IdTkHRI-h5C>AJRg?dPnKvE1D%X;~p%5E}_DvrYN z?c>kR2aA+4$~?uCnhM#diYov9?>*hGcmwCsO&EYo_d&dU}f2n1oKJZIo$ z=^PMged|n#1hVMOO4V&;t7zOIA+XwHg*;+|IN};EZ{Gq`3iu&cG465NT{;DXz-P-_ z8rAZl%ImZ!+5eW+{mP%iZ+%QouE|fe9eTYbtSX6$CS#hG4p17q0`};d| zQH7$5?`tC}-r4s2ce??fWY#}BF7$Ei$A`OD-5$zIFiT9j19{I!7e;}}$zM8tDG^SV z@p_Z}y3G;)T0aHzuaN~l$&d~@fOukyaF<^6pt3+V8e4pkZlKKHwjBpwZPPsffBH`l zD+|aOBxmQ~d+6)v!sC6_xz7WfIm1Oqng1Rsu*gh^fb0Ksxu1DS(85a(h)&UmNyj3Nz9n}OxoT_RXX%;KHO|F<5%7rTr2oCVrWUQ?m#pbM9d zW~UnjuQKh#mHXuJ{J)t4|B}D>=i2}tmL26Yr4q8Cr$BCCseac92r|e~(;*wx*)kDE z%sHih{!{wytL!^fpWQ!@l70poPX}f8{rgq&rZo(B(soM_r4`TK^)O?RGCsHFhp!W! z-q_sJc8rQ}%K%1h)vCrmKKNqJ^A*A3F#i@>>-)9mQ=U)64@#CfQ1Zau{Bx1%HnkZyW^TlzPD2-qLc*}M2aXT^dd-; zYC$CQj`Rou0--2Uq$V~{5Hy4$RV9G*9#GnKRaj9$gQ0~IWdSLn2!s+K@5R;qzQ6e+ z;q%Gm-nlbp=A3!XbIx%}IB#g|439L`tlt*Sf^C=OOc#hfy!)6(Jnda5dN47u5=pmM zdG%)w93M{O^oue+1=L11(kto!dNG!{c=Jn-cAd5ff3_m3-}B(!&|20=ZN^ zxyQ0>+qf#Ej5|llgT#{o)Gf9Xa*{m(O?m%L&cC0x_PXp-pCAD}$qs=SK;mq7<2Y+H zmeRXd-a|`J!>1%Ig3SmG3L(glV@~8tYD?mU%^%z9G3WyPghK)ii zBESgtUpfDG3_oE01~;t7Lw`pg!93G~$G`P-8lp^L<#uu+s`~CNB{uNn&xp4wZsQt+U(}J5a>(d-K6>bw-)LPGpV6B(?;mgRDUc~>Vj>Da zdha%3Ya0h_!)_S1Iy|q6BXj61Sw`~Db z>0aVHy^3#g=$TG9DikWg(e6yOFxE~JqmS3foDgqr8Bj*w6~`8U0Ux5&*k=;`=7wg3 zRk_DJ02Fe|jJ$mr{kJ7n^ql}NCqxo%@xe$8WeNxFM-YmFKzcY9j=j&vu;+pxSz?w( zWaY2LvWNG)+1o-*C+_Y#e$T$!X5YswscCOAc8u2S?d{uEa4SY8)ZpAs(? z-?kX$cJkP5L)0_;(`Si>&r}bV%9z}Gc-!Xl(YX6EszNsV9;^1=mZ`^oP&;~Z;O*qt z`eN$Z=)(F!%lhNqA>T*?iPRM>-|9s$PQrIFv}bI3e$A=iEnvodVcmkA*RzuitN4BB z&1?%++P^6in%}TSg#vynhm?gRa>oZ+m&qhE4tVycEf7+kFed;l|=YMkIiUb(F zqC8;IN)1Uah{}GHvnW{mtnlNqrj@(&0BNU=IEU?k2H42882;BjAh;m>uixJzw0-ss zzKRj6Q45L40ZWor{3*6ifP*Ur?)Vd$=O6vTKUMg_*qI?EZy|KKP?sYtsCGxSl@SxAxTKGV{K5ab1tOqF zJ%wvy^=drJz3@};BaLmC@(J;4h4lKZsB4WEqPcO!fsnYTX!}gkZ+}mo#@<0bs2?>x zal@-wkQL@R zuO+x4i-e*N(3XT^cfF(E1$92Ylpdd!ad3^~!IlC~NmC0D?D`6H>fLWO`(*iObxPlk z?}{&~d;iJ-EHh9->-2`duDByY28+4h#vp)F?fYgXSRrmz#u^n$Y%BLVX6Gkcs z(k8Ka*R?BBZ4vYXy2tz+s2{z@UGlt8j?g*Cg>{vM@QEPK5vds%H7^^J;^{^c1)PB- z;KubUXQ_-+gv+2B>XZ8UYOVwbk z-1!(szkut7cFgu_-8xTp%}crTd@%nqlSyiVg|jQt1~zT}AZHTmmNfm)&Oa~-b^*o-)^8c+gN_+J{&M5?kK*2F z?7Fdy*V<)1amNRZaPP43`=Ey*A6O6cknwAu6=`v}s_A)yq|rkr+{-kgZWDg|(`DOD z)KoAYlF;)+=m>7;?kESgAM&pIQ3-4kG;^DZDn@p%6xya6hf0R9hg_hv{^<=1ji9!n zAX*7^`*~k+tH5%T&*w|j(Z4Z3smq< zy5$zo#Uplf218ZWEKu;{r9}f7fN5;VuA_ns9yC_Op^hWed!!KtD7q6#<`@T+>%G!W2veAM;j%*PhfveYAK z4X3=>r=rU!e_KfjS3h?YztVb4b_R(yu}u!^?N8A=?&m`Dz-QEq*1p3fo(VZM$+PHC zw7`O|e&_L}IywZ$ES^Knt9TbNy4OIzWXI8&Khg4NX4$5nN$Eo9(+V{rLZES_g3ein z+N?I#PQ`DmIMKkAfn~1I_0-{HojY}M%{S(7dNPv<(=d@<`2p+vbzZ;OXyGFKU+AGc z)pulL!;1$m+LG@U#^l@-mrY%>>%PA*WxtxYq);@!by_F?aZ~+9?*dI++6YAly-Nemk%=kzewCw(wc$iOl_7s#+ zj6h*NC0&d=jVi;usZ**+AyP2opI%>_;;ed#`18!Bj*oIT%Oqf3GUM1WKXadLo$InR zU&6rfuGDj*f462f6ht_{$9Ie95OJiq!iWkmHtnekKoP-yeY9>TWKD|c3Lv_Bsamu< z?&n8`ePx-OJ=fzoJPj^WdrhN~ZFtacq#(v3d=*A7BpfLYSKbQSS5{~@e5~!lDK~2O z7qj3%xZd{&xuPF{S=qgZ<0sp4qvTn|t;fcM7j>NpD?wLBGs-8+-=#n9E_0NxYVz}M z5pHg73E&~l-UyZMzI-~=Z^Z3NUaN}Spgx#~I$rD4Z5z5L4-G@R=}@f)+{23qDo$PA zB3kKa!rz-@e`@%4RTC@}(4}5rWzG=@x4Mr^zVV=ITZQ`Zo#dS3!Rs)6?(I%S=+bZ~ zAO*o|XF$+QTfOfq2ygqa z`V4kEW=FjO9lOLSCW{nDNjJ4$Re0=Ligkz|} zGdr2@)-XsB-Y|BquJfV?Adb@|83v%5RhcWE?7tU zb#Fe0rmVWH5KG$jtof>?jYGHi=d>i0Gam@b!2kxUEWM@U;VPwl!NA?zKmL!6D36}S zuj&~k6=z?>*HoztA{5V*R-6!wy#Is4E7$>Xp8KWTCErPluFozMxxe2F=e7mBO=i9u zh`mTox)t&_<6P>(+d)d?2bc8bxWpMjb9X4|xtze7?_7#E&N4#P5B*27*YzEXRJMaJ zwHVfS<6!_3A#Mrgnn<0Y22`339htU99k9yhjP^WbqF%6|dwxi@Vp&A%z@%@JCN<&A z=Hr6KkF~wV!*vN04Wj3O@c^z%u@5F~@nHIZz94R_3t~;@R1~(+qO z`6gu2WB%1}lG<`y5U)h~dnEmUD`G~!TXcFl%-a1&6TpY4G;ylDE?1-*C|_?}iMh9KPJd*LGGg1bN^}a!8TsxH>$3fPX*v%mH;;d5 zlJR!#;I6KeOG$*HnZ5W7&kzBK6r{;&Y+vvZmQ?rHhdk9`0SJR5f4(Y>9uMb)bDC}) z4IvScIb~(JgM+E=WIPb@@^JWJ+Gh=U@%7^QTD=j6Kwiyiy(z^JKjy~l+(bF?z9Oii zCZZy&@v3)U_x}m^ZrB@87jm%xUlDOTWL+&pesX$>N|LA?)_k&U5V8+sVML+i*N)C? zxYH^DkCqutzR6R|$0_uygi5`rfL*y=r>sqNMoc$LPH#ET$Nk+{js6lS+hDQI_ZUUb z7yC9``MfqcifmluMXlv}xTU34Lh-q>)P@QGuuGaFmgtC|{$V@PuM8{QM7?NL=#%qvb z?fDivO#v-beb{nmd~l`3i{JoT2lv2B(TG+qYI>Ng3ldVDt_zMY`Td(BcaW^=eeJ2W zQ1kNUr{T+{t7$}cOI5pQ>kddOS96<0ria8vXimU(Q`F9A0)H#d#}g|C=mn_o^xJJ- zqj+QO>>n+9@qJIbuqW^8KXY%PGL9(@^OfjUpV>4(TSSr820gH0GHHLgIq@}Lg2b_o zRPG)cPI>I%6;JM4M(%KL>_^_aJ1jgf)LwC@HWx^yLe%snMv^Y_Lc_hcSd0fMK~;g1 z8W_9O(S)o`{elw!*Vr$G>gC|TmU@QdQ4^a%uZ9N09Won&auzN?7ok-(u@Q$}Taeo9 z=@UsG(^%#zBLU11swm8Zo!601Q?1Iub;PVIH-yp3`SVauAh@ev`v=Wvgz*b>ii)@@1b= zM%ONHP5dFZ__K?qE*B2qGoDshw3GU34ej2QOF(;`ZKveeIC<((tFMPGg!nKusGNiP z*t+vQenrt(GA_O6 z|COsZ5M$6Z^<}bm?{+N)hi>2KF5AfCR7p<5P0D(oh@QPh^SbrN`&3z^d57jcFTNs2 z+2CD8SEK`Iu&%wne=BBm2fKpIb4mwN67_3#@bp-j-jBW1xEA_xZSeu&H6hwrRIhQA z&>(!HnJ!CNc9cD+xu!a+Y~uj*>lu{_FDZEU&MRUDOx-PuNzSCG*j+F(ywIGSjR)Pb zYToKhH++5-UZ4~2D2vRXrdP#tZ(Li`i@s~KyA?tmI6WkAfxJVRXci2yTGPr`|MS&_ z!S;6yDc}-d85kVIBw2J({*u6P`Zoo$E74!w&{U1}Y&E3_$+uXM9EOTFn~9c?Ly&R0 z)ZrIh7=wW5h;Fvs9g<_+s2lrDhY8m!(TeD+=u1?c!3BGY5H$_6$fdy1`j)YuWcmG^ zLgtWr$$f8rYC$>v&$~!!*KnNlqPGMtYDfC2GEED`gvS>l>Z-Uuu+Lv%j*Pt-J7=4lHP(J;16$Ya7EP(Qa%gw+V$L6H-Zi8h>lRITK!<`ZN~lKN zXb^JT3^OhZnznrSDp(L4wCUwHF2{ds*m+2-hIWA2nH%@lU$RFrHS(@KrW>qHXS+R8 zQx4g;B-?$vHy*hoGFT{goZ7<=T*6P4R2ap=&z*d66^ZO`!!5$7Cc{Gv_H!Zh#6+lL zB_p`yP-vydX{rV_O}4si)UBj^VnHsYmdKe(@fsD2k3t{6pSW8Sn@((k%0tSnb}ctg zg_sJUKoIa}i;@O4;`=cIc{2cBU04xLr7&)o?|`Ve-^osc$1ikuCkXhz-ReL%D#Dgg zh^a{4KD3n5*?kyQ0H30JX8B?yJRU^&sBddy%DWi6Owe*XHjwtx8#P_DPCmP<6KfVq1-MY>AYk3;q&37YR{2=M&2#a*?@t3 z?s-Kp8^j?(AhZY89>je0H1XJ8Z;evQ%DNs^)Api( z=!9tF6drdIi#;K~biVta_(DQ$8MVdaWyZ`sXr=A}G1sIp$`N-*J>7PnbeYd5@`p9x zq(!K{oS!XdJ_ka1;XTh^D(p{wZd3Fhz_jFTd;4j6NhtmUP*sy_k=ZOwcEvhQKXCvF%IK*c}LjhxnrJ%NA||OIsAX_n2vxL zuBOqcvM9){v*5|E2u%b$7nK9n+D8CXERKIW#_=>pfvvw4I*Ngd!r zH~*j8K$GXLL-;>e7O1ZL(@~nvkmy0gvNv-#AG&xdjrD)7ymfpJa?GWtVH>dq5KE{u zY_T!cPkLfDg?JAi$1cXZEwb^DenCgf;g<#Q^Xtv?bVZ1y5rpapbqv!^$;UUygm8dn z$a!klbuHpA%l6+dYh~~ODxbzU=TSq&Xpro_5Tg5kdf;`I1W8Q9kp!0@HP@tAzXkWF z^xn0Q15?7CektC3cyNe8u;4uS|NpB>1_(h)awOB&!?o}3J?-mR@*TiAkhj-nZK(X? zauOz3P59~qc92f*K!5gL0N8fZ-R0>TjJpQFl74kk_%aH7`d$-8S;^$ohio5i_W$GCf4BJazgt9>#kMI_Nug+e7NE|}!pvaYq`lOlbG5m#RYz2UTbcpJv#ILz2{HXA&bDj$IJ9uI+ zBvegYTP&*@e(Zd*31xA(6L11%@a=rLd@=I>iKB}1-efvI-rvl*(|*jaJkHhk7)^o7 z$?!@B`_JFY@R)5vD#8_bw~J5mpHH?hM?nVQIzIpFVA@^><#iyAj3?s-xVf#Xd6hWi z*3~#e!#7vfylG9Og2n4c`3ud{*=qP}ZquW+#Vvn{^qbQru+xSg-Z0+j%}3?YZMUMt zQHu+6FZlTj9}tlkgORC08z84F=KwU-R<5ztlj)3_z^+3Ny5#QOq<4^nR|0_yQvBep z!3^+39sicm*vME0{2O+2e%zpHhG~X>Fe8fr;lQjoFVgc%-Hz(RcdUOWB~dsGMATK1 zjiZj&K#JH{d8Cr?z2zgU9iO?%K}~ZOW6CXkot?|;c zRJ_7`QS4PvlGDMC{J39?9mB25){5{uPEECU%Yg7gJ2mrO?mLl5WXD*}%!+&_mtb82 zS#5o|UvCYL%inl#-Y=adv(fg^(tvpE3oHsxBE_2Kgtl|U01St7hx`l;xu0=0Y*Ifk z79Lb1NB76PW2~8vj=6Lk^W*Q{?Qc=H+%*-b5v+02RM`=`C=gjsFL8OZ2B|UW8%%N> z*fH^tVwE>H)y7)cGM#~3Qg2$r{u<3EvrB2fqcsywJc(VyPh|HG5D4mufa_oE&;j&G z!Ha<(ZqdqtxIErpD+T;A$_J;Ho39IA&6!cRW2mlDe;j1}t=k<`0CQgmgg|6nKrlLxYw2{hIPbBm~5rfef{at z5MO(bc(JU5TBR@Bv?kRjql|@6RwMboWnD1aYqd1?!FwILr zN_sY=sU6wS^A6i~4}2NOlWU{nD?xK4vE1hBk4>)mDxpkmrKW;w^(sGx`9du?^NS_Q z2LcUbXQF6cz+zeLAqW^AWIGpCLZ1j2@JOk%fAy+SKa;xPFS#Q|ZDOeRpZOt3yF#rF z*M9g*%s`2{(HW+VO{ARzcpkiCNom3tD@NU+7vUEVeV^;@K6ZTOIKBs#4+S$FW)ag6 zZEbzE=M9sutynoc8b9VYxrOt87H3*qou6PM7e7<1;=rlF9#n|P%X53sbT%g-1wO?- z1{>)=-;u9X|1$h_F$W#5_qPv+D_#t;vLXWTh;$y0+TftwFR zNi6^9gH+9?83T;nK?`YUCPdykKe)e$;L&bI9uenOmIRlL9)-b)Lt^0|5%{CaT%FQV zFf}6V|v<$UR;Xo_D7B}dPo>#2WdCOpy#dUD>5Y${G7CW7QsK&V%yz|?e-MaV; z{Hg;=qR>u3t0_E&pC*d8$XInj1z*vQkE20QCC1wA!x~Q~FxBXm(Q)?wsT#L#AyAth zN-OKFzW#aoB%ng#t8N_S9Z~Y*LASlyuLNesqFPK1;KSMa*?LNO1I=$JxtI6HD$z#q zM;dm}m9ffHOG>BCS#qWf1*$aj?WI8)m{HxGHmm<;R~f~6f`GbmRu~N_l>~{JAa4y} znYdmJq`Dc$u2Cs^Np8utZ&Mkn31d~Y=abDZzK6M(4mUTg`wHhgxHdjIb2{oY7Sl@& z?BzdAHbhrN*(b@NCQF54r=MZUYn7Hby1kbFTymtjkQOEIPkw7xPeWr+Y**j<5x8zu zG3@jCvJf+)iYa;*D(k?x;x0S%xOTSh93YK7x914Zv36LDFPs^1n0T=GDopxwhrjKE zK!^~#Qc$fuXv7AAl(X}sUO(+!SIXEzqrYm%OS((6aIb-Eb#%*W4a@iht}1QwZrUAe zhgHS4-fu3zb?rpxY8>q{YL41|o;*dUl+ZWa6tC1two#c~p{Up%Nv*^sAru3mXFuIJ z@_RB~I|)D}wS!f?t9=lPJi2Z!JQ_MnF(t5oF2;LcX7oDqMCk^1~;30Zv3)nvK+E9O?n(&U+~9`^C#UXr>JHJ!$h| z4`VGaMFrd!9yZhvy~^sotuc78P4I!WOM@%e#r`fr16Pp=utuR5A$DBJ-1lI35{D2+ z(8B95==1JPgZ&kd?b@Wcbr=&SZJhmSVD3COJ1WOi+nu}&Xaj9P3AO{SW9(e^)-MwV zroVkeJik{emIsw!O@jRmO7^d|oNWh5{COW0eK5zKu z;bT~?{0zmJdKqm>P4f?|R$bY@EiGGpY#sHo$v>yupE|;r7uxihAOolVFn{bAY;2=^6TGO&0x7_OSHHiSgQwCzwMu>>)N3 z23trj@p!;ac>So>F08UiD^b{t58m`82uyf;ug<%(k239}1J!{?L*#An&5P_x&+IrN z8{eM#{T?btpzGH&a^pmZh<76^kHD2~X;lVqCHdQuuK}qt!Q1V;7j103f+yxM5?X{a zeAqkM;=pOVn&aA}E^sn087XN*RL5zmH?|o+eqKf8Xf7GEGKa+3k;@3ED4DdaOltnf zt$_HKZ?n>{JczbK7YTKa+mj@ZinSYDprc_HxM{yaC>uA`YYxi9NRX#Ko%tf?WbXp4 zc%6*mE_iBp>^U=nKF7yxn9SdHiKz^DyqxW8Wj~!BvQjwvdwohiGX;%GVGaz7GqQsi zhI=cMrcl6P!B&;o;Gm9Mk)X}bHY@|*fO8aj%Uz9Guxye>jlt5`EaL}|Zys%#DvbAG zXTaMps_&d5UnMZV=w3a<{~1qr$-3$t(h|p-|8}u}WCr zm3rdnj@e)Yt?uAk;m6ylDbMlt4$lxVyH6hxkI(E7409b{YPH>{C@K#;@t<A@b(={lO<<{u3mthYS_ z!ar}8B>m)RXj&>@1RO$Edf1N)!nGdT40n`NWi;HSGdc8!e`_(}dq1tEp?sqow<6Ux z6;4|0YJNB{Z%rkmiGS1_@c!Y^r~#*%ZspT6bp&0(CCDxB0voT7tspKF-t-(mRC~?$55%{56I-40ah8 z?GXbaKiJ`9{RtdseS1QZ3+?v(#jrzBZIDna`xyUA0kjr^;@KlX+8VW6iI+^sQ(%2+ zMtxgw$;7>1xBvX}F!TjH^nRKe>?A2mbfYlW4TKj{;Sm_N3?b-f8Of7Zx?+)HJ^TV z9~{ZAoeVYVbi8t3u;?=8dsu(|?04xpK5(28gs6f<0* z`Pc9ZuYm&e`t1eWx<+H5bF6;(mX_#6!Da`tSYuo$G&=m`?kt#lvvK(N+LPI>FnOqG z_@M^kEt&F;YK|VZ-7m%Cb$|__uA1H%B^q*aa{Y%1n&rP8RnP>2P4nW^NLL@uAdo?_ z@J(C^V-U!cCTJR^l6DSKEhDt6K!~Q2URj<~ApVNN4X&JLa0DH+tc2+Gro&F;t9VkT z+Ef1m4>BL(qsHoIBOS^=ENj9$*4%6tp6xg1=G-wC$eWOea?tK;N=>_dtmgPqy?aXI z32)ZNLXc^s4{Oa)lA5AEY7hi#HPz8sVSTXyG;XSL#OLV*Ksj*H_CdUMNE7jR;JEGD z4Y7;k;d)~e<*}F6pN@3w4Uq7SF-zI$cn@1O5!6Q_eJ&l>nrj z+BuK@>8nT^=3^ceHC7=ga;4B`}P3gqo_^=&`S&@7BY9 zB8KPZP`@59z(&hZPX!td-7Q;Q_NBcNn%);#v=t?Jf+x~fij|NGt~z7%tpzETXx)FV z5$+67eSQs6LM2(nIh4S1AO*x=K?sDGSg~c$wiRx~&2+1Mx4Y!x~ zM+DI9sJ7+Qdf3P4MkNTC4pw{JzH1o2YGD$FGmnmz-rHn7zYp$a64!7mIB!frzn0Vt zze$~ceJ1uKvJC_{KXBzLmtMuhQk8k5mOk6qQ@&oNsiDJCzq3@qJe5@8P*nH$-FXMHr*rFQR0Odifs2GQCT$AWL%%{s$;q1|< zJOicq0$Y?oYm{Os0#N`yWn6|xjx9;2%qU?sry%+P@$K*iTm#shjy2227HoF{?3f%vz5&p|-m zBwmWHBU(ZoQ7=ar^tB0mwxgteFta_*^;)}-*Y0~p8mao>b%~I>L8uThn zPCS0gP&D7^hj$LOKj~*&MJEVlGVjpeXZOU57m0K_1Cg|9pf}KR_I0e&y*dgwyqs8D z%(#_!w84^j_wC8K@&I+Yz-=<)EhSc;sNM0^8$22-2fgfnN$8q@Np>EkRwElx+52*N zT)mhrc}a5r4)5OQFt`_SABwP&`Z2q}mS3$o2p%hr0NJOHL(!@sJRuH!o4qE^pBZYj zpeLh-6K;wrqtKX=w^<#WjEeR#whfIX(e6d^Yruh|92}Z=mj%((&>U_zA^QO9vgIc& zp>ZQ$0uOiZjMi*DZ-H!F(;P^t4G`~kIQY?^Z;_n@V>}O9o&t^>g6Xk)i9+`)iCeCkj5lt$i$YG;o|vVf15`vXzwS`a+pU(#irf+&^^Q#N^t! zme5|v@L1-fDidr-%c7(DqgLd}jKbY&x^46c#(uMcHyq7nH`19h5pt8Y0lPQGVOo{L zRnNYf6BIQWi?5oS2K9?ZU-^@lxM{jnk7{x4(hJtTTK#2!C5~^Xz0zO*JXskx1TB*j zF0tFmWS^RoZ12N#IB>X;(}8rn#dlNho8LRi%HB2MkTUlqJ4mr-eGBh*=g7P}+Y4cu z3^(~5$Q6d*JE1K$cy8aPnDx-};P1aBJMqyTUsfeIhDWO|Y2pA>USrhVlsxpYi0(32 zP={xJon^p*izW~)o{bdZ&}`Zm!TyJf`kLPU!TRidtYCv`=8^99Z!PPgVloC2Oo|i> zTC+ogBtM{2k>*gL5<8B2$Ls>*uW@-t-}SI%WP{~DD@ds`S3+=fPNX7tD|F*_-_vtQ1r;Oe6QHw4WckN+>}{Cc$?&zw~K`i^1<**D!hi9#VYi4EZME+N!8Y z_JPQ!e)igwH;dtop$yI=erCI-*;K{~W#FS%a^d``@pAl1;T<}dT8bTW+W!1ma(HOxCDthU@euGFH#X;nCSpL($wZrcm|B* zh&n9*xeKMH!c!e7&bx{;IwXmOh1TzfQKmNdqOp?>(sjt#v>(HL>7;kjc#Xs5)hoYu zNq(LQ?L7@QIRQ{e1#pX!dA{)s;t*CD((yc~m+y+U!d&=o;KIXB z4G2$VH%oIKULifRBxpa$c==F`%$pRNmq0vn>HRK;E-a5@{yCHcs{G#?hrs4X%A|DJM?{6}IyB7(KSr78;DeR`cs!W*$bBz)P&+s(j%2 z94T{#y7q#PBCdZMj#cAn{>*5w;1q}@=`KNO*0jSW>=~oTN`Gd0ijl@DqdxYurH-k# zz~I$C{yQ`z3afx-E5A5cP@<@n8H4XHG`ksNOD-ZwH=YXgjdJAORigb}>nbwHI0w3x zV$8_rir&S~d?OUf%GVf-Pi^!8l_Wm8XR;19qTe$TMedbhwiN7-IUHHa`IRM_CFge! zs&J}(--$bQi`ySb9eR6|XX7aG8lIx+v{wgk=%d&H8B_sJSgBAoUzc1^D4)Z~jQ zod{?PYPf@Rr&|k5+SY9(jS6PVXo|hGa~UP^1mUEodgAE?Z{3jR^wF=4i|@>V1l)lZ zZI%Ca>t}lht${(^rQz8x>6AyryN4S=kiZ1aQ=+UDn|*&i;f+p~2( zvz3)+Nfg_$T`AvcpLbo;fk%?~23lZRM86T!aubN2!`o}>H5wr?65qc2kMzQtj9-3Y zc*E7hSBG1$@x$$000V*QvXN>`$ffr^kGp_~#n+j?V>6jdG7T(n6+c*X?M?dwe<4cm zdexfX2Yh%5<{n5je^gADDyu~G*Tmka4CF_9Q7`llYjA21?euQ&Zrq{kMBP}AgJU?h z&yyErDR6y@&6XvabH^#{IGFhie;W>_X*fkQB{6^GehQ{|wHwr2uG|zvAEH{KqBLuy zC&QpLACPnjvYMAIXi31F>^ciW?U1;+)Y2E3E81(xXYJnm-+)O*U3Oh}la%Brpc@S7 zzh%e*EUYNTva-9^;F#Zn^LjP(!eCruzs7+RXUOgpL+Ulaw_K2*GU`W&EjB=*IKJcQ z<+5oT)V1ZP0UJ3T%t+VDoCS;IT^PkbKajPo*ic6MS=8#whKt$g545_YwoaC?@D}G#}b9c+xHi2%cW~r%#^JMJAx$1j@Q_eK305s*Rh8rldNN zSjZV(kXNC}SZWA{6G^`kUkr;eVdp?F-!Oubi~4G zlO=(EU1oy%Egy!4se3L)qoirs$tQ)PYkHk7Vmi;wnPyb>LH)a`Psh^&#(3txfT+HZ z$@zpEFST~gpee%_N2{Exw(|OmV?}CENsL2&&O5+v*xzzw`J zvhl-dGM+$T<%A7H5d3wgQU`Y(`f5|{VN8luNX&NepuZ{S@Rg58q~%gDMD~^@As>baGxs1_D<15{ z;Z*tGd)+fBP&e@Nw?)8fL~a#8YP7rsA{)=NTj#_Ag0 zy%e#W>iLs+>B)RJJ9iF|ccC;R#IEq1`X(zH4Mp$BJ*tq8u#J<5So9ct-Cckk(iVSn z#Tz_FRYL;GFf*7tQ5r<@%wH?)bCDpDEYK03I72Tng+RcNa~TiLT^akt*7 zgSA!nv+t6pMEFd#VS|UVo^FA?i${hK=sR0icWS2$2===`KpLyWAy9M`{X?R=x10EA zH`K$CN|NNbM?a1`?joLc9kK*6;u6%J|F)ZjDSP(B&YC%mxg$0q9;@36q;B1yCw?D} zBkVkH;+%pWfyZ%emx1*c1wr0=Dz&}oWt-p$>7`!%6lt0l;oXk;%kM7@CRM5nm_o&w zJL4V70}@Gywnufy*Wna87vM)Im`)waA9?Zp_rQQ^%K>!UJnIlzq%}^@&>D|--uAzC zT@%#-S%75-dm&35+1r(8WKAY-Edx@GVkvmE!UI zk%5xKj8J?#PleT7JztG*O(9V{fIi+7>ngE0ZmgF6L)ao9bX&H&cfONCXUBRBwpYB| z;X)q=t*u4-A|C8qV6dLnvHwU$hTISKm;>>2p4P{81#4C>IkaLDs}HMWv>6ZWpcTw_ zy_mlElp?cM_;$Iw(ilS?FH~)yM3P8v!1P&_!$E_)aP?h|EMiHb2e@APxk@OiLh?q-19$2ueb7Oe76K7K2R{$ge-Ho(p zXZ1_16oSwOIMH`C!^V+&-;b-Uq+WoD5pMUX)V~YPf3pQAXuzitd2j~;ElYzsjznhC-)oCHz4?GJhm5`b zfQo@larCgeAD(T#dk^W{z?HQxm%UZD;p^(4R(A&bK^<}9e_zNjVsG&HRbtF9ZM5?1 z|HRcLJwI$IEUE8>F?04nQrN*OUZ>C<5qW$ut($*@NYo?;_Qp(oceFRyxNcjI>%t;2 z9onnbVU}b`;8tGBF9*#t={mgfPvO4XQi+qsy5LN)ZGo&O_F&QoUT-vipjh{6?1Ctp zn6`s7OFqFGzkiNROy5=dH@(Sd&)1e1SKghgr12&*_6y_UsE#^_>3m6BHKOVIjO_Pb zo?RKkk9kE;7l-O|iXEG=0}aJsvFt0y!OD*|U`7ECIEk&Q*lf38Xy|Y4_Y4sJg@8rm z;UoLRxO0a;1HTrY(W5=t?l5*1-w>}{UlB7)Lst4Q8OPd#z!BnxQd#&0y%X&-pSA&8 zpu;7XbYh7$KN^vH+5U0o^7zTuC;s8SiGRg@9?8XFb@dhGKGwv_!5RwY_?zOEIVxXw zv~GW*jLcv6*$$sReg2Pkk}@<&nKP>R3GRdWI};;!v$JROs}{;$Qbv2%S4u7IN27aR z1g~AUA1__WU(Y=-0?j=>BLPIm8lrU|WE?##Cx zQgE40@h`bt{(0ngj{d}a6^}g+W?JIw4_N?z`wpc#ral>hlRD&PPNRLn#8j6+hEYr} zaW3&e3oifrUNR-m7dC()==#Dm+SxjD=Nuks~OBAmnS=O9d*GZ>h<>UaQ-Ex zAvFiG2@@XQG1|NL2ryASu&wK_E(vim7W2Q}wFj~|)I z0(C$2jl<+S`_sphu;r(v{a2`&Az2WC zfap*$Lyq6eUefcn6a~anZWHeyc7!9vB3;Q(&6!P)u7@bTI&Y}ch!tKQ03lwCavR^c) z;S|6l7PYJ`sjem#S;GTTk=!_SEXetn_XhmmW+c0J@aE%%W^lTjIMqj3qimsww%e*Y zYk6yT4)HJNj$&V93ee0_+ym0|VEaC>)J5aVo1(Z$91~-}VO6Q#eqiY+k_-Jv`&QD! zh6bWwPB1V`P-T5of^f$WU+%yo?O(5$NBz0wI+Y1>2wwxZ|MPHDa6d8_6dI&3#3?JO zXG^&u+fXf@$XIibair$VsTEw4N9xUNs3IacIVj8#4BBLZgIbTE!?u+}c$en1VM)(j z4^)_x3VgW&MH{WWBC*&oqqmxeH3qLi@C;bH#s3ET85|^Zo8cXbKg?2vBVijnAtvg! zN|HuFSJCXE(u;vNk7^#B+QWB z6$Q`+YD}wLm4)Uwa+$2?1SxEsthr6p9NrxTjHoA(bTg*~F!fR&iV(4jw3R zvc{S$1n`HktJ{1;K?uE6_}{d6Ll5D%VOCw$@BW<&7?{0i9@4t6`Hrdvvm~l;HXaPm z<3O=ETtAF>8%4m~x#t~Ct@tP2=gw;IQG4w?9$rW`#kcPh(=B*iCH`!upTwE>Xv{}} z31jKqzZhN<>m%(s;{|efpAaM@KCH{UyBXWdsK<{%b*Y}?W+)w)LGgLKgQ4#7#v!j8-bC6JKmhnFj8o+aeBcaqSihy-`d{qQ%oVSHAg0`Jr5*3? z&&<&F6p;sqR`-Gp2de{;3sKpT z`=3m*GHD71{y@%L5PqL5m;bf1?nDh*@O`rdq$XB3BxdyLbv*rj!l35CEZ?>tiSA__ zT@iu9j0kjZl%zOi0842IQc+UCY^~HM@I)!r~Ab{-e@hGg8VNqFy}7Oi=#Wh z)ETQYjE;cH|s%FMAtU>p;a7gsEhl8&00Q;FgR8t8_iX>nqQE#5?bWC@Iy( z25_*vZstHgROuuNZOvpW{G3(KXTuy>+%X>+Z%GoQ*kbx9#^7Q^$c~aAWGdLJyLaZV zm+*VSUHa@|JR`{k^hu1K316_bKLWeoIc_ zi(HX>OE#!@s1h`eZ~GOaW0o7Fo&9Q3L`VDej%xM$Dq#HEN)sl`z@h!`RN+vJC8z#T zzxCP8c^n<@@Z|Chp6?~9Px)1r#ZDhq2==~ea+u};(P1b&v#!}uTS7s=++{h?YPdce zOp~Nxau#sxw6cNY8PIT;59|;mVJM$c!-@v}A5-5Q)>PJgoe+vh6Ht0lnxG)PNfSXJ z1Vnn5C>;_(q}OC{01L&?L=Y?>(tGG6ib@mFC@rBx0TD2Olu!cXyQuU2zWayIJTvo{ zd(S=R?!DJuYwcWwfs1X*{~!hB7WA+2_f&Co7NHP_&I?j}seU&FK-+$zU(u70sz|G# zmcg>KT`5OMG~(5|U(6i>T4^d{v5d8jRfcI-)CJ-NgSCUzgIQ{2R&C$`sZX0O5p)1w zq-5&@_bG6Jje?vi`7!>k`fdLI{o=Z&(#_K|4U)jy-)ZN3Xq3ls_}>5%#y*Tb`@}^- zsp(?#W05W2Kbja5s9E=kpXCIx;!HW%&Q^*}AV;;HjS($nSrD zw=%n<mr2cE zL`MAF8GdpUup-#@xK=HpBr})VkzQg0XmuN(8IYHVL`y^eN6#>R;}p!P#HQs$;5!qZ zqgLf|{(KVfBwxoL+c0lc;JfkDD0h_lBKu)uD;h?)C+!XbdR9)^`txA_T<*n%||4;xR9M z+sY2>^H(d@*PZf+=S-yN0G6S#Jdvua0^XM6wgDW6J2)D70?tH^hR-aH`~;+}jg&$Y zjfAF=V;N@qhu5E7Lc{U5C(Q0w~;jN;GAM3vqyKga*zf z#>e(1#l5F`V@CW$_JYPVGZ<^xf?Zdh|HrxqXdv}*tlkR*Ki~s?cn)M_Nn22tkV?C= z0_R9p>~$;tqO_|agN;3`VbpA|X$>jBEfz2C7LxMinP3!a#+;l`cPEX-OE6OalK*YPHXgiXxV zFRQWj#ggb!bdMCp(IZq+(m%%h4xJ6~x+H;;ArY|ijpm&HWmEv=BEkkhq=0;H8w*Jb zBx(q6S5lUws~9F^7gVuDl(D0I$?+q1XSnJU`0c#~-%J1iG|`t3HvC9v*t}w^jV~OG>R%CkXg%%K=dA zvF&mS4LNO|r%k82JQL2_0`;hI9YDsqSjGg$ObOTZ(t!=ZEWL0EV;3Rv_l$VD|5@*( z6&3R1RAB_Y;p;*vdL3yn{Q0HH4Ni^|Po=7WL%xmdRvu#T^uOREO@8qz+yTn*8J!)& zXAP7cP{MICv-xJ;t2AwM0@AWsk?Z-&B`Nn)3)IE%isB|6!GymX$e@o0NLAD^4vc(4 z-!h~tW*o%7JzT)9EWw=sZvHPl@^xUmdnRfL<&1~PExiw7L0G$nQfR8Rjm29KN1#Ny z+^qNf>%&wuZkT&QwxeoSSnc7Z7(VFzH!)JkkJo8l{TSiFtK)N#63=K?xpc>}>_!m= zrc*;hkI{9EU9 z&X31mAOxZ(gxyi z%ULZfw`4!AzbblI6H`G0*ev0C#8*xd=l##@;I{SkkvI2l@crm+L5vPc$U@@f$@Ev>52m$&pGQmLO zhX({g7%;@Px1~m56O48`L=p7-Xn_we$Gh%h?sIz%ox)Rei%yRD-8BFA?kkM77~^Hi zWhd_E8i_UvGR#|?a7VZxJON(Fh>{TpUvAikZ|>+G=t`wjGbtN9)zBUF5 z?9nllnRX#BPF0)RUV zsZbo2c&7ucU?}~yH|=NL|Mmm3zMQ`($s-`3LBCc3pi7YVxU&>L`a<}@9<`Iy+{xkG zF&yIywKw$vo7>OrC?m%Q(D$IV`bdwf3-R_L#+OO~Ch%SUpE zTySO^#qV>(#b&NC?QW4cig$TpJPPUG+O>0ZlKi>^O7@oR%%M|rsAdLJ>odOt8Jy-~ zUh*6rAg(z+)ewDP4tFNaYpU&Nt)Jsw4S^>v{_4j|VAT2-jUsHTONniq_4}^S_A9{P z`u(~^)&Ku4^{l1AYUfyjJ!cM*UeRlS%0#Aq@!q1r{U-}I0h`Nq6bI6SWhm}u*9X~e zt&NXoq>)z8i`z{Ug>vLP*Z>>XZ}yuh%KFvWd}j~5Qp*0Li0h=ky1Du@549#5e{Eqg zNe;3BjD@$O_+B}~-dNHm6S#E#ddTiye+F8?LZ2nfvkT@r;85eD*QH^1+d`aeVm z(Kw-WpBNw8&otQ+Nt{e#HHC^-o1%;fk0kGy5?<>jSYjE6JTf1v|0C6>4j^FkD5=9u zb9k};zVT9oI0=Zz(%!*qn)p$KxNA@-_hzOV>$d3Jz|uPUwA|9y>Z2B!jm;F>{6~U? z`DNkOMjrRB^wSfG|GAZ+&WhnOrje&sp%zjrChZS| z#p@Fpjk0qqBmyRfsrvbQ-2@>gSHch?q56YBj|3@QL${FiJ%UI#uJFNIkTlg1F_ljT zJ=Zk^UBW~+bj&wV>yZcN{p`u?P@2Q2UUw63?fKe>-<$vNIT{azkDqQ~)BOdU7{`XF z%3<%0e=@ylDK|$KBHa>-Fl*!67Wh~I3O?%nJ+2`Se;Qe&{@O{SB(|?JiQ;To2Xxp3 zxBV-Uuq#YyOljF_Wjjq94>+Xa;8}5%9DALRx{Z4!sJ^Vt)Si3lXjjwmp1_wFq=dv7 zTiK#K&&{$MOT2ldPc5n?kjr$+U^%P7gvv)kf!W#TDown{rOI8y=u-KIy22 z@w0*+39f$ti)U7c#%2N6Xns&G$Ml4&5xT%3(+B8|>X>ul0$RC1WQisherLw6yi9ZE zh{%8VE4JGG0^q-)RB z?#u2zG%gEOO10sO)QwbDI??iU`NDZW;ePoKz9!>Vm|=Gpt+C_-iL;0n03bw_ixUrS7drxSR8!EjxS@Q6*{*!BZf$XKyX+`u zAcG@VJb-&ZBFi~4-?47*3)NH#>Gn26Bsj9YE;NxcAUH`j!0sd-csW_!v0&j(SD?Mr1%IN}WdBg{N55=<@PpzJXCsBgfe`ap%lq3H< zrLp7TE0TCNGzN%H+@XrhSB>T75*|}Z0eq@!F+K_oB@bcvn8O)?23w2un-I0&#^NTF zy=@B! zU-;b8&32EjUV=a14!_xVWGF_twuCY+sk>6E=9XE-QEAc2*%qD>sDdy!weUD=>4nK@ z<$B})=;+wP*CFxDYP^f7#akfxoS}0>E{-fp@^~bZX^MaGy;sB?oA~V0nZM zi@x*E--I{kZ~n}lUc4#&Sfh8jN$NLh#Y*M}@+@q2+p&Q*%m*>Atwqbaf}@p=$e3%T zo`?53)u6|_?QU6`z|ivI#VyGN??iVNDA9iD zDNP918xMp#kCyBq8t$Q*L6AV~G&90^5_FKPa>M}R#K-iaajZ#YJqOFQtyk-ABp+dY z2Gr3N9j_MLZ+87o${i>{1)snGc=K@-XxZ%m4YD$KbhCBN$;Ipid>&SuLcNpJ!s+rD z*b0ECAeLi{#fe$Vo=}a~lp8fR4O0MITYq2XzZ2%&AqD(h{QVbz)HFVOtaRgCyJ5_W7=h3rQ1 z1)CAm*VcC$DV}WtzJK=In_Kmahrlm=T(E^}yO#1V^9_7H+BHUGAO_uzPFH`s7ELbF z1H^|ih5J$Qs|i4`n~xSZH@3L2!nDk!PyF@>p*3o#ii!hJpg*hF`F9oHQCBK>>H%qy z#?Q7~72c}cI=6HF!sN4fE}`&AF1P6cCy8e>d@Nn(7QVJY1m9f8J1AgI-90u}EN;av5AM`Y2SL2tZlWwM$}TBA?|l6KB>2dU59; zd>tmOx-emi8qszl=+DzJ{@JLC<6X?#=`WB85bDcQIXIAxI^q+D|mjO3{04z})my1_ykwJujx zztJwZ4Zr7Ul@TiT#ITL#I4^l9IR>tWu764$37L~5mSNHEJu|?I$!gt)>_k!xJR-N- zvw{rrh&VQrTD*_mUrh6qZ-`5nRQ~%y-i!ojSpNBEgE6jc+zVtbBzg20?9aaf{+xy} z{XwsOz_3AO_BMXMs|*yQ=Yw^B&4QmPU|xU}D;GA{Ah6-zU5`Ki!|#J~ z_`W~!0WfCV5iJ3y5Jq=-7Tu%o0~#hn$*1w^l3M?5v6la-$$!W}mu!7*aw!F8BS(+h zIGVX6t7siKlB@uLu5?_VLklT|l%C}57^Yf^a{OiJUjOI6)`T$^^bw;7gDx_L{-}FF z8+wny;QBHnFu?(d@)+f@W3i`qO*2lh$sf^Wu9R31B1>X}UaEE--Y{?pO#in4pCpIL zt2gn?_}7@6#?GL@YnxdBV3W#R2y@A_`LMr6{AaN;4y6euF(hD-(0kw*$h^5rH}$8> zf3G*?W}waFZzaQhbqrtb#^W|1xvMMjUrjhmPQ|-QiCztaZ_=#Dr)ORoALsxDhlgfu zF`9B3DSlL!4Pg@)`sbiwv*cD9(zsA#Dp`; zjO(`&BaW_ekTk=0J3!cUaN2^&^o(^AH9)H|P)TxVY{ytTK z4X9dOI$8LNcbkEcL#u*tTi^r;c>ed;DgXj}cm#G+DcaaA$Oi^0;$|;9JUZz4B0JO- zdft|hhc89fI1CK|V@yWK`l691P{k$avnYF%sT^J3Agj?e?(19Q(GO%gh{ScJ|4ESj z;9ap52L`IR+3Z67zi7oxvaZ=~5LA;RLGSfabRDEbbfGQb)j&}iLqyewL~n)8-9e`3Fxd1)M{-BYGhsVZK3P;xHB60Y8Aal z!W;fYGfC}7W_(Wvv#|SSbn*)^(>+)aEb_AcZ(nrF*p}Nj?z+V(Dp~UE+pu0BJbRC0 zq%q(tcSJt_uz|BcS-|`Z-Ew`ni^BVw=Z}uT2-cE_=` zKvqor>Bh81N0c*ti%7|rTh^D)EV=w-Y`wj44$WKY!H;WAxLV_5u7+Oc|mSa{|ktIvC&b~ zTe%;#C_?642S#AwlkM79R$S$vf-Ftr)yQE4m8HBmeINZ8-Hq-(Y=y3;D|4xaN_-W> zDnc?sS!=`jJ)@qqtt1E5|M~c&aQ}TGPR1LhZ{=^n{mCcWrVnHi6r|tQf5sz)-+GYe^oR)(L0`1C>egd=au&|Bk;Pt6#(hi5630-ho zM3<|jB{iI6o0I5gul-YaWRw}~ah{&e^5BsD9MN;yHY>p{vg`H>MF1|G81Pqti zCP}K~;Za;hu;^}_) zn};^iQ3Z?zQvQbh7Y0sjny6pb0iShf<_EEgE8WlgBdi|7vVV88Az)rD{M+?cCp7VJ5OxUxcR!)QLuAB2?|NT6w9 zujyt~1Q?ik1Pq~JPGvEBbkuF65qYA24G18UQ^Z&XfN}#Q&*5WYTA-HDS;fEFsFNoS zU!G(VV(@=lfbWNb(|l_l@KvBbdbf{xVLK?3nj%mGVDkqoW1PabTQI^Zig|At zumIXo=G72D$QO}XKV)KyW~%5}0s)rPm6UwB8t(v>q2Zr8S)&o&o3Svm899I)3pJ>X z3*;XXS9bf1S}}Jie|r5L9)CbW*VyOtG4egzyMcT9w6omxc_02cwpo1fjlIpQ9sFrT z(U;n|x7=Mhf4&4Si~odtHmo@F6xYPm^({TTW3ji`k=c#7V zY`{R692T@xODu&H~V(!J#m&UP7$I{ z`-5%8exV;+=DUzp**V`PkyUYQ(Sjj+XQ+Vm(;0bq^kAJa?E{E2x3QSgQ@%zgG0@b- z{b-Ju1BO`id@hThw;>b)0|~Tzr1EmmMqk7-PmDcq{41Be^(PSlB5h*`&uae*B(oR< z`{T_8EYP0O#tS2cB34^m#P_bkr5e)H!TOi;{+(9G7BNmq_(zea(b8x-b9J3wL;n1- zI@I6^Z9vnQ{}8IjtAI{31YMh2qo-1ts&hhhKbE`E|H<-J($@|?+Rr26s3y`Ny9)Pw zdj#k*1-(q8=TQ<;_w4_+(Gi)8|JgR}5?J4N=ICWP?-TZk^rpDCk-~d51*{#_%O|gYVa@@g0H^aJPa2=O%3w2#_N+76n&fKN z45-zfEj(mFXG>f9k71dC`A96aTSu-QB7(qW_g~)3yn?A&YUkTf#mQ&LIg16QkRqRL*oimC5JlbV2J-^#A3z80griw&^h6nu z9Vg>eSXuBV4N?S{3zV;c(3zwHn8L={$rdk4tEOx(Q@z?SG`lGl98!r79 zmLB2V@$BT|q^+$zCS#BC9B>PR*3s>rV{>$tw1kTUess6#O=1Ij3zD1mEd9^s^gHD| z4BStg8Q{Ijg1#ixX=P*8f5OywLlUYO5UpS4!lvJ5@m2#5Lv6uaS|M>jV7t`4UWUJj zw|!1&f0c*1dPPqkZSyS_-;A<6A6Z@aGM<{iaMh~pQE+RqWksAV`c_2@;GQOKm+r_k z0uE=^s1VbXG2X~3mcxVtB%AQuMudAEdvdX~toK5x8L{fCukIAPJVXgMPKR7(6cc>A z!^sq$5n5a94U($5xHBoX$s_q^0eKJ2PJra~e(|XFh}(gX(!Xm=OTcvSO7+^5lwH7# z;~3DgxAsXBa|kkfEbSi%b>*x}h=S_Ch$UaKZPr*<{ zF4Im~fYUNV9~7%r+ycyzaVFzIs`guKpr8kh_V?mE`#cIry?$(En&Hi zVvAVem@p~(wrWjk4wpCyO7op!%W9*#v)eFu|R>e?eq9LFk{+hd2{(DPQwuJ*<)s8pPK>ypK7xDhDr`O6KLZZbza3M+Z&>`<~dg-(zst zt9kVEo<*oo5z=8yP{H~RmacfByyXIKKm-Kp-$cxHX1!`P$wUR2?bcE9x_@|z zVM}4r(yQOgai-{XQ-Y)L0b?wT@XlS|O0)CmHne-44b3%rd;oPz7IwzX1gi9Kx}Jf~ zS_y=;Gv26uN73{f8&np)AR<;`X7$l~Kx~+l__N)e5a@!y9gPh8jHO9evB-~yZg*Gh zGGWWkv~_@5O0F%W{n?iSPY^6fcdjYnOU`FVYrVSMR(?W z@m{Pe)g~vVBT^^0jM5|ZSb8BJ@Wc2?4&YeRLpM7N0fXuouDXeaR2T0fHFLffO8B3G zn^Z6+8nQQWZnQY>a?_b?XxBG!*b{2cGr9YT%c=TR%4JQCki zly2d~jaz+w6r&H8y|?K(l!qVIp(2CJAhDmXwM_$V_78PLwH~pht2>w8AKv;~#j+oY z(|~Wr8)_T|klHqn?Yjf{@OglQdVVbas8;2&Ru*Ml#`cC9iQ7WefoH zGH}@S4Q1be1lLpUnecrlOMx5Pa$14N zuM^kxsoZ>A(1=!AF8h)0}?RGw%jtE}&R zd)03Zb7362t>U!H?wt{;5}Zmgjphjz1`;eR!wZL{&oz*rk_*>KiGz5$KyajRX{+Ei zqtYOCLxcF3v!HJR@+6&smKL&_a1Mig{(cWvY8%J-RTZzUr)8zNC$ODZ+#`!4(HLSt zWAP3IdwjZ-JM+)p^*apvvjT8ecta9$3*-UZ*3Ryk)uZsiBxHibe7iY`m@j7GEYAh?&Fa_8mK4Jr{U9z<-`3Pb{Y$m}9`qMj1ClQ#9KE8Eh*MgHZ*HR(O}f|r)j8(a{207f6%9<* z75b?4;~=8nV%bC$Rf-lZC-Ijf@7d9Y7;gwbl`syO8wzA~e6ut~!hda#$nkvo2Iqkh zbi)Z7-C?kbCOqtocTUgI74xn8X}IT?fF6OOc{F3Bfs#ETE(^S2rMi96cDi=| zaZ=9~pbsSC=qD|GiSe|PacO>?A<(nd=5vbHNEa@xJe9%uTtAlFd8}oS8fGMN3mp8c*d8%G{*ey&fWCm~96My> z1Gw33%wJ6QQ!Zi!T*+L(IKeq#EH{Jepuk*25~RJIQPLNBUdU~$5>jawaZD6@Y&8(tVDhQw8U6$|V)2TF zvIQ1U1%uePwkyyT!Wx4O=QblfX{_XI_aD3N3fMdKS+6~$^`;tEnDB9udd~K&@Ob6} zu6C#VNqUY-e&nC&4HP6#Jf&zA7cNMuU_ZUjwWeqmFc7Y~V@q~e6qfax+ktJ54L zpsn_0y!OvKmr42^W53Khz&Xeucw_m4TVF>E`l>WWH>YoX1shqdYxgzY4xP z@n?)?t>f^J)6KK17L$gdW5TkDInV1L-ZD`eDgAz{fNU*GjY;cvJ?FkuKVmB`pE-k> zh%|Qg*!3s31N~MkjxBP6S`)J=^bReIc4V(#x%J*P4E}Pc`?7P6itBb6cjLZDFsrkz z?sYqaf%b%vTtWiw!Vba-W%G9KIy8SwEK=qSK9%jsE1Y50Cx+Dq8cB zK1%_w=|Y~ft`iSlSBk=kU_toPl5V`!`ZV5UM;O7Y_2WLlp`dlZG!`BK4!P3s(p7F%R1=EkJ0#tjz?0Pqd zh(9g4QwyN9`O^*-f5qFuc*nY|2y0khjw!Y4-(F6!?JJGNi+Ky8A|Ur{a+Y2`E^d;` z_7f}9`2$egyfL^KZ&PJ`pZ8CofgCR6#>sC9tC(+ z`arlqD}kR7%&VM$76r(_rsVwZE$%2|t(M^rJ-}B@R(Qb&7vzSfd9l9GXvUUy$9WM2 zQm&?MSBbv|K)a8=0E~R!$F2m9Y2?*Q4JfDfI1GR+p2uSMJJS2<9$edL6yB=g_vH9vm94-9*?0-uFs%9Tv4)a$ih%A|u2`X`o# zHQTV=za}r0nH&R(1G8x5+MAmj-uUCtcDo_PI=u|}4Q8?}AP&?ub8ee8!hgoIDzxdJ z7;9=<;pehG!y|G9=*}EoGZW_c9(4W^r`O;65ckgp>7;y_K_;P*6Uk{lP1G zO5uYIbFvQJC#;93$r(mCy~KH4BsvV}RnZ&bc!CK^>3YIiF%NryVm#vb(?6*nFxclX zp@0DdU=Nu@dR*BlR`L;`nfvJk=IT-TPuE9H@HTp!r+2$~@$OmmGs&YO1Cg6jbG{RR zTHn0F^u7*;52Vjh`LT9Kj%-Xy5H?I$VZ6~0hx|<4V$d8r81VasT)cIw-}h%7cD`{u z{E~TC%8I&UR7RunstcJ0D22{U0oNRD0yHfHWW(ffcm!ZWwiO}W zqG7)>pU#j=?0RvHb{TKE9z%z^u#TbE+E=QXb=WZuB^D}LBUI0IZ3le2EVLQ;-KWLg zz;LG`->q;xGVpu?zx8a!8*)Gs+;>>il)YMLV`z7pd-4`%tlJ*)o*iba9HF62ryIu6NQc!;`J}>=n=tV9p9ajs)SA! zGF#+?KBfp0{ko)A zQmffJA~9#A!Jz(_tz^6=FugO^c4`IKn4gmW18VjIVEz2Pr%C$3@aM$}vcsC!8S3|~ z$VFj?I?&r;6|`nZgk$>XGxjlYvmKI#TOcSC^?m$fp#9e40%<+L$P63r`H^rThlaZm zWra6hcd&x2KtoDFHXiIZ;NjstXLQ+Llxx(2OLn_I<2SPerzP|1^jRWB9ztojA_#7j z>pr<-a?LC(!Mz)+UP1fX(G?$KnGR-7vUvaUOnL{~wx0BzuQ>suyuY0yet)abd9c|r;0!Dk%Zhm(g-P$c&Y5fpZ zM0>vz+f@`au5p>rh5wHEekVoFenw>=K}tzo;>8G-&8cD{&Vj(-1-GC5NosD^Jm7>r zDq{a(Ri1i{uVgYS<)Ik&XXz?1(2UP*+b+OC2e$4nX^zvcl0^sm+hC8l1o*gXvT5Du z0Jk8lD)ke7b+JW*_@3!Ki$z*WGtp1=A2*DbiE+nNrKLYWbM-Oq_~ej3e#$>GZsB%{ zmNQT*@mdnYw|C8jpbnOgrbZqPsAKuHD`I{nO*Wem)g=l8LMCKGat<0({Okv%C9Xbb z1nR$mz|XIuD*u^tH@{G}IT@)CHn&+cj_BaN`Lvkiw}0MlCbp8d+l4i<>iKk8h+g`W zuW?VFT5h&;Q}!q2=dVRZO}rbr-wuIk!~m1<(iyR5BGMU`YxZx5Fz!i6__Uq_CNLw& z0wdFq!%@Pjs(~ue7~~Za&9R@9@s`qF; zcw=(2m)tMg0qP727(n2>>t;zv^?HUsiyy#rIf~ydmXy+S2#f$IOCqbsK9)@P5Fe3; zGF10Q&!Xo7=oe>KXlYHz=TfP;8{#1*zbY`xm{5ULJ3(3n=CZ8e(C$o?{K8_$)Ya_J z=3*|5#&IixamYwmm>6fEpCr`aWQCaBJlzCZF+!AASV+K#N&8;Lom+5$dbWk65p452CwX4Z*mwq*fme~Hw3UIWyj@?90@Id#d`1-e z-vh1eUl;h(v{MQUnVs9#T2fk`YrgXxVfA2``plKy&baEn2HVwk*}+6Nr)ZT;ByiP+ z8@pXu2Ij7Av7SQkO{9f__9{@Lho}JE$>z%F7>|;b__rYhT`<|?Lpi26l ze5=QYd7a!_=@)#HAm4LedfHP1l!ghlHNLN4M0~o@dfh+5eY{J*)@z~tY?sLgH9FYY z4h2IdMn__gc^3f#X&2|nV0ZGY6-rpvMIW2>-`)KJtGv4Op zV3l34!~OV}h*n`NSIxU$VIdmZsk3dX9uTVZP;xI}MVyfnLOq)-3XX*cSe>&3&76Q2nihVIsov z;PMo-i>vbT)%*ysZ;r-_RKm*i8PCW0dvQAr#akwC;`-k_9RLVK`F+#Rt58-sUFBW{ zoBjz4|7fCMy@8%LfVQ7yi1U%&TVEb-2eZ|(MeYAQ>+dE=TaoxS$NAv_FhzZn!4Y)$ zfosrr{Kt?#vtgv|+sP1j%HStexaPwnUR_4!)KGhI@|1Jal8emj8`8>rjh+O`Fs5vuMX~@i1BbA6x z&cJzQfbAr{MTVFFS`h9!TjK(8?w+hJpA4wF&ZRfrcp>GS+Z(4tseNa16~}6Hdp^sdOeU{WlUBAD>3b8`e}DRK~1pIU0otv3X+-8Ks?KWVP#x;0F5({hCI(7Cd#|t zNWYV!Ao&gAU9b|U%TIZrhASR2-#xptvuUg%_w_va7XBM|ot5zyUQmvt$9$V09yS+7 zx?>>}bw_@N>w=s*PGo1xOOZU|wbuK+>DPVcc;gQlbZ+1`)7fXwnK@LnWEZe@!L&_g zr|+EZo4vn}dfqqtZ)%{Y2=HKEunN{UxYAR&Oy4BUs(+3YbCgOXYd$cfc_=SUcbN<~ zh2AiZRg%EU&NISi)^;6>PE5t`!~RXn?nTkAdR+ttS-<1RW^iCE401|)=JNgd^Pv;= zZ)L!v8Fy5Q?xx%enAz6L3vG~&QV_8VM^4Xb7xHlHn7q;O`u4_b?bgxR%|;EuQ2GU9 z1gvn&C~*J2T=NV`DA+lke70mIW?+Wmf??;A;0=^f6S;LwaK^Mx>h^Ho&?R7XI*Yk9 z9Xx=I+AuZu_j6p@&u^L_iPMd)zBX+JPfclQpO}`FxZ(ff+v@;qrE|jFl+RL~7Y1_6 z-0MUIA8x};Ir3ZNB$j`^yLl@Mq+q^8@xxK^YhP(fu^~|=o6@H=|M-=z$gQ<>aYbI znmXX`Cc-@j60RopWWC@tYc$+;>aAyi|mSfW2xW z9p>;ERWKZ<5FBc3#|>Q+`i~2M8#tRw+U(2QT_4?Tsi3Z$K+j8D56SHDck_9&xX$Z^ zZ#RF*sv>w4x}NcB?X<+V$|U`sED|fypwl__fyLcj)}4r|N75bo!G=2f4y1Es$QVeZ zy2K5|E&emjL!(55d0~xYAb{Q9FdfAz9M$FFrU(95a*ouw8OW~vd^fy4z^J6q!XAlh z6e%S*mY#X?W#Y2KMO1+vP=y(Gmc!gxKPp;8O$MZQvTLu4p;9942?HKpinRn6rll+rU*;%BVyTfZOvAo`gIJBqbB9S^ zfjkTAg!qqC74g*at;F=qJ3IhhroPFH!Jf_xcktH=e@etv1RPBt!Rk5Ps91{E&C9C& zx7Z_Np4`m+>pJD3aub%~{3y1_uVBGL)Zpna)SBRI0C{oEB|fh*r_pssJFD{KH6ZxM z;aUGA0i!Q6Rq4K%2KbVOgl~mIVA56h{#J*EKobzX)Ga>@L4k!f#B+1!M$BtLVIW({ zZ@0z7FilQ(3;xvss(p9-xxxOWh|kC2`}Gd1hK=qIy!chjuGrrfFk!Yjqv|gj>9@fw zc!6$~83%jt>Yi<1(><=cDdl!+=e(YHv*!hepo{1FoF8l2iyFTPebmmg?axY9gfa)+ z2zZW+89C`&5&mNLwL;_j6m{Xsa@4fuK;;yjr-Fj)Nv9KVL6<_>5tUzAm^Do>aH0l?&@DYnC4g$YI~a4qXvAY0LTt>ST-!#a{oFX zTv$B$=qF!QZdpKwfu^%W43D$k69ZUn{y3h>?);j1F@!=a%9O_92uAz3OF8Wa3OnBW zOvpx3dclHoE9ds3VyG9$%U?z5qn)uXgRVrGGXvhL4?n0?|8vC&I-e83qLZoW)svOr zae`hjd&A}NYC^!_Y^)0kG2UxV^%SOXzBgh%DP9R!>OSN#Cq6ecI%W zFD#z}$UdW)svHL>vh@suE|?K1-wel+`2=^WhxM}K&^{{VWjV8&YEnU*!SidRv)sR2 zj662io%C=9m^*=`W-iV816K)dmOP`t_GX<6k6NR1&Ez+hRhNYIlIcaTvRJ89aQKtW zsB(;$3=kZxWE2~B_s_B_2RU-d^2s;*f{RY))^0~5>H4!_IM-|?sRbn!@DqI!ZhW)$ z#tb%PyR}%gzh#=Oz))sJO$OB17B8LZ_tNKM2_p!)BAs~9{;7VV`|~UhC+=R#&4+n; z&P75aH+c_tMgw>zj11%c^?-W8t$8c#uinbr_b5-8`LnxwoEKv>HnpF6p--P zoo-9uTAfab%r3a8^+LWvDZ9XVFU}=bK4@SPUtaPv(saakL}kDy(b5&&V6vV~%9d7; z^*;ffR#5%tEL#?-L`uQIXLKap9hm=KViDC8$Glodn2!c((Rlh<&wk2n8BdqO5yM@L zY(W}JX7*!!0dA6=0e;Tw`h~D_@06B=7Crs+U>!n^`K%zkSBN&sQabJe;WegIN!c3?v$pCt=jc`+$~UJI}%}T+`-L_yOY9|u~KJnx&j{y zY4ISi1Pkx$By1!{JW(+}p2Fky(Qr-uee0hdHp% zF?)IcX;_G1Lsw4*RMwu{ZmyBs-RgNTjIKef_lAlrEPGdNMzg#L8Iv2e!lJ{ks$J?i~I8{2XFsJ`0EZ6gD z#ir_uiLS?>lM5m$+}?>U?Uzr3%ywmW1eZYdF0U8xKKKyso3)8_ApY!k|A{{u8S)o* z2z9Y_x?EMGx71ZDV(t}ixHx0v>+Th|3UzrE<;s($J^P7+D>9?YNFM|8{pgQpC0-c6 ziRZ36wHl++a&R$1%!A-!ujE0P@XE%O;nTd1&HIzNLk4FCCBKz~B+R>ruLM1(P0G%_ z9k{s#(aH8ov@P$}5%P2{_ZC^r<18F#?;XE8>Fk3?oOI@UD8Mah-=*~csBS?W7ppz# zk|BB_Ac=4B^#Q#(Uc;%v{ne!2>1-sLzfbUU26*o4Z1j3f2CKU11K==~^do23$)CL7 z4GpR!O{v`N?KopK84kNUy2CN61j}9bqmktrunrf=F0lVndN%3-5 z1AG8)jj8mCEqkbH?}fKavxxoyDGHQX&g8R710b>w&HL1%qR?P+%J=1gHNkg4nf_GD zHT1P3YDsF+=H2Ao;t0?@gF$LasjoH>5xm2spjtvY&bz|( zGDyYcdKwYJXL(KrW(ES(Dt;IdEw5~Fmq)g;io&_mrNSksTb=HUDHi{<6E-R?ofzMv zIUd0&ctq57S^UxxS!1?xE&AA+4EeZA|DchBqjTl80$QmN~@h2E^Ib` zlL^tT%tbXU)&v<_JOEk^MlL=zR+4ni!mEK>NyU0Vb$@G9Hmd7g#{Z-0y5p(d|Nj{r zmDNclS#|7e$ILj56CH#oJ5(IWCM)9{*Da^AI_5#B&@i+2IbF&+C~<7(TtxPf>~Ve{ zb-#c7JbL6&dGtA-_jt|c>-p?#h>=XBjK39LeV-d^NbgKQ0y+Uv-N`G?<`gaN_yARA zs%`z;`G&@-MIn{1-@g*lWM=s&2JV;#)x?3WW{KKDKg}X&{{V4dI=Rxb^?Jr3e)u<| z?|&_SJ7%A4k~P`v-g-;l@@7q5phpt9oSyrAEhHy1l^^jcOOCl7AOasS8jc?>(}epL zj1Wt$6K>v6Fq#@TE1aAM=2V9Ks`{Cc6xKHJyyna)Y-gJ#dh%Pn~rN?#}A2vW~k7 zQvef@M=9~ap;9zj=*zQsWsO?>sjw*zmefII%>k3~+_53+LIfsMxYQPHZx=UqyrwpB z-fCkijeM#2YrU1D-clyIcZlK|xr}c4dP{T3%Gqp#Nzg0|(jQpu;Q!a6-6jMD36yZP z$UY8l?Hj(uwyTDS7*m9L3bb-hod-C^-+DUAx&)z2V6t9M2%+vfDQBVd`=bMo_O0?< z)I}(s59ro06jxASQ-}oBG?1m^kWQFhTd(pCrBT&vX3-K|G!ZQ_9w6Xk% zf+T%4_1uYj4<~$2NEC04XEd~y)XOS@Ej)z> z1mHl0{Hh-p^9AvcGQZZdl^oj>r;z1ZmZan+l)x^_|HQ6hidey2UAjd)KU@*wm{7r6 z>)bq9N&KmEKE&Ds};PctpgDF%hwJ@OqRU3Gxd?-~^a==W;ie{k8u2~}#q{Lh; zv;5BEOeyw#VKM)=dH1iHeUVlW@`GG_DK8U+k=1XRq?AP7Y^yYnCT@w#e|@yR`fK>= zLpsFSX2Wh|kSr!Y|6%D`arW*dLC-E&?6HQQ#`=O>kD>mU;e0a39sd}|=kwk19O?-- z=s|KyqXUydfQsNv@;Vl)-cn@kr5n=7q50<%e%hkgsLH%CE`GAx^K;oX(&he6+!-Td zQ*m-;Z6sIU#cry@%R+AM(qlFlN}&zo~EK zm27Ua{z3gLocB+2D=_CUd^9a}w};6ce*O}$!y|r_dyJkv-J`!FaIKcPJzf0E|8n~) zHqgY!B=r;EZ}0P`VoJNy^o#qq>}y$)wORExLB{#i;CO=6%dYtVrMjoaIRgE$cOCEe zz&=YskP=01Br*TrS-{*3AKm=Z6iLociRz9HDtsQw1@OD9{C+aTD^vAHI@VsJki=JO`E{ri3v(S$%S zXv-O!vK^7ZyE3b)L`iAq6`3K7XdnwdW?j1*YKox~2v$2zVSBSK0J(4XR6w~ANgyuQ z0`D1_2YCN$Y_unY**!Ju`8q<{ArD2je;Wi#D!x8govYM9mPZzdBO^%mdheI22sMQj zLjpkHiYpM_06UEnYO3NN4+HX5K+CTC9Il|wZvl%(Ol*&z8gW9*?os}MugvU=7`f!! zatGokENwLt<%FLv!6rQ+DG6hb5c5cq{KtAmq zR~h-|69Q9ioHpk&M*nJ3zdg+Ke_ry<%oL;vJ;g~qQ&RtSaRW#I&_~sOc5a>zth9s1P4lWnkEzp${VpefV2^m?)~#9ia>bQp}Y#V zf-Za9TXjZz^hcR?QXf|V^jjK3`$|5f+?(wZ-q@?QItYhzJEqWS=;vSU(%ONDQrS`+ zp9}o)x_oJ{!r^aGr~i(FT1urJ6_kbzS021AR+suG@wjrBit6j$ccb9a7ZFf&|H9h= z_tuK^#bpLL;L71m)ad7?RD5dsB2w^(xIB0lTEn54X1qCc#5&u!3X&$e$!3$6=OyMe zMtFO!)C021ty%qYtg#ZOXb5xD8~!r=X$i%N%z(;YwPd=5DZbOY+ho#|eeG*-J4$7i=RIo`r(qUF?PY@M@!UeofB7BzwrTFJl${6?-ge z=*+k2Pz+i}%+19~-<9uj=W>rdW5`6+IvN&(aeUr4D=fq1%Eq03lf8&6}EzYpalye}#=SUIn z)~fEsKayQ@=nl6hgMN}v=Z zpwlE`4cS!PvdKHYNaYcl#f@zm?b7vjfXbTi~CZffOS>}B~^UPETY>D(Ef3{h#44&7$5ll+zu$oDyk5I zg}16bkeJRS(7)@>r5zs9)-haMqPHRb-)9S4R!{PX zBf3Q${y||27yteAw)gzj%^4goFqUNZAZ#Cn>7H{ek8!tAso}j~V>|K9S!K4v#U5xe zT9MzaAs>Y`0trJ=+j}{&Ha6ISCl-YKal|k+4A48#8-VbfaXoJGeo++D{R(w*GdCCL zd`4C7y>4f0>rZVr52)(2yrxvd+%788Q=VrLp9eCl$?@FnOLBjL<*g7)1{2~R+IG42^1F|60^ z@A>?}&5=)lET(ai3acSqC~%g=+-;|HbW&J1$zqi3wvA>9JbxQ0BlfU)55yFLlipyB zOexdFqcAA>ji?lx5*kwPQuo4GBG-cM%_=(D$f?_-G&IY2dgn$h>ppt4x2s8?h^!P9 zi)u`MNTiQbl;K~KHwvCpbSP0%3#%Qd^eV6GUH3(KkHV4SjUc(9FJ7lg9|)|5Q252} zVEJ1)Y+Rg9*zSwyT!nQ!A?!#ja_`0!{>405>fh`-v)0CvDjfO3dRmDym8s^tKe8m5 zD3h(Yk?ncPYAj}$j5CttCD+H!+;Uo)oN5Q*|!!~+$fl@YZ z$8DDO({0HEJxfl{uH1Wf{(Qr;kF2^Ykz{ZXIEZM}+?Q%z^SAM?tx%0FV%#J~8bjeH zJ~=c%!~wD!Rj(#j)m}&KdCqpM3f+t-Mr6}(Iaijf3muY!h86CD!fbmv#1Quv@1%(R zb`xO5c5VXrT)6fSUA@9;z%ZESp91NdmG=Rj`G9ZD+ez0mU`{#0l+X%1&mro zKIB`Qz*4ZW4hQS`*_0MV#zU-VA_K^+gLj|y@hpxy2t?HrFv9}D zC@sEx**Gy*kg#D2=a@FaVZo5Y1vV)%W&7HI=#Jfg`)u+ILIL(UMOhf8BLXKceYV!) z+_mmaD~@~lWn_RGa*Sdw8+je!Z%zv=$vqnDyUfCX*jZ5CeC``5_WaCF2-96!(n7w zcmIr=DMNOOy2aftj^}fqDLEHOCIT9JUEB@j9vS3%)5831`!WxK$)A)J7rXHGXbt>x zqPqKFmGvSpkflRrzu&Wb!HJkV<~~xDRKZ_s|4~!rBc$vc&(tx91t19P*-NWEu!`j` zdwxf@>eh><-6^=&%_(XwC%Yo1{6GNis$)qf7`-dFDJ$S{{yd`2?%c0XiWI&F8vVdu zE(nqe)ei9IN>YsI0RvJCm|jtFwc^zCtqIUu9SiSM@DlI<*a9(8rM_)v)a%8KiUnZnW4T=?b@!>$7XY2& zfj*JT#ka%xx2k(Q-jXn_NJ>VfR!U}Vczv#CXH_;*ec9Z@jfQT}NV_hMBtw14WIW;eyoV20~-aS4D%Mrh@ zdn8z3Fi)r3%h@H@|KG))R*i)07Y=fJG4gwg1D|Gw3cDu0udn7UAEr!GL<^LUlclQ% z2L9TT>fPQ&nPt&K-CM(trqz#HHt}X&k+e2G%R>D+UfTzTuLzNZ8reu5YMr$Oy4i6K zR=@pN%b(IU_xZdS*7nrGm!)7l*DF2EjLWscgX}f6^*~cRk(f_(C+hWG-w7POTI@FL zLVWzZooh{{G#gY!ta#v>YH;dRF^E<;Mu!jT_mVJGCvg$$tdGf~x|?(;QS=HsFo;(SF_ zQYBFZcwMoHHOc5O{(J80bE54R+8ww@q#!-XIF#vrw?f`jgKQ@Q;o)%tR0~(2qxh!J&w5Y;}NrGxtm}5Fe8e1kD9@NLP=P-oxbLBV%cQtw# z$JO0qkg|Z1LhReS2da_&4!-3%qDJw?Kdiso{@v4-7=nVkwMtC;SqZ zpTQmR2?P)?G}d+JiGOSLRwLPy2RLFsxaK0sxMlQ==iy+Uf)Bo>g8H$RsctW#E;N# zd=%{tvS|zfnyyCtb>e5|ct?G^UrD2j*w4;oEKi<`zLn{=w2#P^%TE3S6q5zn3hm{8 z{8h!jP%0L*B-Xj64m+}R)>Vf`y}oyytF7mGvJQ-x4RyR%7A{$;z;ssBU2=C2jQAnb zE|i*RG=4$y#>LJ6mJiyVJ}{}`ZfZpqEnCM7$L{VIHnQRC#U={ERdc;$CH6`3&?`$Xk|2l~10< zdeb7li&FRH+Bop+cq=SUvnbOn0`@9;XXOL0BC64a6YE`D{PovvrBXs+=agI z5H9{B^}G}U8@ld;9=)`I9o1N0jTQL;#F%)%+NsrkzK;yOf-bQHNe|VH3G5KzD`Bl& zbq2jV?UgebT4xX@3y)ey;WaUG{oBeaU(UZ0ymjpOx%Cc~2F;R4 z%@27A)Ef`hkajN+d*a};4}J0BW@i6f&T(m6V}beCI|(p6p@#b{ZLlaibzpYS1>VHg z5Us=VCeBxPUq{@5)s7e6)7t1?T-j53I}{`%poFIl^szBI_D`8{m`FtJCEssIJ-_LF zOTz6MBY$5cnq*^2Ah1B4lTXzS9;^=1`d!NO;IVqo5q3&bAdRizN(zFmipXD|8HC~E z!L8sD@VCfSd@SP5oqB^cKmkV-o_)L9giSL`j>A#D(wC#u9c|x>yFAxKNP~qP+Ei0I zk#-5jQzdlit0FN3fI7^yw;F#NuKbSNs(Lg@0@frmTTf{t1UE|Uq&_&Kq>G3c>OS=un*IFO zWdK&oH&wX#Tvsb4QW}9Jf`2+#-=B&QF|P*z%Rtbe0Y*I` z6l{kY10Y7oAS5li(AviltuwAaQfoLuqR>0nEEhwilyneT?tY_pTpUZ}FRGyBA%&MD zn^gU^N-gNztp~RsNc`{pR}cjlrG>3!5XJWfo0OUCPMSXaKKIea%h6}M)l0fY?a>XG zZpyNo=(%c7Nl@QsrB+D@i0cspH+F${S3~&)trN_pNgU_4zozhQMQ3YgB?2R*-|~{% z)9Rcj9U(i}l~i#Ht#dtn;ZWG$)8N@`@CLYby@OAn&H*9>K-|e744$@z zZW435P7h}twm%AYPf^FgObQms#|901ch{oCW7z^hum=)OXP`H_adH8;Okx@p% z12$%6t};Ul z@1YHQ7%S92un>)zc|oay`vxkax<@J3D7x?uLEd^P2j_@X*>&PibSybOUR$^ zMD?Bng185Vm@CC1qxx6y*NG<={`F1gwlwP94i9l>l(@L@0#P%!%0;IF+xlm1E$MZp zDT`R_H9+r{DeZHdx%kun9J3n(g@ug$a?YNNRNQdR z#ztK~yiW&Zo`i1<1ad=PwV%DH@cMZW_7;rtoz+z+CJH_YY7&K$-+7WxY+fmcigR;J zzqgWb>&-Vjc`#Npat{eP#RGKN1-R>@Q%9Z?^(!~5$IiMP_c^&Gvi*pVHk!DXaj+XU z1Hp%X7Y>K|j_xk61=x2{r`d>~4Ih@i$hMPs7kf7qQp}+cM_5)}$TBffD)iD+D!*+P zE&xhpX_Uv^h+O`p{Wb7Zsgly+v~#m4VpWMo0suWO$IE;Ndfbkf^lBOwj^Xbc28`>V zc_kYL2U(ZxYE5Z9U%3#Pn%k2s{`ZitX6ZQ}bM)?A^&OSpw`6GQ4;uG{2467ne|7Fj zwW|%_ct?4|t^=er^I{X3`vR{>LkTMqPA>z2X=Qjhb*hA&rRa8Sm!l?n+GTfuUBP|O zQXX1*NP*>z6|O%WEHqd`9Y%51$RbWBJ_DTuPqT~2wt5`dz1V9AU-5ABKVHhuJhN5n zf2FLWr+`vzlrf3F6&V^i({^E31J94Yi^oCSA)U}_a0y5w^{yh+Qj9FRV0i_BS%&hQ z>v=g8T70mWq&4N=`8FwFd>LQs_U_d$Ri@}qqn>TKzSiwvdo1>{30h~g|E{<^1|Sdc z6x%c%V(DVU#3qXTM(?R?uCF~-zR?NVg&eFc54uGaqYdJR?j&VDAr?cL1mUK%bTYzMn?wVuSBxMP~}SyAwIZ)ku79U zR5R!HJ3zl{QFbh(DX)WKGvzv|2%y83e*HO=x}AS2@-L3Vy}yL*(fD>A%3Y?)PCcwm z$a5c2`LMqHBd3Veb=weM@S1^wui$fmnjGdlfy;gmvS|QV=c$Be9s8o||CDxl5S|cl zMu0}1G{CBV+lki+igCa3#DLdq3msG!BvRLZZ~ zqrW({M5FkXKOg;d*(rcAMW}h15&q}i@(TVB;O4OA?*|)2QrH(O>N8X3j=a%tDQMJH zLJHo9fE99up?hl{XE&Z6UgBxs4}P^<2nuV8jZg$jCKxrPkpch*gl;(jUr8odAJ!DG zeiXJm`+lnp-Hw79fJPD}So0^v`PhrucqI6E*JoQarGhjz72R~pj(iMeBrN?p!0ZC; zx8^_gtI+XEOFOY!mgR+fD+;#&h@#|yEm|7_0XTw9bpdDh>5tnl2*Dzocz}Y~eV6gBvsVr z-gX%|LisnZUH;aB-?7q|++-uif|UK4f=Uusp|o3VFZLE@$LMtb7hXy}@rK~?EHD+O zzA#Y(%!aT7h6lGi@!|Ii(>nh&r+_~Q1Bn}s_aCYU-cD4LXH#40vNcd%kFt{p~SHfY$Dp0GiIUW3}qE=8di`EY_fjV%+fw6|?^E_BewGEUV?Hx9W zBJQwgd%f>=FLb+qd+qJG)ZeosfVYfmxCDy_I*HtH-^AQ5;6iSIAo-9P2-*GKzF3Z) z5l)UN$SAYLwHiG4d|m$JxltpH6pSk2R=zLNcA+<++3ny(Xnd9m)%&GG(EpA@_@&-q%D+Go-Z&*!#@@NK z1q`rESONsZ@rLIW5LrL6zovJ6jf2J&aj@nOn(N_s4sp+8aE-M^Ch+;FKY^zC_Pz+= zV7-Qf?!@kkP|N^M$b(&&mmPtmUTGnB>~R(d!+kF<(g7}!6KUl5R#){_StEZBn9!g@ z{lS31O-eKfFu6l!YY>~tA8-EGgFowa7*LSAyQiD*zdk(8N*$&!_x8F?XqW>7)u@L+ zx>p=iLLx+#(IfSd@}VI*03Om!<)EnzOlSVTruNc7Q@eRP^fy*ty){jre;lkX}=FK@Eh#Ve=|@`ew;Q6yBb}Aw7*y*=$5gAZnjZg z1?w*5F@=8q-aeSIJ1&|`8e*JvyX@qCf#OFoX1JZf&m$(Xi6_|tIlAKs10B9%kpMpH zy{F5LPTt}pAn@k>OjcpeO4ctC2nE>J^iPp5@c#ANI^v!@4I=QMz>SsYr+(qFPYE9Y zlpR(){7~9yc=g(b^|09NT}m@B0@u853Y|nu(D#rBHl{r5-~X+=6^Nc#!SAEX)cVO; z)oH|J-2jM#Y%tICTb}J{+$h%?#!z}BJdeV^rK=@W=$68^LOroq`G`Ydxv}A*AYfd{ zbpvF{zOJ|vD4r>_J|N% zTf*UrRi}iX9^@L#A0-15K3s#f9?$%Cf){I&I~R?(_ljO`a6u27%=nNc>}GMdt^E?Pb&o}scD_-5!dJ}r;|sc< zMU|DRDm`tgJz016lb`k%$AY=^`vD?i6DpVj z(4K~wa9BP&l)A5hbaxE>_@xsc4i=Y3%xW=KUFcCnpcyUK=Jfprqjt^-!)XMtJZBIu z_0AI`&bbxaX5@*7zi%qyyt@<&TJ5jUF#w70UGLo^N+!=JoAge5#>}qxQTKtl+rHUj zn?!Zu1OJeigkPn(!uNN`QnP`W)qyHc#aVWYsN9CctP-XqMQ@z=z~P;l8LqHgeD4iy z=`6-ERn@YW8W>lP?(O8hyXzb}^D1z`Kw`{Fd))++@nC&7Nv}$_Bzqh#V|)uwA+2x))vE4d?gnF93v3G7+IC<+8U)9L-l>*p?RX z2>&ZgL=ci{Xp2CM%XyCL#S`P$03=Owp^-$z+Mp2_2OGbbHB#NSHmgXixPflCs@Jmt zMzJ@Ya})cy3*N0BEj}V-D0ye}a!MT?8qB?UfAK8pFx752R<>uBt!!#{kpl4)s+K3+ z3*uBNidngY`6f2e``Q0`XoP#>{18XTHE!8f2iq*io3y4z{|Y@)(lJV`b6#XP-qAu2 zn)LTy?s&LM%(u=-p^LDte_12-%S!F<@86zWPCv_a_0-X$;@p>yo;ZF~-0-N`g$rg! zpFewEa7y7X8^vjNlN?bD`%1bQ_zK&J4?jX7i`wQzgRR;dvbf_jb`@(HFKy=FVAbowl(;q3zH>E;Z*UrL>8c87)+u+-_^!p~3u0`o!A)K9MxiR|Uwt zU58C%u;C-eEey;Y=EoveBl$s&`CKVv{J#<_jg=ykH!HdJCn)DhA>pwS_(bV;c5O8y zTXf6&q?X5@I|Aw*b-Ra?2EsV*LqJT2j`@8*!+-wKr)Wq=%~{BN-+0s4MCJ%AHsV_Y zyF)qp?vfLJiVQ{8@`0+}Dvvo<<3Q@q2<;>-c_d2;5tu6uT1XXw?h$n3Ui1@*lh+|&6mr8*0`#c>DM%bpWoxBGN8)>~~NG~xJ zh;hgZ7*Q+2EyD_*lW?M56iQS;sFDlzmq$m=&qTx>dEgr|dqPtHzJr|>SldpjTXbJ@ z8}7c>W$yUWYx(|~U5S_DWr3q~HRLjOGkuTF6ZTw1R*2zir~)QwAra$T_J#t+4qTez z$PCirwTVv}(wLK;ot68I>MmclMyZ(&Bk9)h??xmdT_5Ot?w2WHtrba~PO-FQ|>x*kqU1L#y)e#q;U7F>{4aNs*!`+0|ppbdLeGv3llvY-mP_xJy zggH$Ztm2^r={^2v%)UgWww}M^E+wZLj|(?Eyg$9Bsfc_NurM$%>@A;Dl6+L@%Lg(~ z!}FiE>L0v#NBiYu;P7YtclTEQQ7MRt8N@tyN)J`yIsEn!T-7Hs)qMT8#0s& z<;!n?qg7Bunx&IKN@nbMNgJmfYQw#zD51d{(^-%7;?u2_dMkT?pQ0c2w1~7zzc_CD zG(rH7fNf3^n3HmzP8Mre&cM&8MNwWL?qE8oKa*vmcI*sVPLj4#hh4lo@M~X5A;Dv= zqJ|I(DmvJB9<K6A9cMcoM>~P|5*(M*?7e_90 zRK*gm0ZLFPW1C^dm86T?GL`c=otTR8)zs?rjF0>I5B8s~ZO(u~ou?Nr@(heRI*xh! zjg{zX(nA(*N_SfBCYu-IuxPoO4~yahS2H&V`<}wD*+)!LYFUp2q>9xL7wk2Kr2-Bdsc@VLfr~!uh0) zE;c8(j-6OSu+6P*r$NL7gD_YqX=#7O<`u|L4faD6gu96@G}{@&UtXW04^P>0=d1=V z?%X@3GJX_p1keo<2DK6T=^!x-QFX}}^xs11n<8I_=CI+_B5jfaXo7SO5%##Jgct(r z{i2jP?6xTY5TjL10xYXT@aGg^$^d?#Dy~|}MR$Es|ENE*Z7==wWq%SMyhPxmFRTov zq>CJZ{%}{>IODyVxmLNYv!#QbuBDhp%14G9_|T>LCP(eEOMo(^U2BA3Daz&K9qg;K(x~^i2C$w39@Q?>*C-{@?R-eQR+7Z=xOe?rr`^pu)_d;ViVks|>B+|>>@Ncj zT!AvF_L<&4B3Zo-%pZ%nv`3NPE1hp@;zdDL&}dNnz>fCo&-31Mz=eD{eGK%+%=iA- zk_F@@+o7X@$9%5W?}lKo=t0nLiEvJmQjI117LPUhH0cniBev9#*c4m1kX=Xm7NH5hQt95x`J{lZv z26Ks?-%Bdn+A%wKXp~(jm2@pH3TKv8vQe3GX!GcIjc=VG6#%U?nErEH6*}%OjS)n7 zjSXzbAisDQ?TiV+r9i0rYg)19u{n(~AMXZ)o|TZ9;9>kt)ge!Q5Yo4aZ@MKj5der4 zzK}-JcchI@=zLakp1uqJ0Nq=DGeohe7}q8NYx4dfE7V*vX$&lsNV*n)FOW$-J{%8_ z(r}Zs03(TVc@pXA-k?DX&c3&{^)UAJid4rABgxWkHAuDK#H0x2dD7p6oCbX(aJ2Fi zUG;xhfFPX|E08F=`fG7+5P)BKt{ znL5rhy)0?Q7$u(+(w_#CIB)f|7)v|s&nWJf>r`Fa;_39 z0J?9yO^k;P6!_s;ng86|={6z8cZwDMne8Gk)aZc(0(07t5B~)I;bt}T>s#x?HQ7J+ zs+2~J~5(i=C0^FgU zpwtK2M-QIlcIUMh#~053?tj3;Lz+PeBkPcHt+)?Y&8tVb*oK;;oHn@Cl|iqfDXo)p+HRJeA(AF`iuhv_C#M-3Y6vFYrV3N7Y80zb3IyJ|2Qp zS-m{QgXYXn89<$?p$u3MbDuvUgad?lWU4Wrn3^Qw4jF%A{=PH0k4({p z0`OLJiw%5bn!sem|G7z=TK`-4V{kqo(4&LifR~{u%_@UL)m(!0BbAY`q2UL7%xBb0 z+FZG;k`xj*@aQPV33w=Iz;&8CYE)04MrhL)0 z+f+804>Zz3hb1b-?$`h|II<;q!=Oc-wDkql8X?M*U_7I6XnRGBfIL0pA&$c9(C4}E zw@<$Fn-kl$U)<`6osRLhhCU^z$zYhB=$2kiJHNkF%~O1m4*YV!)3|x93mM|?BoHaD zxr!kTe1q>C^sc^p>*w0Ic(@~HqzBIzB9mdABk9^>6Wr4m$R$E{j$;UN?2ajy>;;FkDr80XsMQyO-+Z_~7 zLqO&oVRvndgFL6c4 z3q>(H7X`)c-0a}pNOi{2H9xOCsPY=yf2Gjr6M-JRN`kXYIw;#$RS$zS;>^P?4~Ycl z?&-x7>|{BMbt?s>a1#!XPLZ z>GCdC_#kJq=W2*kFX>1PA276 zy$jfx0bGGwVYY!bc;vdCXuTw2UvTs2o>4z_)#jZ1)58B5f?IDMUUtfUI3zGw6|k4E zbVUloS%g(*P2K*rr^;NJ2DlJ_ei#Cwt$-ApaH#~ae;i^HO%F#337c+co%(=G2>?$7 z|M2rFqy$NKKnont{50AQiiJv(CH6~~00*{dgqG7I?(`Cj*|8Qhym#iccZii&`DYJE z1gyj+o^Ow*!QoQCv0GbL6PqyEmet&?Z>kP_Uk%VL;=CJ|6`m0mha=G~4gsE1w>znV zu&aJHMP4)S0R9qfD2gM6ZCt$p!EYaNm`SG>b&JM2?%l~tUZ)Wg{czt~^W~fI z@DCyL>j3C&leUI|ue>2_Iu&?sJP)(#U(GXx@zjcpR!-7(Q?$zK4N?+m z+sMN3>17gT*Nu@%aS$Uk+PLp-KE&1Qw+xej!={&@a%wN}VYs%_>gm>hZnWp58nb(K zQc2e?W4q%B^N}-E+nyL35r#TL#fjUnc2gT~3W^7%nvF{#BgtkCGxdl&79BaE=HpR( zGUZ=Q;|cw9dy7}!ooC)d%W0GIp1WWA$91lMnfJ^0qa6T=wJ+S)8yn}0{SiqymIPiZ zknZWcoD z9-^4j?AO@wg6WUbA8dYoxVAf7#r=JE;xOYq-)P~UUF}30QE|1g%YV2_kzSr1vGgz?(JFRH>B~Zo80+F^r zOnoO`Mgw(J85z_=b(dN0|0Fa2jeI-y-|AAit! z8&IBpxu!=JhIjI;Zgv8;)BCj!?+A3JZ&E0mWM^(j@5z-zeOZ6V&?41d8(Ti!k;6&> z1++iYj`W-h_tf7K)R986)H63>gdlH2M9&1pz_w?8n-T!!qM`(A$UOTRC)m?%-djX+ z%+KrOP#buIl_fqher+#{am*`XUgy38`4|?N`-}PrGs74))P}P0eQ-zc_ilNhVh@_?Sa&4^i`dE_`B5wBW$sBf# zM=GaO28>${;u9s-1`X88DO1vKQj`ml?iV=S#nsVGik%-=WPwnxaiH%J9Whr`RyW`u z*qJ?BA!h*M3V^Blct_oux9D3(EC55vUs}}xQuO?!p`6Pk^J-UDYpxND23%fnqYw>E~ zuF)CIAjr2lvSNN1&I4L_Wy?Xk*yetIgq5dB!7wGP<%lK7EM5tG;UI47bAw16b}9`h z6cuT;7I%AY&as7q?B?<)h?ojE>EI(fvrsaKz}HEi8o4!{?Tzika52YoAib5U*^!oFL2z!k`k8h1t3-VtA=pL3oEuUdPc7EnAru2@rl1f|w^e z&aAT_=oY`E4sLf)s>OSh902fS4Ku&6P6vvVkZiUf9XV8&q>cWN#rwRZkfB{20%0(c zXk7~NamGeq3Aaug^)CuHFQ5+Uo1X4L6>8zbQQF=ddPbPwnw%<6P$6u$sek!c2YxGp zQh-Nsn}2dLgDZnK&oR9^CLdmLUzbgC5jbYuba&vEbQCrleG4lCPVdvh ze*$9@K)#w3vYDVOfr;v%#t^;%arC_2O?n+{kypBWYQ2*h$}wB#hmFG`Xp%`6Tgi~} zjGdg_qfPuSw2hI-Wu*%6lP`5$O7+gUMv1J01DiR!2dh-`9>Y12-XSzEiP|}xMPlP&_z^v zb(9YH{d-M-Mb`P$WCTL7Te9)=P*J>Jiey&FHe;@z2*Gy0qmMDf9b0q*E=}3=C6x=M zjjV2?7OD8l0&+Skg9Ts}e|@Y&8fiv@zaxm9k{7jSUBdoz3LlP^I|;8h$G$CrgvlW@ zh;3c-bP?n6{DV^@+vgc-gU9BFlsB*e4hAhW$|H`5I1Sh66HmVVgdiq!LNOm&&#ejw zF#{Bh!tj+c%aJm;uc}Mzwqrb_Q4KhXbH0-1$HcZ_Km08g`I6WO95Ts#1cHk+(sCK= zm3n<&GK<5WbN5b~FC1QA?oe+9Aw#R?g?7ESpa2y_gEAr|ju3x6WwJ)7<{o~(YsWcD zpa8xSMbNC~`A5w&14J*f>N&M^Hz9XR$xI?+!;HucAeOq=zEAJGd$)TDy>J?+>@d>! zEt<-SacCe+!=Oix!{@n6={|*=qbgU|B;20g{ZoTnk2 zD$@1x%x3J1<#Y3SzUVPghC5vOwS$N!cbtgTh89_5$E)KfWT!H&T+GF6<3w{zNKf6K zTfH)J`3={NrW#3QE^+Ou)3@CF7A2AdSTkm@Y%*F#jILQb9^tXt^zud~=w8nc)N>-* z&kt=JPl!UU1~O(SDU{{_`f4QKT+A94HWQH)`TR}cov#D{z@1%el?v|mYJBsi`WTl8 zn<7c zyu&h+>y~|9aCO(j9j(`ta2INi0Rz?1b#uJ)%n z<2fNX^XH48uv_Qzifmwv7-~b6Tj7(W9gAZ%>ZeS6;46iMAMW9LdVK%a-gN~um37?| zAcM5IpeWr50l`sPs7i4(lmOCn08xqpVGwB|RZ7tDBMu`aW`GC-DD6X&OVg z1so6yp+rzR0@4YP?*NYT@IU`=!$ThK4JWxb=kC4sTI-zc%vx|=NJ}+3O+5bKIN)%_v2EdQ){=mnw;{ewEy7j1d3cW#4J zgjCBy)pR2|AoE>sIK>UXZ#3^XPxvK(qGJOs2reNq&MvK^Mu(UgIu%%S0Ca#UGxou> zYA$ttGcB-@Ocy4`e-78V{yExM75_T-fyhccc8qd)3MHTyI63xeA@pm-t zDv(#Q)=!uCE3_TjUuP82>hJ~nUM}G08wUlLR>q#XmT@>2hK*Fa4j6Rw8Rg-f7bhd zIjPNrdpoVmL@;7k!TqNeK0GTr;YMBi{d3zC3Y{Rhm@B;Dj+)G3KB$#V1{6`smzs@E zX#1Xey(;>#q`yq})Poo!oue!aXfuZPBQ;99CYjS~&t9!{Wl!7RxV=y(cSK!tJG~Rg zx8C%?T8yfpZW+;X5PG#QCcH`1PScgHP5jS4szk+QDjA*yOiw6|cB{Fw)c;a&FZfAvfol^J|g z^IAD8^^BKOUu4ehTYBZeS1n`*e$W(dMAkygf%fp5*4*Q$7%9+O$d|doK{cI9(CP{h zpV`M5M6!rGWOF5+x`ltPdhrQhgE%5~b0@&3fQ zhpCf*Osw69m&CdWW!+*Dv+oShI*$J*c;GTNt^<)VuNgSWVZr8FbBrWFscob(^?r5C z>U7rn`<6+|?ZaB3Cv-%hN{Jxl8I5}`{u{D0YM?a=$8kUqtfRUu*HjM*N|`aSci3ft zdvY_sLX#m{_uinUmeAjeRG&B=r7w~3_Pnt!-k8pGmwvh)CmP|onI}7>p2pG%#g`Xx z4LC#5wRzRm82-0_WNAZA2}Kn_mHUDOW{z=kp~>Aa89v1D&h24MiLPPvMcxMf;K_J? z)#|G{=^5<71apJPVr|5 zPWA`CyFgoa1UQ11yJ#X?gIzvHx}>Zxtb$KNEfzb8?K#`K`PI@&*|+JUyNga5x^M(r zH}__1JKG;v6plJc+m%&y6!xbYT12W?cPm*X|@g-Ds)5c^0myO(KYVe2E z=@|UrOC-x6C)k3XFTV>?z#2CsUxj{QamaKtd(z`u z4$5K5_sp9>MLI`SKxbC>gkdquNBw3LsL12m`q%)Hp&q^+?7;zPD&os;&|+}3Aya6U zU8rzxWz_JGm77c!dY>KTWxdy)x=A1#-#NMSZRD>_ zqIGA;mfi)dB#ms8O}_AFo)e|tm7OCP{mcEIyE4r#TKk^$_&UR*((WK@IsBWyyh3h= z8C;7P?HyP{8E1ulG7+BKamJQu|3odwg><3!5{)*3-EAk(#uHroZ6#xux$67Fn)rT4 z^}xFYDFwAC#i{?$& zQEzC?U1L7lH4|pJKxI{}MrUYcPKhud`BDPNOtOiCpM4r+)Zk`=5zR;*(q0`8>;7(4 z=OfRSUk&pq7qre<#`Lm)yCGXq^+#&IUB}t#eBnh_8=7J#u9{FkX-nyUTb`yZ3svgQ zm~vuU9-SP~43r+zEVy=U8%2W)8+A_l{A_`%O6;*oq`fbf;i}woCLPf6>d;c0s-ZR0 zEG)-ds3NChbTRVn2+zODNE31H3Anw6iu0(SY`fC-v!6IYUha-NkdnaM=la#AEq-D(6L6AfTPc!)%oyw7QW$OZoal zT|#d25~jp}ZM!0o7TMAw%DGZ2xBryKY0Fa^o?0O#NN?)>*n>x^SCuq0$46I==0`^V zt`x@(!zg2x?9+rtu>rX!@oyVJ^HQ=4;o!~@WvEhe#@j=BeZM01T5I)ej1wBcK*gwzODNsZG+!D6~svB$4GeQ;g}Mg2GtHuie9{0^gP-OCS- z{*yn_`YO;0@Pp+v{ST_Er4rBpwpt*T$&4vu+a%LU{JQz5POqojn2*RI=p<}ffg09s zsZJOFdQV~#uv(aP?_z}9?5J)(oBi&ST}Mo;0t7U+51PLWoo38kSJawY)T|XNF8ODs zns?s1mc!%;xZw_nuI1(_$i?_zxoDQdU0g5P5R6TE(?+Ha1{INE54H(O(@f zVZ0$zBeJYA^V1Y-HrlYz0Hy{4`<79(Xywexn>*_YAcl$*4xwoo0Tmu z3Iwzv?cSJJ2Nw6?;^lxoCm<9V4ja6=ePAd=Xy&`sj7GNwbqNxguMQ@P^qFoa z{Z0*8A;Y}B6y}qX2TSa$(<4~WXnvi=b(4V9`9uqa18gy%3934=;%*GZ9H2m4d^!q^ z+(9;YqzPx%o4Z(r`~x!IGQ?N)l4dkP+k5<+4WahV!ZZ(8YOPwtuF25yjC&BZZp_)q z*~eUoXsS%g75<>tidjpEPyc4wv%X@^g=-X;(y$r)+Y7QLw5?=Qnc=35!;Fx`MFZqU zS;*Bol@Veq_Komd0|ouYp1R9?ymKbNqifj2bNk|5F5Q@4`VJrnH-Mr5$-+QP z0DwR$Xv@0_&j0ltGx8j3=&xR&LUAlPqljU22G<(9I__Y9K3H&zv)dlUNEPJzYHaKf z=SjBc8O#>3v4u83Ut#1FR4Ko%v|f-+!N8+YHl$031<0MvWfrF-Ea|VfX#&G2VyzsF z;CrSNWvG$ERpYlV{b->?7JA}?BF66nr(Su!E@pRM<~;sMr)gHwrDH4%Ro}=*{cAR; zFT1l_W$T0J+CAlyTl$z#{8BdnSn~2)01F;nw(e77cdO*{6Cu#t9vc*r?wR_$O91`^ zN5b8%Nv6_b9ei#irU>q1{%QwY@0w^K?H*XpzF8}MP21Sbj5iX)j)4Q43?z$XbPLx^ zmYm>)xk}zROoxx>NinpaXY)UnT*d}PZVt=7&EO4fhooPJ zm0=xtC@=a#@zmMXrZZJ2Jh4vh+0lLYa!jEYWdv9B>H&Vx5BRWEnUNj<)IPTY*3M;U zW)U%LV9#23s)DUEc><0F43c$Aa*r)4)2EQEF&+v1g-c(<76C&gz;vLLhsd@2-vU4{6U~ zw(2jd3xatf{ut61u91t-^)^c(6q|bwI~}^U;mESO5qmX1ov9@d(BTC3dqYry81CZRJteU1pIXu9fTQVG7oF#-_=Gs+x$ zuw~TyX*3vRQ9xY(0hkT+=e@gtU-1pL4$Tup1dQ2jxrBqVTb0GU_6Zy>8P{(qwKkwc zRG0`jNzbpOGsW!RTuGwEsA5U2=&o9+bb{|ZsnG!rV-(0u|I~Ns2nl(Cyb0Z>MecNN zMut=*4rePUO-`dw0*YkP4<~m*I4nDSAD%2Eu~jW(n~igLdhy3b71o|Ssk0~3pWBBW zMu9}%x@jL2pULWZ2wIl}iOnRG^DC33ZL=r94sxgzK2qZ#OkWspq-F2{v-UezVJo_J z3mA$;WdTdaWlXYZqd0SgBmflU__GuX4-{z|+%M2#F=+_MA%xgPYQH^)ZcNeZx$KW=o z@`DE#*aFFcdB8SzL3l0mGm{rVdR*)WF2c-}($43I7RAcvNB6r6l=4O6i9Vs4hUCt- znI~B70>9<=KipZ+%NtM`S>26o#pFyh12vXC4-lA$M+ya`BraGw%g6}I= z(X8VuNMNSmn&;ZHRKkr)f2tVvboWFuw#jSQpica5L2fKh@P-CtEsWG_ zQ;gBLPUj0cNpX7#rsF|jd>7%R4HT?YaI)oUUy>R7OH<#8CeMr1xAI=jMEtB-|tVRzGwik)DhTbmp1(ioi!FM8RdtZ|1PLDqjbK! z#_g~0YU=>M&)+zCD})-s+pdW1kWP=*nhM>hHR9>)1H@t5I|FO|P(Dal+>5 zV%!(Y!}b6UVqeJat$zjI 254 +#error EINK_NUMBUFFERS must be at most 254. +#endif + +#define BLOCKS_Y (GDISP_SCREEN_HEIGHT / EINK_BLOCKHEIGHT) +#define BLOCKS_X (GDISP_SCREEN_WIDTH / EINK_BLOCKWIDTH) +#define WIDTH_BYTES (EINK_BLOCKWIDTH / EINK_PPB) + +/* Buffers that store the data for a small area of the display. */ +typedef struct { + uint8_t data[EINK_BLOCKHEIGHT][WIDTH_BYTES]; +} block_t; + +static uint8_t g_next_block; /* Index of the next free block buffer. */ +static block_t g_blocks[EINK_NUMBUFFERS]; + +/* Map that stores the buffers associated to each area of the display. + * Value of 0 means that the block is not allocated. + * Other values are the index in g_blocks + 1. + */ +static uint8_t g_blockmap[BLOCKS_Y][BLOCKS_X]; + +/** Check if the row contains any allocated blocks. */ +static bool_t blocks_on_row(unsigned by) +{ + unsigned bx; + for (bx = 0; bx < BLOCKS_X; bx++) + { + if (g_blockmap[by][bx] != 0) + { + return TRUE; + } + } + return FALSE; +} + +/** Write out a block row. */ +static void write_block_row(unsigned by) +{ + unsigned bx, dy, dx; + for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) + { + hscan_start(); + for (bx = 0; bx < BLOCKS_X; bx++) + { + if (g_blockmap[by][bx] == 0) + { + for (dx = 0; dx < WIDTH_BYTES; dx++) + { + const uint8_t dummy = 0; + hscan_write(&dummy, 1); + } + } + else + { + block_t *block = &g_blocks[g_blockmap[by][bx] - 1]; + hscan_write(&block->data[dy][0], WIDTH_BYTES); + } + } + hscan_stop(); + + vscan_write(); + } +} + +/** Clear the block map, i.e. deallocate all blocks */ +static void clear_block_map() +{ + unsigned bx, by; + for (by = 0; by < BLOCKS_Y; by++) + { + for (bx = 0; bx < BLOCKS_X; bx++) + { + g_blockmap[by][bx] = 0; + } + } + + g_next_block = 0; +} + +/** Flush all the buffered rows to display. */ +static void flush_buffers() +{ + unsigned by, dy, i; + + for (i = 0; i < EINK_WRITECOUNT; i++) + { + vscan_start(); + + for (by = 0; by < BLOCKS_Y; by++) + { + if (!blocks_on_row(by)) + { + /* Skip the whole row of blocks. */ + for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) + { + vscan_skip(); + } + } + else + { + /* Write out the blocks. */ + write_block_row(by); + } + } + + vscan_stop(); + } + + clear_block_map(); +} + +/** Initialize a newly allocated block. */ +static void zero_block(block_t *block) +{ + unsigned dx, dy; + for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) + { + for (dx = 0; dx < WIDTH_BYTES; dx++) + { + block->data[dy][dx] = 0; + } + } +} + +/** Allocate a buffer + * Automatically flushes if all buffers are full. */ +static block_t *alloc_buffer(unsigned bx, unsigned by) +{ + block_t *result; + if (g_blockmap[by][bx] == 0) + { + if (g_next_block >= EINK_NUMBUFFERS) + { + flush_buffers(); + } + + result = &g_blocks[g_next_block]; + g_blockmap[by][bx] = g_next_block + 1; + g_next_block++; + zero_block(result); + return result; + } + else + { + result = &g_blocks[g_blockmap[by][bx] - 1]; + return result; + } +} + +/* =============================== + * Public functions + * =============================== */ + +bool_t gdisp_lld_init(void) +{ + init_board(); + + /* Make sure that all the pins are in "off" state. + * Having any pin high could cause voltage leaking to the + * display, which in turn causes the image to leak slowly away. + */ + power_off(); + + clear_block_map(); + + /* Initialize the global GDISP structure */ + GDISP.Width = GDISP_SCREEN_WIDTH; + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Orientation = GDISP_ROTATE_0; + GDISP.Powermode = powerOff; + GDISP.Backlight = 0; + GDISP.Contrast = 0; + #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + GDISP.clipx0 = 0; + GDISP.clipy0 = 0; + GDISP.clipx1 = GDISP.Width; + GDISP.clipy1 = GDISP.Height; + #endif + + return TRUE; +} + +void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) +{ + block_t *block; + uint8_t byte; + unsigned bx, by, dx, dy; + uint8_t bitpos; + + bx = x / EINK_BLOCKWIDTH; + by = y / EINK_BLOCKHEIGHT; + dx = x % EINK_BLOCKWIDTH; + dy = y % EINK_BLOCKHEIGHT; + + if (bx < 0 || bx >= BLOCKS_X || by < 0 || by >= BLOCKS_Y) + return; + + block = alloc_buffer(bx, by); + + bitpos = (6 - 2 * (dx % EINK_PPB)); + byte = block->data[dy][dx / EINK_PPB]; + byte &= ~(PIXELMASK << bitpos); + if (color) + { + byte |= PIXEL_WHITE << bitpos; + } + else + { + byte |= PIXEL_BLACK << bitpos; + } + block->data[dy][dx / EINK_PPB] = byte; +} + +#if !GDISP_NEED_CONTROL +#error You must enable GDISP_NEED_CONTROL for the E-Ink driver. +#endif + +void gdisp_lld_control(unsigned what, void *value) { + gdisp_powermode_t newmode; + + switch(what) + { + case GDISP_CONTROL_POWER: + newmode = (gdisp_powermode_t)value; + + if (GDISP.Powermode == newmode) + return; + + if (newmode == powerOn) + { + power_on(); + } + else + { + flush_buffers(); + power_off(); + } + GDISP.Powermode = newmode; + break; + + case GDISP_CONTROL_FLUSH: + flush_buffers(); + break; + } +} + +/* =============================== + * Accelerated routines + * =============================== */ + +#if GDISP_HARDWARE_CLEARS + +static void subclear(color_t color) +{ + unsigned x, y; + uint8_t byte; + + hscan_start(); + byte = color ? BYTE_WHITE : BYTE_BLACK; + for (x = 0; x < GDISP_SCREEN_WIDTH; x++) + { + hscan_write(&byte, 1); + } + hscan_stop(); + + setpin_oe(TRUE); + vscan_start(); + for (y = 0; y < GDISP_SCREEN_HEIGHT; y++) + { + vscan_bulkwrite(); + } + vscan_stop(); + setpin_oe(FALSE); +} + +void gdisp_lld_clear(color_t color) +{ + unsigned i; + clear_block_map(); + + if (EINK_BLINKCLEAR) + { + subclear(!color); + gfxSleepMilliseconds(50); + } + + for (i = 0; i < EINK_CLEARCOUNT; i++) + { + subclear(color); + gfxSleepMilliseconds(10); + } + +} +#endif + +#endif diff --git a/drivers/gdisp/ED060SC4/gdisp_lld.mk b/drivers/gdisp/ED060SC4/gdisp_lld.mk new file mode 100644 index 00000000..d5c1492f --- /dev/null +++ b/drivers/gdisp/ED060SC4/gdisp_lld.mk @@ -0,0 +1,2 @@ +GFXSRC += $(GFXLIB)/drivers/gdisp/ED060SC4/gdisp_lld.c +GFXINC += $(GFXLIB)/drivers/gdisp/ED060SC4 diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h b/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h new file mode 100644 index 00000000..98f05ee8 --- /dev/null +++ b/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h @@ -0,0 +1,127 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/* Board interface definitions for ED060SC4 PrimeView E-ink panel. + * + * This file corresponds to the connections shown in example_schematics.png, + * and is designed to interface with ChibiOS/RT. + * + * Please note that this file has never been tested in exactly this pin + * configuration, because the actual boards I have are slightly different. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +#include + +/* + * IO pins assignments. + */ +#define GPIOB_EINK_VDD 0 +#define GPIOB_EINK_GMODE 1 +#define GPIOB_EINK_SPV 2 +#define GPIOB_EINK_CKV 3 +#define GPIOB_EINK_CL 4 +#define GPIOB_EINK_LE 5 +#define GPIOB_EINK_OE 6 +#define GPIOB_EINK_SPH 7 +#define GPIOB_EINK_D0 8 +#define GPIOB_EINK_D1 9 +#define GPIOB_EINK_D2 10 +#define GPIOB_EINK_D3 11 +#define GPIOB_EINK_D4 12 +#define GPIOB_EINK_D5 13 +#define GPIOB_EINK_D6 14 +#define GPIOB_EINK_D7 15 + +#define GPIOC_SMPS_CTRL 13 +#define GPIOC_VPOS_CTRL 14 +#define GPIOC_VNEG_CTRL 15 + + +/* Set up IO pins for the panel connection. */ +static inline void init_board(void) { + /* Main SMPS power control, active low + * (open collector so that MOSFET gate can be pulled up to Vbat) */ + palWritePad(GPIOC, GPIOC_SMPS_CTRL, true); + palSetPadMode(GPIOC, GPIOC_SMPS_CTRL, PAL_MODE_OUTPUT_OPENDRAIN); + + /* Power control for the positive & negative side */ + palWritePad(GPIOC, GPIOC_VPOS_CTRL, false); + palSetPadMode(GPIOC, GPIOC_VPOS_CTRL, PAL_MODE_OUTPUT_PUSHPULL); + palWritePad(GPIOC, GPIOC_VNEG_CTRL, false); + palSetPadMode(GPIOC, GPIOC_VNEG_CTRL, PAL_MODE_OUTPUT_PUSHPULL); + + /* Main data bus */ + palWritePort(GPIOB, 0); + palSetGroupMode(GPIOB, 0xFFFF, 0, PAL_MODE_OUTPUT_PUSHPULL); +} + +/* Delay for display waveforms. Should be an accurate microsecond delay. */ +static void eink_delay(int us) +{ + halPolledDelay(US2RTT(us)); +} + +/* Turn the E-ink panel Vdd supply (+3.3V) on or off. */ +static inline void setpower_vdd(bool_t on) { + palWritePad(GPIOB, GPIOB_SMPS_CTRL, !on); + palWritePad(GPIOA, GPIOA_EINK_VDD, on); +} + +/* Turn the E-ink panel negative supplies (-15V, -20V) on or off. */ +static inline void setpower_vneg(bool_t on) { + palWritePad(GPIOA, GPIOA_VNEG_CTRL, on); +} + +/* Turn the E-ink panel positive supplies (-15V, -20V) on or off. */ +static inline void setpower_vpos(bool_t on) { + palWritePad(GPIOA, GPIOA_VPOS_CTRL, on); +} + +/* Set the state of the LE (source driver Latch Enable) pin. */ +static inline void setpin_le(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_LE, on); +} + +/* Set the state of the OE (source driver Output Enable) pin. */ +static inline void setpin_oe(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_OE, on); +} + +/* Set the state of the CL (source driver Clock) pin. */ +static inline void setpin_cl(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_CL, on); +} + +/* Set the state of the SPH (source driver Start Pulse Horizontal) pin. */ +static inline void setpin_sph(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_SPH, on); +} + +/* Set the state of the D0-D7 (source driver Data) pins. */ +static inline void setpins_data(uint8_t value) { + palWriteGroup(GPIOB, 0xFF, GPIOB_EINK_D0, value); +} + +/* Set the state of the CKV (gate driver Clock Vertical) pin. */ +static inline void setpin_ckv(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_CKV, on); +} + +/* Set the state of the GMODE (gate driver Gate Mode) pin. */ +static inline void setpin_gmode(bool_t on) { + palWritePad(GPIOC, GPIOC_EINK_GMODE, on); +} + +/* Set the state of the SPV (gate driver Start Pulse Vertical) pin. */ +static inline void setpin_spv(bool_t on) { + palWritePad(GPIOB, GPIOB_EINK_SPV, on); +} + +#endif diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h b/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h new file mode 100644 index 00000000..68129bf8 --- /dev/null +++ b/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h @@ -0,0 +1,83 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/* Board interface definitions for ED060SC4 PrimeView E-ink panel. + * + * You should implement the following functions to define the interface to + * the panel on your board. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/* Set up IO pins for the panel connection. */ +static inline void init_board(void) { + #error Unimplemented +} + +/* Delay for display waveforms. Should be an accurate microsecond delay. */ +static void eink_delay(int us) +{ + #error Unimplemented +} + +/* Turn the E-ink panel Vdd supply (+3.3V) on or off. */ +static inline void setpower_vdd(bool_t on) { + #error Unimplemented +} + +/* Turn the E-ink panel negative supplies (-15V, -20V) on or off. */ +static inline void setpower_vneg(bool_t on) { + #error Unimplemented +} + +/* Turn the E-ink panel positive supplies (-15V, -20V) on or off. */ +static inline void setpower_vpos(bool_t on) { + #error Unimplemented +} + +/* Set the state of the LE (source driver Latch Enable) pin. */ +static inline void setpin_le(bool_t on) { + #error Unimplemented +} + +/* Set the state of the OE (source driver Output Enable) pin. */ +static inline void setpin_oe(bool_t on) { + #error Unimplemented +} + +/* Set the state of the CL (source driver Clock) pin. */ +static inline void setpin_cl(bool_t on) { + #error Unimplemented +} + +/* Set the state of the SPH (source driver Start Pulse Horizontal) pin. */ +static inline void setpin_sph(bool_t on) { + #error Unimplemented +} + +/* Set the state of the D0-D7 (source driver Data) pins. */ +static inline void setpins_data(uint8_t value) { + #error Unimplemented +} + +/* Set the state of the CKV (gate driver Clock Vertical) pin. */ +static inline void setpin_ckv(bool_t on) { + #error Unimplemented +} + +/* Set the state of the GMODE (gate driver Gate Mode) pin. */ +static inline void setpin_gmode(bool_t on) { + #error Unimplemented +} + +/* Set the state of the SPV (gate driver Start Pulse Vertical) pin. */ +static inline void setpin_spv(bool_t on) { + #error Unimplemented +} + +#endif diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_config.h b/drivers/gdisp/ED060SC4/gdisp_lld_config.h new file mode 100644 index 00000000..befd997c --- /dev/null +++ b/drivers/gdisp/ED060SC4/gdisp_lld_config.h @@ -0,0 +1,27 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/* Supported features of the driver for ED060SC4 PrimeView E-Ink panel. */ + +#ifndef _GDISP_LLD_CONFIG_H +#define _GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +#define GDISP_DRIVER_NAME "ED060SC4" +#define GDISP_HARDWARE_CLEARS TRUE +#define GDISP_HARDWARE_FILLS FALSE +#define GDISP_HARDWARE_BITFILLS FALSE +#define GDISP_HARDWARE_SCROLL FALSE +#define GDISP_HARDWARE_PIXELREAD FALSE +#define GDISP_HARDWARE_CONTROL TRUE + +#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_MONO + +#endif + +#endif diff --git a/drivers/gdisp/ED060SC4/readme.txt b/drivers/gdisp/ED060SC4/readme.txt new file mode 100644 index 00000000..5409d810 --- /dev/null +++ b/drivers/gdisp/ED060SC4/readme.txt @@ -0,0 +1,85 @@ +1. Introduction + +This is a driver for ED060SC4 800x600 e-ink display panel manufactured by +Prime View. Note that this driver uses a direct connection to the panel from +the processor; it does not use a separate controller chip between the processor +and the panel. + +To use the driver, you need to be able to control the following signals from +your processor: + +Gate driver: SPV, CKV, GMODE. +Source driver: CL, LE, OE, SPH, D0-D7. +Power supply: +-15V, +22V, -20V, digital Vdd + +The file "example_schematics.png" shows how to connect the signals to e.g. a +STM32L151 microcontroller. It also includes an example circuit for providing +the panel supply voltages. + +Note that the larger panels (such as the 800x600) consist of multiple segments +with separate gate driver signals. These can be daisy chained as shown in the +example schematic. + + + + +2. Frame buffer emulation + +Because there is not enough memory to store a full frame buffer on the +processor, this driver emulates a frame buffer by storing the display data in +blocks. It will buffer up to EINK_NUMBUFFERS blocks and then write them to the +screen. The following #defines control the buffering. Larger numbers will +result in faster drawing, but also use more RAM on the processor: + +#define EINK_BLOCKWIDTH 20 // Width of a single block in buffer +#define EINK_BLOCKHEIGHT 20 // Height of a single block in buffers +#define EINK_NUMBUFFERS 40 // Number of blocks to buffer + +After drawing your images, you should flush the buffers using the following +command: + + #include + gdispControl(GDISP_CONTROL_FLUSH, 0); + +The buffers are also flushed whenever you turn the display off using: + + gdispSetPowerMode(powerOff); + + + +3. Display clearing and writing waveforms + +This driver does not know the official Prime View waveforms for driving the +display, mostly because those are trade secrets and not publicly available. +Instead, it uses reverse engineered waveforms that are mostly functional. + +The following #defines control the waveforms: + +#define EINK_BLINKCLEAR TRUE // Clear to opposite color first +#define EINK_CLEARCOUNT 10 // Number of sweeps to clear the display +#define EINK_WRITECOUNT 4 // Number of sweeps when writing to display + +Increasing the clearcount and writecount can improve contrast, but will also +slow down the drawing and use more power. + + + +4. Clock speeds + +Because the driver bit bangs the display, the clock frequency of the processor +is quite significant. This is controlled by EINK_CLOCKDELAY variable. Set it +so that the delay is atleast 50 nanoseconds. + + + +5. Support for other kinds of panels + +Most of the Prime View panels should work using this driver, but only ED060SC4 +has been tested so far. Some points of consideration: + +- Some displays may use 4 bits per pixel. The driver currently assumes 2 bits + per pixel. +- Larger displays may require some other way of daisy chaining than shown in + the example schematics. + + From 5541e6a96c34fbb5bdfe4a491e8acb1107d290ce Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 25 Sep 2013 17:28:49 +1000 Subject: [PATCH 014/160] Nokia6610 streaming driver orientation is NOT supported yet --- drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h index e6834d13..93debcd1 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h @@ -27,7 +27,7 @@ #define GDISP_HARDWARE_STREAM TRUE #define GDISP_HARDWARE_STREAM_STOP TRUE -#define GDISP_HARDWARE_CONTROL TRUE +//#define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 /* This driver supports both packed and unpacked pixel formats and line formats. From 2907c6114dabb4287e12b21313f3ab35b5c4a628 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 25 Sep 2013 17:29:24 +1000 Subject: [PATCH 015/160] Useless leftover from ASYNC support is now removed --- include/gdisp/lld/gdisp_lld_msgs.h | 181 ----------------------------- 1 file changed, 181 deletions(-) delete mode 100644 include/gdisp/lld/gdisp_lld_msgs.h diff --git a/include/gdisp/lld/gdisp_lld_msgs.h b/include/gdisp/lld/gdisp_lld_msgs.h deleted file mode 100644 index 2c199cbe..00000000 --- a/include/gdisp/lld/gdisp_lld_msgs.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file include/gdisp/lld/gdisp_lld_msgs.h - * @brief GDISP Graphic Driver subsystem low level driver message structures. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_MSGS_H -#define _GDISP_LLD_MSGS_H - -/* This file describes the message API for gdisp_lld */ -#if GFX_USE_GDISP && GDISP_NEED_MSGAPI - -typedef enum gdisp_msgaction { - GDISP_LLD_MSG_NOP, - GDISP_LLD_MSG_INIT, - GDISP_LLD_MSG_CLEAR, - GDISP_LLD_MSG_DRAWPIXEL, - GDISP_LLD_MSG_FILLAREA, - GDISP_LLD_MSG_BLITAREA, - GDISP_LLD_MSG_DRAWLINE, - #if GDISP_NEED_CLIP - GDISP_LLD_MSG_SETCLIP, - #endif - #if GDISP_NEED_CIRCLE - GDISP_LLD_MSG_DRAWCIRCLE, - GDISP_LLD_MSG_FILLCIRCLE, - #endif - #if GDISP_NEED_ELLIPSE - GDISP_LLD_MSG_DRAWELLIPSE, - GDISP_LLD_MSG_FILLELLIPSE, - #endif - #if GDISP_NEED_ARC - GDISP_LLD_MSG_DRAWARC, - GDISP_LLD_MSG_FILLARC, - #endif - #if GDISP_NEED_PIXELREAD - GDISP_LLD_MSG_GETPIXELCOLOR, - #endif - #if GDISP_NEED_SCROLL - GDISP_LLD_MSG_VERTICALSCROLL, - #endif - #if GDISP_NEED_CONTROL - GDISP_LLD_MSG_CONTROL, - #endif - GDISP_LLD_MSG_QUERY, -} gdisp_msgaction_t; - -typedef union gdisp_lld_msg { - struct { - gfxQueueItem qi; - gdisp_msgaction_t action; - }; - struct gdisp_lld_msg_init { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_INIT - } init; - struct gdisp_lld_msg_clear { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_CLEAR - color_t color; - } clear; - struct gdisp_lld_msg_drawpixel { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWPIXEL - coord_t x, y; - color_t color; - } drawpixel; - struct gdisp_lld_msg_fillarea { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_FILLAREA - coord_t x, y; - coord_t cx, cy; - color_t color; - } fillarea; - struct gdisp_lld_msg_blitarea { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_BLITAREA - coord_t x, y; - coord_t cx, cy; - coord_t srcx, srcy; - coord_t srccx; - const pixel_t *buffer; - } blitarea; - struct gdisp_lld_msg_setclip { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_SETCLIP - coord_t x, y; - coord_t cx, cy; - } setclip; - struct gdisp_lld_msg_drawline { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWLINE - coord_t x0, y0; - coord_t x1, y1; - color_t color; - } drawline; - struct gdisp_lld_msg_drawcircle { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWCIRCLE - coord_t x, y; - coord_t radius; - color_t color; - } drawcircle; - struct gdisp_lld_msg_fillcircle { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_FILLCIRCLE - coord_t x, y; - coord_t radius; - color_t color; - } fillcircle; - struct gdisp_lld_msg_drawellipse { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWELLIPSE - coord_t x, y; - coord_t a, b; - color_t color; - } drawellipse; - struct gdisp_lld_msg_fillellipse { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_FILLELLIPSE - coord_t x, y; - coord_t a, b; - color_t color; - } fillellipse; - struct gdisp_lld_msg_drawarc { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWARC - coord_t x, y; - coord_t radius; - coord_t startangle, endangle; - color_t color; - } drawarc; - struct gdisp_lld_msg_fillarc { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_FILLARC - coord_t x, y; - coord_t radius; - coord_t startangle, endangle; - color_t color; - } fillarc; - struct gdisp_lld_msg_getpixelcolor { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_GETPIXELCOLOR - coord_t x, y; - color_t result; - } getpixelcolor; - struct gdisp_lld_msg_verticalscroll { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_VERTICALSCROLL - coord_t x, y; - coord_t cx, cy; - int lines; - color_t bgcolor; - } verticalscroll; - struct gdisp_lld_msg_control { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_CONTROL - int what; - void * value; - } control; - struct gdisp_lld_msg_query { - gfxQueueItem qi; - gdisp_msgaction_t action; // GDISP_LLD_MSG_QUERY - int what; - void * result; - } query; -} gdisp_lld_msg_t; - -#endif /* GFX_USE_GDISP && GDISP_NEED_MSGAPI */ -#endif /* _GDISP_LLD_MSGS_H */ -/** @} */ - From 9c55df546763b9fd4912d3fbb36af1e2990969ba Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 27 Sep 2013 01:35:29 +1000 Subject: [PATCH 016/160] Fix compiler warning in image code --- src/gdisp/image.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gdisp/image.c b/src/gdisp/image.c index 89f42ee1..1e9ac3d6 100644 --- a/src/gdisp/image.c +++ b/src/gdisp/image.c @@ -16,6 +16,8 @@ #if GFX_USE_GDISP && GDISP_NEED_IMAGE +#include + /* The structure defining the routines for image drawing */ typedef struct gdispImageHandlers { gdispImageError (*open)(gdispImage *img); /* The open function */ From a7360c13c2f4527d38888a249d2ce83ed2dc41f0 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 27 Sep 2013 01:36:31 +1000 Subject: [PATCH 017/160] Update animated image demo to better support small displays --- .../modules/gdisp/gdisp_images_animated/main.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/demos/modules/gdisp/gdisp_images_animated/main.c b/demos/modules/gdisp/gdisp_images_animated/main.c index c5260174..58558185 100644 --- a/demos/modules/gdisp/gdisp_images_animated/main.c +++ b/demos/modules/gdisp/gdisp_images_animated/main.c @@ -38,7 +38,7 @@ #define USE_MEMORY_FILE TRUE // Non-Win32 - use the compiled in image #endif -#define SHOW_ERROR(color) gdispFillArea(swidth-10, 0, 10, sheight, color) +#define SHOW_ERROR(color) gdispFillArea(errx, erry, errcx, errcy, color) #if USE_MEMORY_FILE #include "testanim.h" @@ -57,7 +57,7 @@ static gdispImage myImage; * Orange - Decoding a frame has produced an error. */ int main(void) { - coord_t swidth, sheight; + coord_t swidth, sheight, errx, erry, errcx, errcy; delaytime_t delay; gfxInit(); // Initialize the display @@ -68,6 +68,12 @@ int main(void) { swidth = gdispGetWidth(); sheight = gdispGetHeight(); + // Work out our error indicator area + errx = swidth-10; + erry = 0; + errcx = 10; + errcy = sheight; + // Set up IO for our image #if USE_MEMORY_FILE gdispImageSetMemoryReader(&myImage, testanim); @@ -77,11 +83,16 @@ int main(void) { if (gdispImageOpen(&myImage) == GDISP_IMAGE_ERR_OK) { gdispImageSetBgColor(&myImage, MY_BG_COLOR); + // Adjust the error indicator area if necessary + if (myImage.width > errx && myImage.height < sheight) { + errx = 0; erry = sheight-10; + errcx = swidth; errcy = 10; + } while(1) { #if USE_IMAGE_CACHE gdispImageCache(&myImage); #endif - if (gdispImageDraw(&myImage, 5, 5, myImage.width, myImage.height, 0, 0) != GDISP_IMAGE_ERR_OK) { + if (gdispImageDraw(&myImage, 0, 0, myImage.width, myImage.height, 0, 0) != GDISP_IMAGE_ERR_OK) { SHOW_ERROR(Orange); break; } From 548eb3c981772ec4be1211352867f2edcdc24423 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 27 Sep 2013 01:37:32 +1000 Subject: [PATCH 018/160] GDISP Streaming bug fixes and new optimisation method --- src/gdisp/gdisp.c | 81 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 11 deletions(-) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 2e423764..828e5aa9 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -185,7 +185,7 @@ static void hline_clip(void) { gdisp_lld_fill_area(GC); #elif GDISP_HARDWARE_STREAM // Next best is streaming - GC->p.cx = GC->p.x1 - GC->p.x; + GC->p.cx = GC->p.x1 - GC->p.x + 1; GC->p.cy = 1; gdisp_lld_stream_start(GC); do { gdisp_lld_stream_color(GC); } while(GC->p.cx--); @@ -243,7 +243,7 @@ static void vline_clip(void) { gdisp_lld_fill_area(GC); #elif GDISP_HARDWARE_STREAM // Next best is streaming - GC->p.cy = GC->p.y1 - GC->p.y; + GC->p.cy = GC->p.y1 - GC->p.y + 1; GC->p.cx = 1; gdisp_lld_stream_start(GC); do { gdisp_lld_stream_color(GC); } while(GC->p.cy--); @@ -392,7 +392,10 @@ void _gdispInit(void) { GC->p.y1 = GC->p.y = y; GC->p.x2 = x + cx; GC->p.y2 = y + cy; - GC->p.cx = 0; + #if (GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS) || GDISP_HARDWARE_FILLS + GC->p.cx = 0; + GC->p.cy = 1; + #endif #endif // Don't release the mutex as gdispStreamEnd() will do that. @@ -415,12 +418,9 @@ void _gdispInit(void) { gdisp_lld_stream_color(GC); #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS GC->linebuf[GC->p.cx++] = color; - GC->p.x++; if (GC->p.cx >= GDISP_LINEBUF_SIZE) { sx1 = GC->p.x1; sy1 = GC->p.y1; - GC->p.x -= GC->p.cx; - GC->p.cy = 1; GC->p.x1 = 0; GC->p.y1 = 0; GC->p.ptr = (void *)GC->linebuf; @@ -432,12 +432,10 @@ void _gdispInit(void) { } // Just wrap at end-of-line and end-of-buffer - if (GC->p.x >= GC->p.x2) { + if (GC->p.x+GC->p.cx >= GC->p.x2) { if (GC->p.cx) { sx1 = GC->p.x1; sy1 = GC->p.y1; - GC->p.x -= GC->p.cx; - GC->p.cy = 1; GC->p.x1 = 0; GC->p.y1 = 0; GC->p.ptr = (void *)GC->linebuf; @@ -450,6 +448,33 @@ void _gdispInit(void) { if (++GC->p.y >= GC->p.y2) GC->p.y = GC->p.y1; } + #elif GDISP_HARDWARE_FILLS + // Only slightly better than drawing pixels is to look for runs and use fill area + if (!GC->p.cx || GC->p.color == color) { + GC->p.cx++; + GC->p.color = color; + } else { + if (GC->p.cx == 1) + gdisp_lld_draw_pixel(GC); + else + gdisp_lld_fill_area(GC); + GC->p.x += GC->p.cx; + GC->p.color = color; + GC->p.cx = 1; + } + // Just wrap at end-of-line and end-of-buffer + if (GC->p.x+GC->p.cx >= GC->p.x2) { + if (GC->p.cx) { + if (GC->p.cx == 1) + gdisp_lld_draw_pixel(GC); + else + gdisp_lld_fill_area(GC); + GC->p.cx = 0; + } + GC->p.x = GC->p.x1; + if (++GC->p.y >= GC->p.y2) + GC->p.y = GC->p.y1; + } #else // Worst is using pixel drawing GC->p.color = color; @@ -475,13 +500,18 @@ void _gdispInit(void) { #endif #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS if (GC->p.cx) { - GC->p.x -= GC->p.cx; - GC->p.cy = 1; GC->p.x1 = 0; GC->p.y1 = 0; GC->p.ptr = (void *)GC->linebuf; gdisp_lld_blit_area(GC); } + #elif GDISP_HARDWARE_FILLS + if (GC->p.cx) { + if (GC->p.cx == 1) + gdisp_lld_draw_pixel(GC); + else + gdisp_lld_fill_area(GC); + } #endif GC->flags &= ~GDISP_FLG_INSTREAM; MUTEX_EXIT(); @@ -595,6 +625,10 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, srcy = y + cy; srccx -= cx; + GC->p.x = x; + GC->p.y = y; + GC->p.cx = cx; + GC->p.cy = cy; gdisp_lld_stream_start(GC); for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { for(GC->p.x = x; GC->p.x < srcx; GC->p.x++) { @@ -605,6 +639,31 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, #if GDISP_HARDWARE_STREAM_STOP gdisp_lld_stream_stop(GC); #endif + #elif GDISP_HARDWARE_FILLS + // Only slightly better than drawing pixels is to look for runs and use fill area + + // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap + buffer += srcy*srccx+srcx; + srcx = x + cx; + srcy = y + cy; + srccx -= cx; + + GC->p.cy = 1; + for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { + for(GC->p.x=x; GC->p.x < srcx; GC->p.x += GC->p.cx) { + GC->p.cx=1; + GC->p.color = *buffer++; + while(GC->p.x+GC->p.cx < srcx && *buffer == GC->p.color) { + GC->p.cx++; + buffer++; + } + if (GC->p.cx == 1) { + gdisp_lld_draw_pixel(GC); + } else { + gdisp_lld_fill_area(GC); + } + } + } #else // Worst is drawing pixels From c71a227efdfc7c9dbb65259b6d010333a07193c6 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 27 Sep 2013 01:38:37 +1000 Subject: [PATCH 019/160] Nokia6610 GE8 driver: Orientation support and fixes for some controller nasties --- drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 344 +++++++++--------- drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h | 15 +- 2 files changed, 183 insertions(+), 176 deletions(-) diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index e16c6d5c..e51e780f 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -37,12 +37,19 @@ * * The controller has some quirkyness when operating in other than rotation 0 mode. * When any direction is decremented it starts at location 0 rather than the end of - * the area. + * the area. Whilst this can be handled when we know the specific operation (pixel, fill, blit) + * it cannot be handled in a generic stream operation. So, when orientation support is turned + * on (and needed) we use complex operation specific routines instead of simple streaming + * routines. This has a (small) performance penalty and a significant code size penalty so + * don't turn on orientation support unless you really need it. * * Some of the more modern controllers have a broken command set. If you have one of these * you will recognise it by the colors being off on anything drawn after an odd (as opposed to * even) pixel count area being drawn. If so then set GDISP_GE8_BROKEN_CONTROLLER to TRUE - * on your gdisp_lld_board.h file. + * on your gdisp_lld_board.h file. The price is that streaming calls that are completed + * without exactly the window size write operations and where the number of write operations + * is odd (rather than even), it will draw an extra pixel. If this is important to you, turn on + * orientation support and the streaming operations will be emulated (as described above). */ /*===========================================================================*/ @@ -100,9 +107,11 @@ /* Driver local variables. */ /*===========================================================================*/ -static color_t savecolor; -#if GDISP_GE8_BROKEN_CONTROLLER - static color_t firstcolor; +#if GDISP_HARDWARE_STREAM + static color_t savecolor; + #if GDISP_GE8_BROKEN_CONTROLLER + static color_t firstcolor; + #endif #endif #define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0) @@ -122,10 +131,6 @@ static color_t savecolor; #define write_cmd3(cmd, d1, d2, d3) { write_cmd(cmd); write_data3(d1, d2, d3); } #define write_cmd4(cmd, d1, d2, d3, d4) { write_cmd(cmd); write_data4(d1, d2, d3, d4); } -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ @@ -179,59 +184,36 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return TRUE; } -LLDSPEC void gdisp_lld_stream_start(GDISPDriver *g) { - acquire_bus(); - #if GDISP_NEED_CONTROL - switch(g->g.Orientation) { - case GDISP_ROTATE_0: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set - write_cmd(RAMWR); - break; - case GDISP_ROTATE_90: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1); - write_cmd(RAMWR); - break; - case GDISP_ROTATE_180: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-1); - write_cmd(RAMWR); - break; - case GDISP_ROTATE_270: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y+g->p.cy-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-1); - write_cmd(RAMWR); - break; - } - #else +#if GDISP_HARDWARE_STREAM + LLDSPEC void gdisp_lld_stream_start(GDISPDriver *g) { + acquire_bus(); write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set write_cmd(RAMWR); - #endif - g->flags &= ~(GDISP_FLG_ODDBYTE|GDISP_FLG_RUNBYTE); -} - -LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { - //write_data2(((g->p.color >> 8)&0xFF), (g->p.color & 0xFF)); - - #if GDISP_GE8_BROKEN_CONTROLLER - if (!(g->flags & GDISP_FLG_RUNBYTE)) { - firstcolor = g->p.color; - g->flags |= GDISP_FLG_RUNBYTE; - } - #endif - if ((g->flags & GDISP_FLG_ODDBYTE)) { - // Write the pair of pixels to the display - write_data3(((savecolor >> 4) & 0xFF), (((savecolor << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); - g->flags &= ~GDISP_FLG_ODDBYTE; - } else { - savecolor = g->p.color; - g->flags |= GDISP_FLG_ODDBYTE; + g->flags &= ~(GDISP_FLG_ODDBYTE|GDISP_FLG_RUNBYTE); } -} +#endif -#if GDISP_HARDWARE_STREAM_STOP +#if GDISP_HARDWARE_STREAM + LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { + #if GDISP_GE8_BROKEN_CONTROLLER + if (!(g->flags & GDISP_FLG_RUNBYTE)) { + firstcolor = g->p.color; + g->flags |= GDISP_FLG_RUNBYTE; + } + #endif + if ((g->flags & GDISP_FLG_ODDBYTE)) { + // Write the pair of pixels to the display + write_data3(((savecolor >> 4) & 0xFF), (((savecolor << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); + g->flags &= ~GDISP_FLG_ODDBYTE; + } else { + savecolor = g->p.color; + g->flags |= GDISP_FLG_ODDBYTE; + } + } +#endif + +#if GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_STOP LLDSPEC void gdisp_lld_stream_stop(GDISPDriver *g) { if ((g->flags & GDISP_FLG_ODDBYTE)) { #if GDISP_GE8_BROKEN_CONTROLLER @@ -264,69 +246,73 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { } #endif -#if 0 - void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif +#if GDISP_HARDWARE_DRAWPIXEL + void gdisp_lld_draw_pixel(GDISPDriver *g) { acquire_bus(); - setviewport(x, y, 1, 1); - write_cmd3(RAMWR, 0, (color>>8) & 0x0F, color & 0xFF); + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x); // Column address set + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y); // Page address set + break; + case GDISP_ROTATE_90: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET-1+g->g.Width-g->p.x, GDISP_RAM_Y_OFFSET-1+g->g.Width-g->p.x); + break; + case GDISP_ROTATE_180: + write_cmd2(CASET, GDISP_RAM_X_OFFSET-1+g->g.Width-g->p.x, GDISP_RAM_X_OFFSET-1+g->g.Width-g->p.x); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET-1+g->g.Height-g->p.y, GDISP_RAM_Y_OFFSET-1+g->g.Height-g->p.y); + break; + case GDISP_ROTATE_270: + write_cmd2(CASET, GDISP_RAM_X_OFFSET-1+g->g.Height-g->p.y, GDISP_RAM_X_OFFSET-1+g->g.Height-g->p.y); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x); + break; + } + write_cmd3(RAMWR, 0, (g->p.color>>8) & 0x0F, g->p.color & 0xFF); release_bus(); } #endif /* ---- Optional Routines ---- */ -#if 0 && GDISP_HARDWARE_FILLS - /** - * @brief Fill an area with a color. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { +#if GDISP_HARDWARE_FILLS + void gdisp_lld_fill_area(GDISPDriver *g) { unsigned tuples; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - tuples = (cx*cy+1)>>1; // With an odd sized area we over-print by one pixel. + tuples = (g->p.cx*g->p.cy+1)>>1; // With an odd sized area we over-print by one pixel. // This extra pixel overwrites the first pixel (harmless as it is the same colour) acquire_bus(); - setviewport(x, y, cx, cy); + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set + break; + case GDISP_ROTATE_90: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y+g->p.cy-1); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-1); + break; + case GDISP_ROTATE_180: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-1); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-1); + break; + case GDISP_ROTATE_270: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-1); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1); + break; + } write_cmd(RAMWR); while(tuples--) - write_data3(((color >> 4) & 0xFF), (((color << 4) & 0xF0)|((color >> 8) & 0x0F)), (color & 0xFF)); + write_data3(((g->p.color >> 4) & 0xFF), (((g->p.color << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); release_bus(); } #endif -#if 0 && GDISP_HARDWARE_BITFILLS - /** - * @brief Fill an area with a bitmap. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - coord_t lg; - color_t c1, c2; - unsigned tuples; +#if GDISP_HARDWARE_BITFILLS + void gdisp_lld_blit_area(GDISPDriver *g) { + coord_t lg, x, y; + color_t c1, c2; + unsigned tuples; + const pixel_t *buffer; #if GDISP_PACKED_PIXELS unsigned pnum, pstart; const uint8_t *p; @@ -334,19 +320,29 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { const pixel_t *p; #endif - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif + tuples = (g->p.cx * g->p.cy + 1)>>1; + buffer = (const pixel_t *)g->p.ptr; /* Set up the data window to transfer */ - tuples = (cx * cy + 1)>>1; acquire_bus(); - setviewport(x, y, cx, cy); + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set + break; + case GDISP_ROTATE_90: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y+g->p.cy-1); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-1); + break; + case GDISP_ROTATE_180: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-1); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-1); + break; + case GDISP_ROTATE_270: + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-1); + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1); + break; + } write_cmd(RAMWR); /* @@ -356,30 +352,30 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { * memory write. The controller always starts with column 0 and then decrements * to column cx-1, cx-2 etc. We therefore have to write-out the last bitmap line first. */ - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: x = 0; y = 0; break; - case GDISP_ROTATE_90: x = 0; y = cy-1; break; - case GDISP_ROTATE_180: x = cx-1; y = cy-1; break; - case GDISP_ROTATE_270: x = cx-1; y = 0; break; + switch(g->g.Orientation) { + case GDISP_ROTATE_0: x = 0; y = 0; break; + case GDISP_ROTATE_90: x = g->p.cx-1; y = 0; break; + case GDISP_ROTATE_180: x = g->p.cx-1; y = g->p.cy-1; break; + case GDISP_ROTATE_270: x = 0; y = g->p.cy-1; break; } #if !GDISP_PACKED_PIXELS // Although this controller uses packed pixels we support unpacked pixel // formats in this blit by packing the data as we feed it to the controller. - lg = srccx - cx; // The buffer gap between lines - buffer += srcy * srccx + srcx; // The buffer start position - p = buffer + srccx*y + x; // Adjustment for controller craziness + lg = g->p.x2 - g->p.cx; // The buffer gap between lines + buffer += g->p.y1 * g->p.x2 + g->p.x1; // The buffer start position + p = buffer + g->p.x2*y + x; // Adjustment for controller craziness while(tuples--) { /* Get a pixel */ c1 = *p++; /* Check for line or buffer wrapping */ - if (++x >= cx) { + if (++x >= g->p.cx) { x = 0; p += lg; - if (++y >= cy) { + if (++y >= g->p.cy) { y = 0; p = buffer; } @@ -389,10 +385,10 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { c2 = *p++; /* Check for line or buffer wrapping */ - if (++x >= cx) { + if (++x >= g->p.cx) { x = 0; p += lg; - if (++y >= cy) { + if (++y >= g->p.cy) { y = 0; p = buffer; } @@ -409,13 +405,13 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { // There are 2 pixels per 3 bytes #if !GDISP_PACKED_LINES - srccx = (srccx + 1) & ~1; + srccx = (g->p.x2 + 1) & ~1; #endif - pstart = srcy * srccx + srcx; // The starting pixel number + pstart = g->p.y1 * g->p.x2 + g->p.x1; // The starting pixel number buffer = (const pixel_t)(((const uint8_t *)buffer) + ((pstart>>1) * 3)); // The buffer start position - lg = ((srccx-cx)>>1)*3; // The buffer gap between lines - pnum = pstart + srccx*y + x; // Adjustment for controller craziness - p = ((const uint8_t *)buffer) + (((srccx*y + x)>>1)*3); // Adjustment for controller craziness + lg = ((g->p.x2-g->p.cx)>>1)*3; // The buffer gap between lines + pnum = pstart + g->p.x2*y + x; // Adjustment for controller craziness + p = ((const uint8_t *)buffer) + (((g->p.x2*y + x)>>1)*3); // Adjustment for controller craziness while (tuples--) { /* Get a pixel */ @@ -425,11 +421,11 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { } /* Check for line or buffer wrapping */ - if (++x >= cx) { + if (++x >= g->p.cx) { x = 0; p += lg; - pnum += srccx - cx; - if (++y >= cy) { + pnum += g->p.x2 - g->p.cx; + if (++y >= g->p.cy) { y = 0; p = (const uint8_t *)buffer; pnum = pstart; @@ -443,11 +439,11 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { } /* Check for line or buffer wrapping */ - if (++x >= cx) { + if (++x >= g->p.cx) { x = 0; p += lg; - pnum += srccx - cx; - if (++y >= cy) { + pnum += g->p.x2 - g->p.cx; + if (++y >= g->p.cy) { y = 0; p = (const uint8_t *)buffer; pnum = pstart; @@ -464,7 +460,7 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { } #endif -#if 0 && GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL LLDSPEC void gdisp_lld_control(GDISPDriver *g) { /* The hardware is capable of supporting... * GDISP_CONTROL_POWER - supported @@ -489,27 +485,27 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { write_cmd(OSCON); // Internal oscillator on write_cmd(SLPOUT); // Sleep out write_cmd1(PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON - write_cmd2(VOLCTR, GDISP.Contrast, 0x03); // Voltage control (contrast setting) + write_cmd2(VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting) delayms(100); // Allow power supply to stabilise write_cmd(DISON); // Turn on the display write_cmd(PTLOUT); // Remove sleep window - set_backlight(GDISP.Backlight); // Turn on the backlight + set_backlight(g->g.Backlight); // Turn on the backlight break; case powerSleep: write_cmd(OSCON); // Internal oscillator on write_cmd(SLPOUT); // Sleep out write_cmd1(PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON - write_cmd2(VOLCTR, GDISP.Contrast, 0x03); // Voltage control (contrast setting) + write_cmd2(VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting) delayms(100); // Allow power supply to stabilise write_cmd(DISON); // Turn on the display write_cmd2(PTLIN, GDISP_SLEEP_POS/4, (GDISP_SLEEP_POS+GDISP_SLEEP_SIZE)/4); // Sleep Window - set_backlight(GDISP.Backlight); // Turn on the backlight + set_backlight(g->g.Backlight); // Turn on the backlight break; case powerDeepSleep: write_cmd(OSCON); // Internal oscillator on write_cmd(SLPOUT); // Sleep out write_cmd1(PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON - write_cmd2(VOLCTR, GDISP.Contrast, 0x03); // Voltage control (contrast setting) + write_cmd2(VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting) delayms(100); // Allow power supply to stabilise write_cmd(DISON); // Turn on the display write_cmd2(PTLIN, GDISP_SLEEP_POS/4, (GDISP_SLEEP_POS+GDISP_SLEEP_SIZE)/4); // Sleep Window @@ -522,45 +518,47 @@ LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { release_bus(); g->g.Powermode = (powermode_t)g->p.ptr; return; - case GDISP_CONTROL_ORIENTATION: - if (g->g.Orientation == (orientation_t)g->p.ptr) - return; - acquire_bus(); - switch((orientation_t)g->p.ptr) { - case GDISP_ROTATE_0: - write_cmd3(DATCTL, 0x00, 0x00, 0x02); // P1: page normal, column normal, scan in column direction - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_90: - write_cmd3(DATCTL, 0x06, 0x00, 0x02); // P1: page normal, column reverse, scan in page direction - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - case GDISP_ROTATE_180: - write_cmd3(DATCTL, 0x03, 0x00, 0x02); // P1: page reverse, column reverse, scan in column direction - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_270: - write_cmd3(DATCTL, 0x05, 0x00, 0x02); // P1: page reverse, column normal, scan in page direction - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - default: - release_bus(); + #if GDISP_NOKIA_ORIENTATION + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) return; - } - release_bus(); - g->g.Orientation = (orientation_t)g->p.ptr; - return; + acquire_bus(); + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + write_cmd3(DATCTL, 0x00, 0x00, 0x02); // P1: page normal, column normal, scan in column direction + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + write_cmd3(DATCTL, 0x05, 0x00, 0x02); // P1: page reverse, column normal, scan in page direction + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + write_cmd3(DATCTL, 0x03, 0x00, 0x02); // P1: page reverse, column reverse, scan in column direction + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + write_cmd3(DATCTL, 0x06, 0x00, 0x02); // P1: page normal, column reverse, scan in page direction + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + release_bus(); + return; + } + release_bus(); + g->g.Orientation = (orientation_t)g->p.ptr; + return; + #endif case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; set_backlight((unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; case GDISP_CONTROL_CONTRAST: - if ((unsigned)value > 100) g->p.ptr = (void *)100; + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; acquire_bus(); write_cmd2(VOLCTR, (unsigned)g->p.ptr, 0x03); release_bus(); diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h index 93debcd1..5e950895 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h @@ -25,9 +25,18 @@ #define GDISP_DRIVER_NAME "Nokia6610GE8" #define GDISP_DRIVER_STRUCT GDISP_Nokia6610GE8 -#define GDISP_HARDWARE_STREAM TRUE -#define GDISP_HARDWARE_STREAM_STOP TRUE -//#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_NOKIA_ORIENTATION TRUE + +#if GDISP_NOKIA_ORIENTATION && GDISP_NEED_CONTROL + #define GDISP_HARDWARE_CONTROL TRUE + #define GDISP_HARDWARE_DRAWPIXEL TRUE + #define GDISP_HARDWARE_FILLS TRUE + #define GDISP_HARDWARE_BITFILLS TRUE +#else + #define GDISP_HARDWARE_CONTROL TRUE + #define GDISP_HARDWARE_STREAM TRUE + #define GDISP_HARDWARE_STREAM_STOP TRUE +#endif #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 /* This driver supports both packed and unpacked pixel formats and line formats. From c1e84a9ebd20a618183377e475526f15963c86fb Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 26 Sep 2013 19:15:40 +0200 Subject: [PATCH 020/160] docs --- releases.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/releases.txt b/releases.txt index e257ddc4..f13f42c4 100644 --- a/releases.txt +++ b/releases.txt @@ -11,6 +11,7 @@ FIX: Several bugfixes FEATURE: mcufont integration FEATURE: SSD1306 driver by user goeck FEATURE: ST7565 driver by user sam0737 +FEATURE: ED060SC4 driver by user jpa- *** changes after 1.7 *** From af81bdf7559b2fdaa2cda9e6ed6a90b95c480a4e Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 27 Sep 2013 07:33:14 +1000 Subject: [PATCH 021/160] docs --- releases.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/releases.txt b/releases.txt index f13f42c4..886140a5 100644 --- a/releases.txt +++ b/releases.txt @@ -12,7 +12,9 @@ FEATURE: mcufont integration FEATURE: SSD1306 driver by user goeck FEATURE: ST7565 driver by user sam0737 FEATURE: ED060SC4 driver by user jpa- - +FEATURE: GDISP Streaming +FEATURE: New driver interface for GDISP +FEATURE: Multiple display support *** changes after 1.7 *** FEATURE: Rename of the project from ChibiOS/GFX to uGFX From 3b8f14e2c8f03bcddfc1c274462bb46bc189c808 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sat, 28 Sep 2013 02:24:09 +0200 Subject: [PATCH 022/160] SSD1289 Area fill fix --- drivers/gdisp/SSD1289/gdisp_lld.c | 2 +- releases.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index a47fb17e..a55dd467 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -92,7 +92,7 @@ static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { write_reg(0x46, (y+cy-1) & 0x01FF); break; case GDISP_ROTATE_270: - write_reg(0x44, (((x+cx-1) << 8) & 0xFF00 ) | (y & 0x00FF)); + write_reg(0x44, (((y+cy-1) << 8) & 0xFF00 ) | (y & 0x00FF)); write_reg(0x45, x & 0x01FF); write_reg(0x46, (x+cx-1) & 0x01FF); break; diff --git a/releases.txt b/releases.txt index 886140a5..f03e31f4 100644 --- a/releases.txt +++ b/releases.txt @@ -12,6 +12,7 @@ FEATURE: mcufont integration FEATURE: SSD1306 driver by user goeck FEATURE: ST7565 driver by user sam0737 FEATURE: ED060SC4 driver by user jpa- +FIX: SSD1289 area filling bug fix by user samofab FEATURE: GDISP Streaming FEATURE: New driver interface for GDISP FEATURE: Multiple display support From a2aa837e09cd80a3d2fd9bd3097062ab06905227 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sat, 28 Sep 2013 02:59:29 +0200 Subject: [PATCH 023/160] updated notepad demo text --- demos/applications/notepad/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/applications/notepad/main.c b/demos/applications/notepad/main.c index 24c292c4..d2d53464 100644 --- a/demos/applications/notepad/main.c +++ b/demos/applications/notepad/main.c @@ -43,7 +43,7 @@ y >= COLOR_SIZE + OFFSET + 3 && y <= gdispGetHeight()) void drawScreen(void) { - char *msg = "ChibiOS/GFX"; + char *msg = "uGFX"; font_t font1, font2; font1 = gdispOpenFont("DejaVuSans24*"); From 6499da5be310f8f3ef8f2d11dfcfb662499c8c17 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 00:05:07 +1000 Subject: [PATCH 024/160] SSD1289 streaming driver (untested) X streaming driver (untested) Nokia6610 fixes Read pixel streaming support for low level driver. --- drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 22 +- drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h | 7 +- drivers/gdisp/SSD1289/gdisp_lld.c | 425 +++--------------- .../gdisp_lld_board_firebullstm32f103.h | 42 +- .../gdisp_lld_board_st_stm32f4_discovery.h | 63 ++- .../gdisp/SSD1289/gdisp_lld_board_template.h | 37 +- drivers/gdisp/SSD1289/gdisp_lld_config.h | 17 +- drivers/multiple/Win32/gdisp_lld.c | 4 +- drivers/multiple/X/gdisp_lld.c | 140 +++--- drivers/multiple/X/gdisp_lld_config.h | 11 +- include/gdisp/lld/gdisp_lld.h | 144 +++--- src/gdisp/gdisp.c | 139 +++--- 12 files changed, 432 insertions(+), 619 deletions(-) diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index e51e780f..bcccef80 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -107,7 +107,7 @@ /* Driver local variables. */ /*===========================================================================*/ -#if GDISP_HARDWARE_STREAM +#if GDISP_HARDWARE_STREAM_WRITE static color_t savecolor; #if GDISP_GE8_BROKEN_CONTROLLER static color_t firstcolor; @@ -184,18 +184,15 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return TRUE; } -#if GDISP_HARDWARE_STREAM - LLDSPEC void gdisp_lld_stream_start(GDISPDriver *g) { +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { acquire_bus(); write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set write_cmd(RAMWR); g->flags &= ~(GDISP_FLG_ODDBYTE|GDISP_FLG_RUNBYTE); } -#endif - -#if GDISP_HARDWARE_STREAM - LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g) { + LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { #if GDISP_GE8_BROKEN_CONTROLLER if (!(g->flags & GDISP_FLG_RUNBYTE)) { firstcolor = g->p.color; @@ -211,10 +208,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { g->flags |= GDISP_FLG_ODDBYTE; } } -#endif - -#if GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_STOP - LLDSPEC void gdisp_lld_stream_stop(GDISPDriver *g) { + LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { if ((g->flags & GDISP_FLG_ODDBYTE)) { #if GDISP_GE8_BROKEN_CONTROLLER /** @@ -247,7 +241,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif #if GDISP_HARDWARE_DRAWPIXEL - void gdisp_lld_draw_pixel(GDISPDriver *g) { + LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) { acquire_bus(); switch(g->g.Orientation) { case GDISP_ROTATE_0: @@ -275,7 +269,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { /* ---- Optional Routines ---- */ #if GDISP_HARDWARE_FILLS - void gdisp_lld_fill_area(GDISPDriver *g) { + LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { unsigned tuples; tuples = (g->p.cx*g->p.cy+1)>>1; // With an odd sized area we over-print by one pixel. @@ -308,7 +302,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif #if GDISP_HARDWARE_BITFILLS - void gdisp_lld_blit_area(GDISPDriver *g) { + LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g) { coord_t lg, x, y; color_t c1, c2; unsigned tuples; diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h index 5e950895..a9e11e03 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h @@ -25,7 +25,9 @@ #define GDISP_DRIVER_NAME "Nokia6610GE8" #define GDISP_DRIVER_STRUCT GDISP_Nokia6610GE8 -#define GDISP_NOKIA_ORIENTATION TRUE +#ifndef GDISP_NOKIA_ORIENTATION + #define GDISP_NOKIA_ORIENTATION TRUE +#endif #if GDISP_NOKIA_ORIENTATION && GDISP_NEED_CONTROL #define GDISP_HARDWARE_CONTROL TRUE @@ -34,8 +36,7 @@ #define GDISP_HARDWARE_BITFILLS TRUE #else #define GDISP_HARDWARE_CONTROL TRUE - #define GDISP_HARDWARE_STREAM TRUE - #define GDISP_HARDWARE_STREAM_STOP TRUE + #define GDISP_HARDWARE_STREAM_WRITE TRUE #endif #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index a55dd467..84ffa6d1 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -17,8 +17,8 @@ #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -52,7 +52,7 @@ static inline void set_cursor(coord_t x, coord_t y) { * Reg 0x004F is 9 bit * Use a bit mask to make sure they are not set too high */ - switch(GDISP.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_180: write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-x) & 0x00FF); write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-y) & 0x01FF); @@ -85,14 +85,14 @@ static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { * 0 <= Reg(0x45) <= Reg(0x46) <= 0x13F */ - switch(GDISP.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: write_reg(0x44, (((x+cx-1) << 8) & 0xFF00 ) | (x & 0x00FF)); write_reg(0x45, y & 0x01FF); write_reg(0x46, (y+cy-1) & 0x01FF); break; case GDISP_ROTATE_270: - write_reg(0x44, (((y+cy-1) << 8) & 0xFF00 ) | (y & 0x00FF)); + write_reg(0x44, (((x+cx-1) << 8) & 0xFF00 ) | (y & 0x00FF)); write_reg(0x45, x & 0x01FF); write_reg(0x46, (x+cx-1) & 0x01FF); break; @@ -112,7 +112,7 @@ static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { } static inline void reset_viewport(void) { - set_viewport(0, 0, GDISP.Width, GDISP.Height); + set_viewport(0, 0, g->g.Width, g->g.Height); } /*===========================================================================*/ @@ -123,18 +123,7 @@ static inline void reset_viewport(void) { /* Driver exported functions. */ /*===========================================================================*/ -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ - -/** - * @brief Low level GDISP driver initialization. - * - * @notapi - */ -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { /* Initialise your display */ init_board(); @@ -196,365 +185,103 @@ bool_t gdisp_lld_init(void) { set_backlight(GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = GDISP_INITIAL_BACKLIGHT; - GDISP.Contrast = GDISP_INITIAL_CONTRAST; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - acquire_bus(); - set_cursor(x, y); - write_reg(0x0022, color); - release_bus(); -} - -/* ---- Optional Routines ---- */ -/* - All the below routines are optional. - Defining them will increase speed but everything - will work if they are not defined. - If you are not using a routine - turn it off using - the appropriate GDISP_HARDWARE_XXXX macro. - Don't bother coding for obvious similar routines if - there is no performance penalty as the emulation software - makes a good job of using similar routines. - eg. If gfillarea() is defined there is little - point in defining clear() unless the - performance bonus is significant. - For good performance it is suggested to implement - fillarea() and blitarea(). -*/ - -#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) - /** - * @brief Clear the display. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] color The color of the pixel - * - * @notapi - */ - void gdisp_lld_clear(color_t color) { - unsigned area; - - area = GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT; - +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { acquire_bus(); - reset_viewport(); - set_cursor(0, 0); - + set_viewport(g->p.x, g->p.y, g->p.cx, g->p.cy); stream_start(); - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, &color); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area/65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - uint32_t index; - for(index = 0; index < area; index++) - write_data(color); - #endif //#ifdef GDISP_USE_DMA - + } + LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { + write_data(color); + } + LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { stream_stop(); release_bus(); } #endif -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - unsigned area; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - area = cx*cy; +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { + uint16_t dummy; acquire_bus(); - set_viewport(x, y, cx, cy); + set_viewport(g->p.x, g->p.y, g->p.cx, g->p.cy); stream_start(); - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, &color); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area/65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - uint32_t index; - for(index = 0; index < area; index++) - write_data(color); - #endif //#ifdef GDISP_USE_DMA - + setreadmode(); + dummy = read_data(); // dummy read + } + LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g) { + return read_data(); + } + LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g) { + setwritemode(); stream_stop(); release_bus(); } #endif -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a bitmap. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - buffer += srcx + srcy * srccx; - +#if GDISP_HARDWARE_FILLS && defined(GDISP_USE_DMA) + LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { acquire_bus(); - set_viewport(x, y, cx, cy); + set_viewport(g->p.x, g->p.y, g->p.cx, g->p.cy); stream_start(); - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint32_t area = cx*cy; - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PINC | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area/65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - coord_t endx, endy; - uint32_t lg; - endx = srcx + cx; - endy = y + cy; - lg = srccx - cx; - for(; y < endy; y++, buffer += lg) - for(x=srcx; x < endx; x++) - write_data(*buffer++); - #endif //#ifdef GDISP_USE_DMA - + dma_with_noinc(&color, g->p.cx*g->p.cy) stream_stop(); release_bus(); } #endif -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) - /** - * @brief Get the color of a particular pixel. - * @note Optional. - * @note If x,y is off the screen, the result is undefined. - * - * @param[in] x, y The pixel to be read - * - * @notapi - */ - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - color_t color; +#if GDISP_HARDWARE_BITFILLS && defined(GDISP_USE_DMA) + LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g) { + pixel_t *buffer; + coord_t ycnt; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; - #endif + buffer = (pixel_t *)g->p.ptr + g->p.x1 + g->p.y1 * g->p.x2; acquire_bus(); - set_cursor(x, y); + set_viewport(g->p.x, g->p.y, g->p.cx, g->p.cy); stream_start(); - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_3 | FSMC_BTR1_DATAST_3 | FSMC_BTR1_BUSTURN_0 ; - - color = read_data(); // dummy read - color = read_data(); - - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ; - - stream_stop(); - release_bus(); - - return color; - } -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @note Optional. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - static color_t buf[((GDISP_SCREEN_HEIGHT > GDISP_SCREEN_WIDTH ) ? GDISP_SCREEN_HEIGHT : GDISP_SCREEN_WIDTH)]; - coord_t row0, row1; - unsigned i, gap, abslines, j; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - abslines = lines < 0 ? -lines : lines; - - acquire_bus(); - if ((coord_t)abslines >= cy) { - abslines = cy; - gap = 0; + if (g->p.x2 == g->p.cx) { + dma_with_inc(buffer, g->p.cx*g->p.cy); } else { - gap = cy - abslines; - for(i = 0; i < gap; i++) { - if(lines > 0) { - row0 = y + i + lines; - row1 = y + i; - } else { - row0 = (y - i - 1) + lines; - row1 = (y - i - 1); - } - - /* read row0 into the buffer and then write at row1*/ - set_viewport(x, row0, cx, 1); - stream_start(); - - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_3 | FSMC_BTR1_DATAST_3 | FSMC_BTR1_BUSTURN_0 ; - - j = read_data(); // dummy read - for (j = 0; (coord_t)j < cx; j++) - buf[j] = read_data(); - - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ; - - stream_stop(); - - set_viewport(x, row1, cx, 1); - stream_start(); - for (j = 0; (coord_t)j < cx; j++) - write_data(buf[j]); - stream_stop(); - } + for (ycnt = g->p.cy; ycnt; ycnt--, buffer += g->p.x2) + dma_with_inc(buffer, g->p.cy); } - - /* fill the remaining gap */ - set_viewport(x, lines > 0 ? (y+(coord_t)gap) : y, cx, abslines); - stream_start(); - gap = cx*abslines; - for(i = 0; i < gap; i++) write_data(bgcolor); stream_stop(); release_bus(); } #endif -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. - * GDISP_CONTROL_LLD - Low level driver control constants start at - * this value. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { - switch(what) { +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + switch(g->p.x) { case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) + if (g->g.Powermode == (powermode_t)g->p.ptr) return; - switch((gdisp_powermode_t)value) { + switch((powermode_t)g->p.ptr) { case powerOff: acquire_bus(); write_reg(0x0010, 0x0000); // leave sleep mode write_reg(0x0007, 0x0000); // halt operation - write_reg(0x0000, 0x0000); // turn off oszillator - write_reg(0x0010, 0x0001); // enter sleepmode + write_reg(0x0000, 0x0000); // turn off oscillator + write_reg(0x0010, 0x0001); // enter sleep mode release_bus(); break; case powerOn: acquire_bus(); write_reg(0x0010, 0x0000); // leave sleep mode release_bus(); - if (GDISP.Powermode != powerSleep) + if (g->g.Powermode != powerSleep) gdisp_lld_init(); break; case powerSleep: @@ -565,20 +292,20 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { default: return; } - GDISP.Powermode = (gdisp_powermode_t)value; + g->g.Powermode = (powermode_t)g->p.ptr; return; case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) + if (g->g.Orientation == (orientation_t)g->p.ptr) return; - switch((gdisp_orientation_t)value) { + switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: acquire_bus(); write_reg(0x0001, 0x2B3F); /* ID = 11 AM = 0 */ write_reg(0x0011, 0x6070); release_bus(); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: acquire_bus(); @@ -586,8 +313,8 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { /* ID = 11 AM = 1 */ write_reg(0x0011, 0x6078); release_bus(); - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: acquire_bus(); @@ -595,8 +322,8 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { /* ID = 01 AM = 0 */ write_reg(0x0011, 0x6040); release_bus(); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: acquire_bus(); @@ -604,31 +331,23 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { /* ID = 01 AM = 1 */ write_reg(0x0011, 0x6048); release_bus(); - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; break; default: return; } - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; + g->g.Orientation = (orientation_t)value; return; case GDISP_CONTROL_BACKLIGHT: - if ((unsigned)value > 100) - value = (void *)100; - set_backlight((unsigned)value); - GDISP.Backlight = (unsigned)value; + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight((unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; return; + //case GDISP_CONTROL_CONTRAST: default: return; -/* - case GDISP_CONTROL_CONTRAST: -*/ } } #endif diff --git a/drivers/gdisp/SSD1289/gdisp_lld_board_firebullstm32f103.h b/drivers/gdisp/SSD1289/gdisp_lld_board_firebullstm32f103.h index 38d9e04d..e55e7cd1 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_board_firebullstm32f103.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_board_firebullstm32f103.h @@ -112,7 +112,28 @@ static inline void write_data(uint16_t data) { CLR_WR; SET_WR; } -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) +/** + * @brief Set the bus in read mode + * + * @notapi + */ +static inline void setreadmode(void) { + // change pin mode to digital input + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); + CLR_RD; +} + +/** + * @brief Set the bus back into write mode + * + * @notapi + */ +static inline void setwritemode(void) { + // change pin mode back to digital output + SET_RD; + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); +} + /** * @brief Read data from the lcd. * @@ -123,22 +144,13 @@ static inline void write_data(uint16_t data) { * @notapi */ static inline uint16_t read_data(void) { - uint16_t value; - - // change pin mode to digital input - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); - - CLR_RD; - value = palReadPort(GPIOE); - value = palReadPort(GPIOE); - SET_RD; - - // change pin mode back to digital output - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); - - return value; + return palReadPort(GPIOE); } #endif +#if defined(GDISP_USE_DMA) + #error "GDISP - SSD1289: The GPIO interface does not support DMA" +#endif + #endif /* _GDISP_LLD_BOARD_H */ /** @} */ diff --git a/drivers/gdisp/SSD1289/gdisp_lld_board_st_stm32f4_discovery.h b/drivers/gdisp/SSD1289/gdisp_lld_board_st_stm32f4_discovery.h index 9d46d64b..7097347b 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_board_st_stm32f4_discovery.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_board_st_stm32f4_discovery.h @@ -18,10 +18,7 @@ #define GDISP_REG ((volatile uint16_t *) 0x60000000)[0] /* RS = 0 */ #define GDISP_RAM ((volatile uint16_t *) 0x60020000)[0] /* RS = 1 */ - -#define GDISP_USE_FSMC -#define GDISP_USE_DMA -#define GDISP_DMA_STREAM STM32_DMA2_STREAM6 +#define GDISP_DMA_STREAM STM32_DMA2_STREAM6 const unsigned char FSMC_Bank = 0; @@ -55,20 +52,22 @@ static inline void init_board(void) { /* FSMC setup for F1/F3 */ rccEnableAHB(RCC_AHBENR_FSMCEN, 0); - #if defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - #error "DMA not implemented for F1/F3 Devices" + #if defined(GDISP_USE_DMA) + #error "GDISP: SSD1289 - DMA not implemented for F1/F3 Devices" #endif #elif defined(STM32F4XX) || defined(STM32F2XX) /* STM32F2-F4 FSMC init */ rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); - #if defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) + #if defined(GDISP_USE_DMA) if (dmaStreamAllocate(GDISP_DMA_STREAM, 0, NULL, NULL)) gfxExit(); dmaStreamSetMemory0(GDISP_DMA_STREAM, &GDISP_RAM); dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); + #else + #warning "GDISP: SSD1289 - DMA is supported for F2/F4 Devices. Define GDISP_USE_DMA in your gfxconf.h to turn this on for better performance." #endif #else - #error "FSMC not implemented for this device" + #error "GDISP: SSD1289 - FSMC not implemented for this device" #endif /* set pins to FSMC mode */ @@ -155,17 +154,61 @@ static inline void write_index(uint16_t index) { GDISP_REG = index; } */ static inline void write_data(uint16_t data) { GDISP_RAM = data; } -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) +/** + * @brief Set the bus in read mode + * + * @notapi + */ +static inline void setreadmode(void) { + FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_3 | FSMC_BTR1_DATAST_3 | FSMC_BTR1_BUSTURN_0; /* FSMC timing */ +} + +/** + * @brief Set the bus back into write mode + * + * @notapi + */ +static inline void setwritemode(void) { + FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0; /* FSMC timing */ +} + /** * @brief Read data from the lcd. * * @return The data from the lcd * @note The chip select may need to be asserted/de-asserted * around the actual spi read - * + * * @notapi */ static inline uint16_t read_data(void) { return GDISP_RAM; } + +#if defined(GDISP_USE_DMA) || defined(__DOXYGEN__) + /** + * @brief Transfer data using DMA but don't increment the source address + */ + static inline dma_with_noinc(color_t *buffer, int area) { + dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); + dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); + for (; area > 0; area -= 65535) { + dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area > 65535 ? 65535 : area); + dmaStreamEnable(GDISP_DMA_STREAM); + dmaWaitCompletion(GDISP_DMA_STREAM); + } + } + + /** + * @brief Transfer data using DMA incrementing the source address + */ + static inline dma_with_inc(color_t *buffer, int area) { + dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); + dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PINC | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); + for (; area > 0; area -= 65535) { + dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area > 65535 ? 65535 : area); + dmaStreamEnable(GDISP_DMA_STREAM); + dmaWaitCompletion(GDISP_DMA_STREAM); + } + } #endif #endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/SSD1289/gdisp_lld_board_template.h b/drivers/gdisp/SSD1289/gdisp_lld_board_template.h index e5d10355..8b55bed3 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_board_template.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_board_template.h @@ -87,7 +87,24 @@ static inline void write_data(uint16_t data) { } -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) +/** + * @brief Set the bus in read mode + * + * @notapi + */ +static inline void setreadmode(void) { + +} + +/** + * @brief Set the bus back into write mode + * + * @notapi + */ +static inline void setwritemode(void) { + +} + /** * @brief Read data from the lcd. * @@ -100,6 +117,24 @@ static inline void write_data(uint16_t data) { static inline uint16_t read_data(void) { } + +/** + * The below section you can replace with #error if your interface doesn't support DMA + */ +#if defined(GDISP_USE_DMA) || defined(__DOXYGEN__) + //#error "GDISP - SSD1289: This interface does not support DMA" + + /** + * @brief Transfer data using DMA but don't increment the source address + */ + static inline dma_with_noinc(color_t *buffer, int area) { + } + + /** + * @brief Transfer data using DMA incrementing the source address + */ + static inline dma_with_inc(color_t *buffer, int area) { + } #endif #endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/SSD1289/gdisp_lld_config.h b/drivers/gdisp/SSD1289/gdisp_lld_config.h index 989cc3af..9c00ce39 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_config.h @@ -23,13 +23,16 @@ /*===========================================================================*/ #define GDISP_DRIVER_NAME "SSD1289" - -#define GDISP_HARDWARE_CLEARS TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -#define GDISP_HARDWARE_SCROLL TRUE -#define GDISP_HARDWARE_PIXELREAD TRUE -#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_DRIVER_STRUCT GDISP_SSD1289 + +#define GDISP_HARDWARE_STREAM_WRITE TRUE +#define GDISP_HARDWARE_STREAM_READ TRUE +#define GDISP_HARDWARE_CONTROL TRUE + +#if defined(GDISP_USE_DMA) + #define GDISP_HARDWARE_FILLS TRUE + #define GDISP_HARDWARE_BITFILLS TRUE +#endif #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index f55f3700..41141a90 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -463,7 +463,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif #if GDISP_HARDWARE_BITFILLS - void gdisp_lld_blit_area(GDISPDriver *g) { + LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g) { BITMAPV4HEADER bmpInfo; HDC dcScreen; pixel_t * buffer; @@ -577,7 +577,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif #if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL - void gdisp_lld_vertical_scroll(GDISPDriver *g) { + LLDSPEC void gdisp_lld_vertical_scroll(GDISPDriver *g) { HDC dcScreen; RECT rect; coord_t lines; diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld.c index 13368bc1..9c6a7123 100644 --- a/drivers/multiple/X/gdisp_lld.c +++ b/drivers/multiple/X/gdisp_lld.c @@ -14,6 +14,9 @@ #if GFX_USE_GDISP +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" + /** * Our color model - Default or 24 bit only. * @@ -25,19 +28,6 @@ #define GDISP_FORCE_24BIT FALSE #endif -#if GINPUT_NEED_MOUSE - /* Include mouse support code */ - #include "ginput/lld/mouse.h" -#endif - -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" - -#include -#include -#include -#include - #ifndef GDISP_SCREEN_HEIGHT #define GDISP_SCREEN_HEIGHT 480 #endif @@ -45,6 +35,16 @@ #define GDISP_SCREEN_WIDTH 640 #endif +#if GINPUT_NEED_MOUSE + /* Include mouse support code */ + #include "ginput/lld/mouse.h" +#endif + +#include +#include +#include +#include + Display *dis; int scr; Window win; @@ -130,7 +130,7 @@ static int FatalXIOError(Display *d) { exit(0); } -bool_t gdisp_lld_init(void) +LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { { XSizeHints *pSH; XSetWindowAttributes xa; @@ -212,69 +212,81 @@ bool_t gdisp_lld_init(void) gfxThreadClose(hth); /* Initialise the GDISP structure to match */ - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = 100; - GDISP.Contrast = 50; - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + g->g.Orientation = g->g_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = 100; + g->g.Contrast = 50; + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; return TRUE; } -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) +LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) { XColor col; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - // Clip pre orientation change - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - col.red = RED_OF(color) << 8; - col.green = GREEN_OF(color) << 8; - col.blue = BLUE_OF(color) << 8; + col.red = RED_OF(g->p.color) << 8; + col.green = GREEN_OF(g->p.color) << 8; + col.blue = BLUE_OF(g->p.color) << 8; XAllocColor(dis, cmap, &col); XSetForeground(dis, gc, col.pixel); - XDrawPoint(dis, pix, gc, (int)x, (int)y ); - XDrawPoint(dis, win, gc, (int)x, (int)y ); + XDrawPoint(dis, pix, gc, (int)g->p.x, (int)g->p.y ); + XDrawPoint(dis, win, gc, (int)g->p.x, (int)g->p.y ); XFlush(dis); } -void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - XColor col; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - // Clip pre orientation change - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif +#if GDISP_HARDWARE_FILLS + LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { + XColor col; - col.red = RED_OF(color) << 8; - col.green = GREEN_OF(color) << 8; - col.blue = BLUE_OF(color) << 8; - XAllocColor(dis, cmap, &col); - XSetForeground(dis, gc, col.pixel); - XFillRectangle(dis, pix, gc, x, y, cx, cy); - XFillRectangle(dis, win, gc, x, y, cx, cy); - XFlush(dis); -} + col.red = RED_OF(g->p.color) << 8; + col.green = GREEN_OF(g->p.color) << 8; + col.blue = BLUE_OF(g->p.color) << 8; + XAllocColor(dis, cmap, &col); + XSetForeground(dis, gc, col.pixel); + XFillRectangle(dis, pix, gc, g->p.x, g->p.y, g->p.cx, g->p.cy); + XFillRectangle(dis, win, gc, g->p.x, g->p.y, g->p.cx, g->p.cy); + XFlush(dis); + } +#endif -// Start of Bitblit code -//XImage bitmap; -//pixel_t *bits; -// bits = malloc(vis.depth * GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT); -// bitmap = XCreateImage(dis, vis, vis.depth, ZPixmap, -// 0, bits, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, -// 0, 0); +#if 0 && GDISP_HARDWARE_BITFILLS + LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g) { + // Start of Bitblit code + + //XImage bitmap; + //pixel_t *bits; + // bits = malloc(vis.depth * GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT); + // bitmap = XCreateImage(dis, vis, vis.depth, ZPixmap, + // 0, bits, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, + // 0, 0); + } +#endif + +#if GDISP_HARDWARE_PIXELREAD + LLDSPEC color_t gdisp_lld_get_pixel_color(GDISPDriver *g) { + XColor color; + XImage *img; + + img = XGetImage (dis, pix, g->p.x, g->p.y, 1, 1, AllPlanes, XYPixmap); + color->pixel = XGetPixel (img, 0, 0); + XFree(img); + XQueryColor(dis, cmap, &color); + return RGB2COLOR(c.red>>8, c.green>>8, c.blue>>8); + } +#endif + +#if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL + LLDSPEC void gdisp_lld_vertical_scroll(GDISPDriver *g) { + if (g->p.y1 > 0) { + XCopyArea(dis, pix, pix, gc, g->p.x, g->p.y+g->p.y1, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); + XCopyArea(dis, pix, win, gc, g->p.x, g->p.y, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); + } else { + XCopyArea(dis, pix, pix, gc, g->p.x, g->p.y, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); + XCopyArea(dis, pix, win, gc, g->p.x, g->p.y-lines, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); + } + } +#endif #if GINPUT_NEED_MOUSE diff --git a/drivers/multiple/X/gdisp_lld_config.h b/drivers/multiple/X/gdisp_lld_config.h index 0cacc4f8..0bd76a2c 100644 --- a/drivers/multiple/X/gdisp_lld_config.h +++ b/drivers/multiple/X/gdisp_lld_config.h @@ -23,17 +23,14 @@ /*===========================================================================*/ #define GDISP_DRIVER_NAME "Linux emulator - X11" +#define GDISP_DRIVER_STRUCT GDISP_X11 -#define GDISP_HARDWARE_CLEARS FALSE +#define GDISP_HARDWARE_DRAWPIXEL TRUE #define GDISP_HARDWARE_FILLS TRUE #define GDISP_HARDWARE_BITFILLS FALSE -#define GDISP_HARDWARE_SCROLL FALSE -#define GDISP_HARDWARE_PIXELREAD FALSE +#define GDISP_HARDWARE_SCROLL TRUE +#define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_HARDWARE_CONTROL FALSE -#define GDISP_HARDWARE_CIRCLES FALSE -#define GDISP_HARDWARE_CIRCLEFILLS FALSE -#define GDISP_HARDWARE_ARCS FALSE -#define GDISP_HARDWARE_ARCFILLS FALSE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 6efdb6bb..205b425a 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -33,26 +33,26 @@ * @{ */ /** - * @brief Hardware streaming interface is supported. + * @brief Hardware streaming writing is supported. * @details If set to @p FALSE software emulation is used. - * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver + * @note Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver */ - #ifndef GDISP_HARDWARE_STREAM - #define GDISP_HARDWARE_STREAM FALSE + #ifndef GDISP_HARDWARE_STREAM_WRITE + #define GDISP_HARDWARE_STREAM_WRITE FALSE #endif /** - * @brief Hardware streaming requires an explicit end call. - * @details If set to @p FALSE if an explicit stream end call is not required. + * @brief Hardware streaming reading of the display surface is supported. + * @details If set to @p FALSE this routine is not available. */ - #ifndef GDISP_HARDWARE_STREAM_STOP - #define GDISP_HARDWARE_STREAM_STOP FALSE + #ifndef GDISP_HARDWARE_STREAM_READ + #define GDISP_HARDWARE_STREAM_READ FALSE #endif /** * @brief Hardware accelerated draw pixel. * @details If set to @p FALSE software emulation is used. - * @note Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver + * @note Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver */ #ifndef GDISP_HARDWARE_DRAWPIXEL #define GDISP_HARDWARE_DRAWPIXEL FALSE @@ -178,7 +178,7 @@ typedef struct GDISPDriver { coord_t clipx1, clipy1; } t; #endif - #if GDISP_LINEBUF_SIZE != 0 && ((GDISP_NEED_SCROLL && !GDISP_HARDWARE_SCROLL) || (!GDISP_HARDWARE_STREAM && GDISP_HARDWARE_BITFILLS)) + #if GDISP_LINEBUF_SIZE != 0 && ((GDISP_NEED_SCROLL && !GDISP_HARDWARE_SCROLL) || (!GDISP_HARDWARE_STREAM_WRITE && GDISP_HARDWARE_BITFILLS)) // A pixel line buffer color_t linebuf[GDISP_LINEBUF_SIZE]; #endif @@ -204,10 +204,10 @@ typedef struct GDISPDriver { */ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g); - #if GDISP_HARDWARE_STREAM || defined(__DOXYGEN__) + #if GDISP_HARDWARE_STREAM_WRITE || defined(__DOXYGEN__) /** - * @brief Start a streamed operation - * @pre GDISP_HARDWARE_STREAM is TRUE + * @brief Start a streamed write operation + * @pre GDISP_HARDWARE_STREAM_WRITE is TRUE * * @param[in] g The driver structure * @param[in] g->p.x,g->p.y The window position @@ -217,44 +217,68 @@ typedef struct GDISPDriver { * @note Streaming operations that wrap the defined window have * undefined results. */ - LLDSPEC void gdisp_lld_stream_start(GDISPDriver *g); + LLDSPEC void gdisp_lld_write_start(GDISPDriver *g); + /** * @brief Send a pixel to the current streaming position and then increment that position - * @pre GDISP_HARDWARE_STREAM is TRUE + * @pre GDISP_HARDWARE_STREAM_WRITE is TRUE * * @param[in] g The driver structure * @param[in] g->p.color The color to display at the curent position * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_stream_color(GDISPDriver *g); + LLDSPEC void gdisp_lld_write_color(GDISPDriver *g); - #if GDISP_HARDWARE_STREAM_READ || defined(__DOXYGEN__) - /** - * @brief Read a pixel from the current streaming position and then increment that position - * @return The color at the current position - * @pre GDISP_HARDWARE_STREAM and GDISP_HARDWARE_STREAM_READ is TRUE - * - * @param[in] g The driver structure - * - * @note The parameter variables must not be altered by the driver. - */ - LLDSPEC color_t gdisp_lld_stream_read(GDISPDriver *g); - #endif - - #if GDISP_HARDWARE_STREAM_STOP || defined(__DOXYGEN__) - /** - * @brief End the current streaming operation - * @pre GDISP_HARDWARE_STREAM and GDISP_HARDWARE_STREAM_STOP is TRUE - * - * @param[in] g The driver structure - * - * @note The parameter variables must not be altered by the driver. - */ - LLDSPEC void gdisp_lld_stream_stop(GDISPDriver *g); - #endif + /** + * @brief End the current streaming write operation + * @pre GDISP_HARDWARE_STREAM_WRITE is TRUE + * + * @param[in] g The driver structure + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g); #endif + #if GDISP_HARDWARE_STREAM_READ || defined(__DOXYGEN__) + /** + * @brief Start a streamed read operation + * @pre GDISP_HARDWARE_STREAM_READ is TRUE + * + * @param[in] g The driver structure + * @param[in] g->p.x,g->p.y The window position + * @param[in] g->p.cx,g->p.cy The window size + * + * @note The parameter variables must not be altered by the driver. + * @note Streaming operations that wrap the defined window have + * undefined results. + */ + LLDSPEC void gdisp_lld_read_start(GDISPDriver *g); + + /** + * @brief Read a pixel from the current streaming position and then increment that position + * @return The color at the current position + * @pre GDISP_HARDWARE_STREAM_READ is TRUE + * + * @param[in] g The driver structure + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g); + + /** + * @brief End the current streaming operation + * @pre GDISP_HARDWARE_STREAM_READ is TRUE + * + * @param[in] g The driver structure + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g); + #endif + + #if GDISP_HARDWARE_DRAWPIXEL || defined(__DOXYGEN__) /** * @brief Draw a pixel @@ -399,10 +423,12 @@ typedef struct GDISPDriver { typedef struct GDISPVMT { bool_t (*init)(GDISPDriver *g); - void (*streamstart)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy - void (*streamcolor)(GDISPDriver *g); // Uses p.color - color_t (*streamread)(GDISPDriver *g); // Uses no parameters - void (*streamstop)(GDISPDriver *g); // Uses no parameters + void (*writestart)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy + void (*writecolor)(GDISPDriver *g); // Uses p.color + void (*writestop)(GDISPDriver *g); // Uses no parameters + void (*readstart)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy + color_t (*readcolor)(GDISPDriver *g); // Uses no parameters + void (*readstop)(GDISPDriver *g); // Uses no parameters void (*pixel)(GDISPDriver *g); // Uses p.x,p.y p.color void (*clear)(GDISPDriver *g); // Uses p.color void (*fill)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy p.color @@ -418,15 +444,17 @@ typedef struct GDISPDriver { #define GDISP_DRIVER_STRUCT_INIT {{0}, &VMT} static const GDISPVMT VMT = { gdisp_lld_init, - #if GDISP_HARDWARE_STREAM - gdisp_lld_stream_start, - gdisp_lld_stream_color, - gdisp_lld_stream_read, - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop, - #else - 0, - #endif + #if GDISP_HARDWARE_STREAM_WRITE + gdisp_lld_write_start, + gdisp_lld_write_color, + gdisp_lld_write_stop, + #else + 0, 0, 0, + #endif + #if GDISP_HARDWARE_STREAM_READ + gdisp_lld_read_start, + gdisp_lld_read_color, + gdisp_lld_read_stop, #else 0, 0, 0, #endif @@ -480,10 +508,12 @@ typedef struct GDISPDriver { #else #define gdisp_lld_init(g) g->vmt->init(g) - #define gdisp_lld_stream_start(g) g->vmt->streamstart(g) - #define gdisp_lld_stream_color(g) g->vmt->streamcolor(g) - #define gdisp_lld_stream_read(g) g->vmt->streamread(g) - #define gdisp_lld_stream_stop(g) g->vmt->streamstop(g) + #define gdisp_lld_write_start(g) g->vmt->writestart(g) + #define gdisp_lld_write_color(g) g->vmt->writecolor(g) + #define gdisp_lld_write_stop(g) g->vmt->writestop(g) + #define gdisp_lld_read_start(g) g->vmt->readstart(g) + #define gdisp_lld_read_color(g) g->vmt->readcolor(g) + #define gdisp_lld_read_stop(g) g->vmt->readstop(g) #define gdisp_lld_draw_pixel(g) g->vmt->pixel(g) #define gdisp_lld_clear(g) g->vmt->clear(g) #define gdisp_lld_fill_area(g) g->vmt->fill(g) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 828e5aa9..a135462d 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -19,8 +19,8 @@ /* Include the low level driver information */ #include "gdisp/lld/gdisp_lld.h" -#if !GDISP_HARDWARE_STREAM && !GDISP_HARDWARE_DRAWPIXEL - #error "GDISP Driver: Either GDISP_HARDWARE_STREAM or GDISP_HARDWARE_DRAWPIXEL must be defined" +#if !GDISP_HARDWARE_STREAM_WRITE && !GDISP_HARDWARE_DRAWPIXEL + #error "GDISP Driver: Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be defined" #endif #if 1 @@ -48,15 +48,6 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; #define MUTEX_EXIT() #endif -#if GDISP_HARDWARE_STREAM_STOP - #define STREAM_CLEAR() if ((GC->flags & GDISP_FLG_INSTREAM)) { \ - gdisp_lld_stream_stop(GC); \ - GC->flags &= ~GDISP_FLG_INSTREAM; \ - } -#else - #define STREAM_CLEAR() GC->flags &= ~GDISP_FLG_INSTREAM -#endif - #define NEED_CLIPPING (!GDISP_HARDWARE_CLIP && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP)) /*==========================================================================*/ @@ -85,11 +76,9 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; #endif GC->p.cx = GC->p.cy = 1; - gdisp_lld_stream_start(GC); - gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_write_start(GC); + gdisp_lld_write_color(GC); + gdisp_lld_write_stop(GC); } #endif @@ -100,19 +89,17 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; #if GDISP_HARDWARE_FILLS // Best is hardware accelerated area fill #define fillarea() gdisp_lld_fill_area(GC) -#elif GDISP_HARDWARE_STREAM +#elif GDISP_HARDWARE_STREAM_WRITE // Next best is hardware streaming static INLINE void fillarea(void) { uint32_t area; area = (uint32_t)GC->p.cx * GC->p.cy; - gdisp_lld_stream_start(GC); + gdisp_lld_write_start(GC); for(; area; area--) - gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_write_color(GC); + gdisp_lld_write_stop(GC); } #else // Worst is drawing pixels @@ -159,7 +146,7 @@ static void hline_clip(void) { // This is an optimization for the point case. It is only worthwhile however if we // have hardware fills or if we support both hardware pixel drawing and hardware streaming - #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM) + #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) // Is this a point if (GC->p.x == GC->p.x1) { #if GDISP_HARDWARE_DRAWPIXEL @@ -168,11 +155,9 @@ static void hline_clip(void) { #else // Worst is streaming GC->p.cx = GC->p.cy = 1; - gdisp_lld_stream_start(GC); - gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_write_start(GC); + gdisp_lld_write_color(GC); + gdisp_lld_write_stop(GC); #endif return; } @@ -183,15 +168,13 @@ static void hline_clip(void) { GC->p.cx = GC->p.x1 - GC->p.x + 1; GC->p.cy = 1; gdisp_lld_fill_area(GC); - #elif GDISP_HARDWARE_STREAM + #elif GDISP_HARDWARE_STREAM_WRITE // Next best is streaming GC->p.cx = GC->p.x1 - GC->p.x + 1; GC->p.cy = 1; - gdisp_lld_stream_start(GC); - do { gdisp_lld_stream_color(GC); } while(GC->p.cx--); - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_write_start(GC); + do { gdisp_lld_write_color(GC); } while(GC->p.cx--); + gdisp_lld_write_stop(GC); #else // Worst is drawing pixels for(; GC->p.x <= GC->p.x1; GC->p.x++) @@ -217,7 +200,7 @@ static void vline_clip(void) { // This is an optimization for the point case. It is only worthwhile however if we // have hardware fills or if we support both hardware pixel drawing and hardware streaming - #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM) + #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) // Is this a point if (GC->p.y == GC->p.y1) { #if GDISP_HARDWARE_DRAWPIXEL @@ -226,11 +209,9 @@ static void vline_clip(void) { #else // Worst is streaming GC->p.cx = GC->p.cy = 1; - gdisp_lld_stream_start(GC); - gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_write_start(GC); + gdisp_lld_write_color(GC); + gdisp_lld_write_stop(GC); #endif return; } @@ -241,15 +222,13 @@ static void vline_clip(void) { GC->p.cy = GC->p.y1 - GC->p.y + 1; GC->p.cx = 1; gdisp_lld_fill_area(GC); - #elif GDISP_HARDWARE_STREAM + #elif GDISP_HARDWARE_STREAM_WRITE // Next best is streaming GC->p.cy = GC->p.y1 - GC->p.y + 1; GC->p.cx = 1; - gdisp_lld_stream_start(GC); - do { gdisp_lld_stream_color(GC); } while(GC->p.cy--); - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_write_start(GC); + do { gdisp_lld_write_color(GC); } while(GC->p.cy--); + gdisp_lld_write_stop(GC); #else // Worst is drawing pixels for(; GC->p.y <= GC->p.y1; GC->p.y++) @@ -377,13 +356,13 @@ void _gdispInit(void) { GC->flags |= GDISP_FLG_INSTREAM; - #if GDISP_HARDWARE_STREAM + #if GDISP_HARDWARE_STREAM_WRITE // Best is hardware streaming GC->p.x = x; GC->p.y = y; GC->p.cx = cx; GC->p.cy = cy; - gdisp_lld_stream_start(GC); + gdisp_lld_write_start(GC); #else // Worst - save the parameters and use pixel drawing @@ -402,7 +381,7 @@ void _gdispInit(void) { } void gdispStreamColor(color_t color) { - #if !GDISP_HARDWARE_STREAM && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS + #if !GDISP_HARDWARE_STREAM_WRITE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS coord_t sx1, sy1; #endif @@ -412,10 +391,10 @@ void _gdispInit(void) { if (!(GC->flags & GDISP_FLG_INSTREAM)) return; - #if GDISP_HARDWARE_STREAM + #if GDISP_HARDWARE_STREAM_WRITE // Best is hardware streaming GC->p.color = color; - gdisp_lld_stream_color(GC); + gdisp_lld_write_color(GC); #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS GC->linebuf[GC->p.cx++] = color; if (GC->p.cx >= GDISP_LINEBUF_SIZE) { @@ -494,10 +473,8 @@ void _gdispInit(void) { if (!(GC->flags & GDISP_FLG_INSTREAM)) return; - #if GDISP_HARDWARE_STREAM - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + #if GDISP_HARDWARE_STREAM_WRITE + gdisp_lld_write_stop(GC); #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS if (GC->p.cx) { GC->p.x1 = 0; @@ -553,7 +530,7 @@ void gdispClear(color_t color) { GC->p.cy = GC->g.Height; GC->p.color = color; gdisp_lld_fill_area(GC); - #elif GDISP_HARDWARE_STREAM + #elif GDISP_HARDWARE_STREAM_WRITE // Next best is streaming uint32_t area; @@ -563,12 +540,10 @@ void gdispClear(color_t color) { GC->p.color = color; area = (uint32_t)GC->p.cx * GC->p.cy; - gdisp_lld_stream_start(GC); + gdisp_lld_write_start(GC); for(; area; area--) - gdisp_lld_stream_color(GC); - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_write_color(GC); + gdisp_lld_write_stop(GC); #else // Worst is drawing pixels GC->p.color = color; @@ -616,7 +591,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.x2 = srccx; GC->p.ptr = (void *)buffer; gdisp_lld_blit_area(GC); - #elif GDISP_HARDWARE_STREAM + #elif GDISP_HARDWARE_STREAM_WRITE // Next best is hardware streaming // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap @@ -629,16 +604,14 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.y = y; GC->p.cx = cx; GC->p.cy = cy; - gdisp_lld_stream_start(GC); + gdisp_lld_write_start(GC); for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { for(GC->p.x = x; GC->p.x < srcx; GC->p.x++) { GC->p.color = *buffer++; - gdisp_lld_stream_color(GC); + gdisp_lld_write_color(GC); } } - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_write_stop(GC); #elif GDISP_HARDWARE_FILLS // Only slightly better than drawing pixels is to look for runs and use fill area @@ -1578,17 +1551,15 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.x = x; GC->p.y = y; c = gdisp_lld_get_pixel_color(GC); - #elif GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_READ + #elif GDISP_HARDWARE_STREAM_READ // Next best is hardware streaming GC->p.x = x; GC->p.y = y; GC->p.cx = 1; GC->p.cy = 1; - gdisp_lld_stream_start(GC); - c = gdisp_lld_stream_read(GC); - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_read_start(GC); + c = gdisp_lld_read_color(GC); + gdisp_lld_read_stop(GC); #else // Worst is "not possible" #error "GDISP: GDISP_NEED_PIXELREAD has been set but there is no hardware support for reading the display" @@ -1634,7 +1605,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, #else cy -= abslines; if (lines < 0) { - fy = y+cx-1; + fy = y+cy-1; dy = -1; } else { fy = y; @@ -1652,18 +1623,16 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, fx = GDISP_LINEBUF_SIZE; // Read one line of data from the screen - #if GDISP_HARDWARE_STREAM && GDISP_HARDWARE_STREAM_READ + #if GDISP_HARDWARE_STREAM_READ // Best is hardware streaming GC->p.x = x+ix; GC->p.y = fy+lines; GC->p.cx = fx; GC->p.cy = 1; - gdisp_lld_stream_start(GC); + gdisp_lld_read_start(GC); for(j=0; j < fx; j++) - GC->linebuf[j] = gdisp_lld_stream_read(GC); - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + GC->linebuf[j] = gdisp_lld_read_color(GC); + gdisp_lld_read_stop(GC); #elif GDISP_HARDWARE_PIXELREAD // Next best is single pixel reads for(j=0; j < fx; j++) { @@ -1688,20 +1657,18 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.x2 = fx; GC->p.ptr = (void *)GC->linebuf; gdisp_lld_blit_area(GC); - #elif GDISP_HARDWARE_STREAM + #elif GDISP_HARDWARE_STREAM_WRITE // Next best is hardware streaming GC->p.x = x+ix; GC->p.y = fy; GC->p.cx = fx; GC->p.cy = 1; - gdisp_lld_stream_start(GC); + gdisp_lld_write_start(GC); for(j = 0; j < fx; j++) { GC->p.color = GC->linebuf[j]; - gdisp_lld_stream_color(GC); + gdisp_lld_write_color(GC); } - #if GDISP_HARDWARE_STREAM_STOP - gdisp_lld_stream_stop(GC); - #endif + gdisp_lld_write_stop(GC); #else // Worst is drawing pixels GC->p.y = fy; From 0f7777395b30ea8cec02b3230ed250eee7d34f16 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sun, 29 Sep 2013 18:23:22 +0200 Subject: [PATCH 025/160] GDISP X driver fixes --- drivers/multiple/X/gdisp_lld.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld.c index 9c6a7123..0e5e03b4 100644 --- a/drivers/multiple/X/gdisp_lld.c +++ b/drivers/multiple/X/gdisp_lld.c @@ -131,7 +131,6 @@ static int FatalXIOError(Display *d) { } LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { -{ XSizeHints *pSH; XSetWindowAttributes xa; XTextProperty WindowTitle; @@ -212,7 +211,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { gfxThreadClose(hth); /* Initialise the GDISP structure to match */ - g->g.Orientation = g->g_ROTATE_0; + g->g.Orientation = GDISP_ROTATE_0; g->g.Powermode = powerOn; g->g.Backlight = 100; g->g.Contrast = 50; @@ -269,10 +268,10 @@ LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) XImage *img; img = XGetImage (dis, pix, g->p.x, g->p.y, 1, 1, AllPlanes, XYPixmap); - color->pixel = XGetPixel (img, 0, 0); + color.pixel = XGetPixel (img, 0, 0); XFree(img); XQueryColor(dis, cmap, &color); - return RGB2COLOR(c.red>>8, c.green>>8, c.blue>>8); + return RGB2COLOR(color.red>>8, color.green>>8, color.blue>>8); } #endif From 3b1b5a4208ab8c29c9bb2f6eb448fd60e6cfe490 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sun, 29 Sep 2013 18:43:59 +0200 Subject: [PATCH 026/160] SSD1289 fixes --- drivers/gdisp/SSD1289/gdisp_lld.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 84ffa6d1..72db9914 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -47,7 +47,7 @@ #define delay(us) gfxSleepMicroseconds(us) #define delayms(ms) gfxSleepMilliseconds(ms) -static inline void set_cursor(coord_t x, coord_t y) { +static inline void set_cursor(GDISPDriver* g, coord_t x, coord_t y) { /* Reg 0x004E is an 8 bit value * Reg 0x004F is 9 bit * Use a bit mask to make sure they are not set too high @@ -72,7 +72,7 @@ static inline void set_cursor(coord_t x, coord_t y) { } } -static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { +static void set_viewport(GDISPDriver* g, coord_t x, coord_t y, coord_t cx, coord_t cy) { //set_cursor(x, y); @@ -108,11 +108,11 @@ static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { break; } - set_cursor(x, y); + set_cursor(g, x, y); } -static inline void reset_viewport(void) { - set_viewport(0, 0, g->g.Width, g->g.Height); +static inline void reset_viewport(GDISPDriver* g) { + set_viewport(g, 0, 0, g->g.Width, g->g.Height); } /*===========================================================================*/ @@ -197,11 +197,11 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #if GDISP_HARDWARE_STREAM_WRITE LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { acquire_bus(); - set_viewport(g->p.x, g->p.y, g->p.cx, g->p.cy); + set_viewport(g, g->p.x, g->p.y, g->p.cx, g->p.cy); stream_start(); } LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { - write_data(color); + write_data(g->p.color); } LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { stream_stop(); @@ -214,7 +214,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { uint16_t dummy; acquire_bus(); - set_viewport(g->p.x, g->p.y, g->p.cx, g->p.cy); + set_viewport(g, g->p.x, g->p.y, g->p.cx, g->p.cy); stream_start(); setreadmode(); dummy = read_data(); // dummy read From fdb74b412a01668795802840efe90ece3773478a Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 01:21:10 +1000 Subject: [PATCH 027/160] More SSD1289 orientation fixes and tidy-up --- drivers/gdisp/SSD1289/gdisp_lld.c | 98 ++++++++++++------------------- 1 file changed, 38 insertions(+), 60 deletions(-) diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 72db9914..2fe5a1e4 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -47,35 +47,7 @@ #define delay(us) gfxSleepMicroseconds(us) #define delayms(ms) gfxSleepMilliseconds(ms) -static inline void set_cursor(GDISPDriver* g, coord_t x, coord_t y) { - /* Reg 0x004E is an 8 bit value - * Reg 0x004F is 9 bit - * Use a bit mask to make sure they are not set too high - */ - switch(g->g.Orientation) { - case GDISP_ROTATE_180: - write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-x) & 0x00FF); - write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-y) & 0x01FF); - break; - case GDISP_ROTATE_0: - write_reg(0x004e, x & 0x00FF); - write_reg(0x004f, y & 0x01FF); - break; - case GDISP_ROTATE_270: - write_reg(0x004e, y & 0x00FF); - write_reg(0x004f, x & 0x01FF); - break; - case GDISP_ROTATE_90: - write_reg(0x004e, (GDISP_SCREEN_WIDTH - y - 1) & 0x00FF); - write_reg(0x004f, (GDISP_SCREEN_HEIGHT - x - 1) & 0x01FF); - break; - } -} - -static void set_viewport(GDISPDriver* g, coord_t x, coord_t y, coord_t cx, coord_t cy) { - - //set_cursor(x, y); - +static void set_viewport(GDISPDriver* g) { /* Reg 0x44 - Horizontal RAM address position * Upper Byte - HEA * Lower Byte - HSA @@ -84,35 +56,41 @@ static void set_viewport(GDISPDriver* g, coord_t x, coord_t y, coord_t cx, coord * Lower 9 bits gives 0-511 range in each value * 0 <= Reg(0x45) <= Reg(0x46) <= 0x13F */ - + /* Reg 0x004E is an 8 bit value + * Reg 0x004F is 9 bit + * Use a bit mask to make sure they are not set too high + */ switch(g->g.Orientation) { case GDISP_ROTATE_0: - write_reg(0x44, (((x+cx-1) << 8) & 0xFF00 ) | (x & 0x00FF)); - write_reg(0x45, y & 0x01FF); - write_reg(0x46, (y+cy-1) & 0x01FF); - break; - case GDISP_ROTATE_270: - write_reg(0x44, (((x+cx-1) << 8) & 0xFF00 ) | (y & 0x00FF)); - write_reg(0x45, x & 0x01FF); - write_reg(0x46, (x+cx-1) & 0x01FF); - break; - case GDISP_ROTATE_180: - write_reg(0x44, (((GDISP_SCREEN_WIDTH-x-1) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (x+cx)) & 0x00FF)); - write_reg(0x45, (GDISP_SCREEN_HEIGHT-(y+cy)) & 0x01FF); - write_reg(0x46, (GDISP_SCREEN_HEIGHT-y-1) & 0x01FF); + write_reg(0x44, (((g->p.x+g->p.cx-1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); + write_reg(0x45, g->p.y & 0x01FF); + write_reg(0x46, (g->p.y+g->p.cy-1) & 0x01FF); + write_reg(0x004e, g->p.x & 0x00FF); + write_reg(0x004f, g->p.y & 0x01FF); break; case GDISP_ROTATE_90: - write_reg(0x44, (((GDISP_SCREEN_WIDTH - y - 1) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (y+cy)) & 0x00FF)); - write_reg(0x45, (GDISP_SCREEN_HEIGHT - (x+cx)) & 0x01FF); - write_reg(0x46, (GDISP_SCREEN_HEIGHT - x - 1) & 0x01FF); + write_reg(0x44, (((g->p.y+g->p.cy-1) << 8) & 0xFF00 ) | (g->p.y & 0x00FF)); + write_reg(0x45, (GDISP_SCREEN_HEIGHT-(g->p.x+g->p.cx)) & 0x01FF); + write_reg(0x46, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); + write_reg(0x004e, g->p.y & 0x00FF); + write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); + break; + case GDISP_ROTATE_180: + write_reg(0x44, (((GDISP_SCREEN_WIDTH-g->p.x-1) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (g->p.x+g->p.cx)) & 0x00FF)); + write_reg(0x45, (GDISP_SCREEN_HEIGHT-(g->p.y+g->p.cy)) & 0x01FF); + write_reg(0x46, (GDISP_SCREEN_HEIGHT-g->p.y-1) & 0x01FF); + write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF); + write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); + break; + case GDISP_ROTATE_270: + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1); + write_reg(0x44, (((GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH-(g->p.y+g->p.cy)) & 0x00FF)); + write_reg(0x45, g->p.x & 0x01FF); + write_reg(0x46, (g->p.x+g->p.cx-1) & 0x01FF); + write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF); + write_reg(0x004f, g->p.x & 0x01FF); break; } - - set_cursor(g, x, y); -} - -static inline void reset_viewport(GDISPDriver* g) { - set_viewport(g, 0, 0, g->g.Width, g->g.Height); } /*===========================================================================*/ @@ -197,7 +175,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #if GDISP_HARDWARE_STREAM_WRITE LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { acquire_bus(); - set_viewport(g, g->p.x, g->p.y, g->p.cx, g->p.cy); + set_viewport(g); stream_start(); } LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { @@ -214,7 +192,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { uint16_t dummy; acquire_bus(); - set_viewport(g, g->p.x, g->p.y, g->p.cx, g->p.cy); + set_viewport(g); stream_start(); setreadmode(); dummy = read_data(); // dummy read @@ -232,7 +210,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #if GDISP_HARDWARE_FILLS && defined(GDISP_USE_DMA) LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { acquire_bus(); - set_viewport(g->p.x, g->p.y, g->p.cx, g->p.cy); + set_viewport(g); stream_start(); dma_with_noinc(&color, g->p.cx*g->p.cy) stream_stop(); @@ -248,7 +226,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { buffer = (pixel_t *)g->p.ptr + g->p.x1 + g->p.y1 * g->p.x2; acquire_bus(); - set_viewport(g->p.x, g->p.y, g->p.cx, g->p.cy); + set_viewport(g); stream_start(); if (g->p.x2 == g->p.cx) { @@ -310,8 +288,8 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { case GDISP_ROTATE_90: acquire_bus(); write_reg(0x0001, 0x293F); - /* ID = 11 AM = 1 */ - write_reg(0x0011, 0x6078); + /* ID = 01 AM = 1 */ + write_reg(0x0011, 0x6048); release_bus(); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; @@ -328,8 +306,8 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { case GDISP_ROTATE_270: acquire_bus(); write_reg(0x0001, 0x293F); - /* ID = 01 AM = 1 */ - write_reg(0x0011, 0x6048); + /* ID = 11 AM = 1 */ + write_reg(0x0011, 0x6078); release_bus(); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; From 39c10335a38c5ebd13613c5d3d433a0682fc2a6c Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 02:11:03 +1000 Subject: [PATCH 028/160] Scolling fix in X driver and removal of compiler warning. --- drivers/multiple/X/gdisp_lld.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld.c index 0e5e03b4..c60e2085 100644 --- a/drivers/multiple/X/gdisp_lld.c +++ b/drivers/multiple/X/gdisp_lld.c @@ -60,8 +60,6 @@ int depth; #endif static void ProcessEvent(void) { - XColor col; - switch(evt.type) { case Expose: XCopyArea(dis, pix, win, gc, @@ -282,7 +280,7 @@ LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) XCopyArea(dis, pix, win, gc, g->p.x, g->p.y, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); } else { XCopyArea(dis, pix, pix, gc, g->p.x, g->p.y, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); - XCopyArea(dis, pix, win, gc, g->p.x, g->p.y-lines, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); + XCopyArea(dis, pix, win, gc, g->p.x, g->p.y-g->p.y1, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); } } #endif From 3480001a799fe072b264bac58cca4d176b05ce3a Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 13:33:35 +1000 Subject: [PATCH 029/160] More orientation fixes for SSD1289. Orientation is now supported purely in RAM addressing direction which means the orientation of the display can be changed without affecting existing information on the display. Drawing then occurs in the new orientation. --- drivers/gdisp/SSD1289/gdisp_lld.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 2fe5a1e4..68cdf675 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -76,9 +76,9 @@ static void set_viewport(GDISPDriver* g) { write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); break; case GDISP_ROTATE_180: - write_reg(0x44, (((GDISP_SCREEN_WIDTH-g->p.x-1) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (g->p.x+g->p.cx)) & 0x00FF)); + write_reg(0x44, (((GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (g->p.x+g->p.cx)) & 0x00FF)); write_reg(0x45, (GDISP_SCREEN_HEIGHT-(g->p.y+g->p.cy)) & 0x01FF); - write_reg(0x46, (GDISP_SCREEN_HEIGHT-g->p.y-1) & 0x01FF); + write_reg(0x46, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF); write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); break; @@ -278,7 +278,6 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: acquire_bus(); - write_reg(0x0001, 0x2B3F); /* ID = 11 AM = 0 */ write_reg(0x0011, 0x6070); release_bus(); @@ -287,17 +286,15 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { break; case GDISP_ROTATE_90: acquire_bus(); - write_reg(0x0001, 0x293F); /* ID = 01 AM = 1 */ - write_reg(0x0011, 0x6048); + write_reg(0x0011, 0x6058); release_bus(); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: acquire_bus(); - write_reg(0x0001, 0x2B3F); - /* ID = 01 AM = 0 */ + /* ID = 00 AM = 0 */ write_reg(0x0011, 0x6040); release_bus(); g->g.Height = GDISP_SCREEN_HEIGHT; @@ -305,9 +302,8 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { break; case GDISP_ROTATE_270: acquire_bus(); - write_reg(0x0001, 0x293F); - /* ID = 11 AM = 1 */ - write_reg(0x0011, 0x6078); + /* ID = 10 AM = 1 */ + write_reg(0x0011, 0x6068); release_bus(); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; From 2c11cc3b942f2e3413a93f86d11db23c8cf6b1a7 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 13:39:39 +1000 Subject: [PATCH 030/160] SSD1289 tidy up --- drivers/gdisp/SSD1289/gdisp_lld.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 68cdf675..5743afc0 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -42,8 +42,6 @@ // Some common routines and macros #define write_reg(reg, data) { write_index(reg); write_data(data); } -#define stream_start() write_index(0x0022); -#define stream_stop() #define delay(us) gfxSleepMicroseconds(us) #define delayms(ms) gfxSleepMilliseconds(ms) @@ -55,9 +53,8 @@ static void set_viewport(GDISPDriver* g) { * Reg 0x45,0x46 - Vertical RAM address position * Lower 9 bits gives 0-511 range in each value * 0 <= Reg(0x45) <= Reg(0x46) <= 0x13F - */ - /* Reg 0x004E is an 8 bit value - * Reg 0x004F is 9 bit + * Reg 0x004E is an 8 bit value - start x position + * Reg 0x004F is 9 bit - start y position * Use a bit mask to make sure they are not set too high */ switch(g->g.Orientation) { @@ -91,6 +88,7 @@ static void set_viewport(GDISPDriver* g) { write_reg(0x004f, g->p.x & 0x01FF); break; } + write_index(0x0022); } /*===========================================================================*/ @@ -176,13 +174,11 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { acquire_bus(); set_viewport(g); - stream_start(); } LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { write_data(g->p.color); } LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { - stream_stop(); release_bus(); } #endif @@ -193,7 +189,6 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { acquire_bus(); set_viewport(g); - stream_start(); setreadmode(); dummy = read_data(); // dummy read } @@ -202,7 +197,6 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g) { setwritemode(); - stream_stop(); release_bus(); } #endif @@ -211,9 +205,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { acquire_bus(); set_viewport(g); - stream_start(); dma_with_noinc(&color, g->p.cx*g->p.cy) - stream_stop(); release_bus(); } #endif @@ -227,15 +219,12 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { acquire_bus(); set_viewport(g); - stream_start(); - if (g->p.x2 == g->p.cx) { dma_with_inc(buffer, g->p.cx*g->p.cy); } else { for (ycnt = g->p.cy; ycnt; ycnt--, buffer += g->p.x2) dma_with_inc(buffer, g->p.cy); } - stream_stop(); release_bus(); } #endif From dd54d42f004adfb54f8512ee8ea61b884e855672 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 15:40:52 +1000 Subject: [PATCH 031/160] Allow initial driver settings to be overridden by the board file --- drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 2 +- drivers/gdisp/SSD1289/gdisp_lld.c | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index bcccef80..a41ab3c9 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -65,8 +65,8 @@ #undef GDISP_SCREEN_WIDTH #endif -#include "GE8.h" #include "gdisp_lld_board.h" +#include "GE8.h" #define GDISP_SCAN_LINES 132 diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 5743afc0..c724e80b 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -19,6 +19,7 @@ #define GDISP_LLD_DECLARATIONS #include "gdisp/lld/gdisp_lld.h" +#include "gdisp_lld_board.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -30,16 +31,17 @@ #ifndef GDISP_SCREEN_WIDTH #define GDISP_SCREEN_WIDTH 240 #endif - -#define GDISP_INITIAL_CONTRAST 50 -#define GDISP_INITIAL_BACKLIGHT 100 +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -#include "gdisp_lld_board.h" - // Some common routines and macros #define write_reg(reg, data) { write_index(reg); write_data(data); } #define delay(us) gfxSleepMicroseconds(us) From 07f96ec3ee34fd4b4fffe2e6afbe50e982555fcb Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 15:41:32 +1000 Subject: [PATCH 032/160] HX8347D driver ported to new streaming structure (untested) --- drivers/gdisp/HX8347D/HX8347D.h | 2 +- drivers/gdisp/HX8347D/gdisp_lld.c | 440 ++++-------------- .../gdisp_lld_board_st_stm32f4_discovery.h | 155 +++--- .../gdisp/HX8347D/gdisp_lld_board_template.h | 49 +- drivers/gdisp/HX8347D/gdisp_lld_config.h | 7 +- 5 files changed, 189 insertions(+), 464 deletions(-) diff --git a/drivers/gdisp/HX8347D/HX8347D.h b/drivers/gdisp/HX8347D/HX8347D.h index b35dda12..280cd748 100644 --- a/drivers/gdisp/HX8347D/HX8347D.h +++ b/drivers/gdisp/HX8347D/HX8347D.h @@ -33,7 +33,7 @@ #define HX8347D_REG_PSLL 0x0b /* Partial area start row low */ #define HX8347D_REG_PELH 0x0c /* Partial area end row high */ #define HX8347D_REG_PELL 0x0d /* Partial area end row low */ -#define HX8347D_REG_TFAH 0x0e /* Vertical srcoll top fixed area high */ +#define HX8347D_REG_TFAH 0x0e /* Vertical scroll top fixed area high */ #define HX8347D_REG_TFAL 0x0f /* Vertical scroll top fixed area low */ #define HX8347D_REG_VSAH 0x10 /* Vertical scroll height area high */ diff --git a/drivers/gdisp/HX8347D/gdisp_lld.c b/drivers/gdisp/HX8347D/gdisp_lld.c index bcb6dfc0..a1e2c15b 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld.c +++ b/drivers/gdisp/HX8347D/gdisp_lld.c @@ -15,12 +15,11 @@ #include "gfx.h" -#include "HX8347D.h" - #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" +#include "gdisp_lld_board.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -32,74 +31,44 @@ #ifndef GDISP_SCREEN_WIDTH #define GDISP_SCREEN_WIDTH 240 #endif - -#define GDISP_INITIAL_CONTRAST 50 -#define GDISP_INITIAL_BACKLIGHT 50 +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -#include "gdisp_lld_board.h" +#include "HX8347D.h" -// Some common routines and macros -#define write_reg(reg, data) { write_index(reg); write_data(data); } -#define write_ram(color1, color2) { write_index(0x22); write_ram8(color1,color2); } -#define stream_start() { write_index(0x22); spiStart(&SPID1, &spi1cfg2); } -#define stream_stop() {while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0));palSetPad(GPIOA, 4);spiStart(&SPID1, &spi1cfg1); } -#define delay(us) gfxSleepMicroseconds(us) -#define delayms(ms) gfxSleepMilliseconds(ms) - -static inline void set_cursor(coord_t x, coord_t y) { - write_reg(HX8347D_REG_SCL, (uint8_t) x); - write_reg(HX8347D_REG_SCH, (uint8_t) (x >> 8)); - write_reg(HX8347D_REG_SPL, (uint8_t) y); - write_reg(HX8347D_REG_SPH, (uint8_t) (y >> 8)); +static inline void set_viewport(GDISPDriver* g) { + write_reg(HX8347D_REG_SCL, (uint8_t) g->p.x); + write_reg(HX8347D_REG_SCH, (uint8_t) (g->p.x >> 8)); + write_reg(HX8347D_REG_ECL, (uint8_t) (g->p.x + g->p.cx -1)); + write_reg(HX8347D_REG_ECH, (uint8_t) ((g->p.x + g->p.cx -1) >> 8)); + write_reg(HX8347D_REG_SPL, (uint8_t) g->p.y); + write_reg(HX8347D_REG_SPH, (uint8_t) (g->p.y >> 8)); + write_reg(HX8347D_REG_EPL, (uint8_t) (g->p.y + g->p.cy -1)); + write_reg(HX8347D_REG_EPH, (uint8_t) ((g->p.y + g->p.cy -1) >> 8)); + write_index(HX8347D_REG_SRAMWC); } -static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { - write_reg(HX8347D_REG_SCL, (uint8_t) x); - write_reg(HX8347D_REG_SCH, (uint8_t) (x >> 8)); - write_reg(HX8347D_REG_ECL, (uint8_t) (x + cx -1)); - write_reg(HX8347D_REG_ECH, (uint8_t) ((x + cx -1) >> 8)); - write_reg(HX8347D_REG_SPL, (uint8_t) y); - write_reg(HX8347D_REG_SPH, (uint8_t) (y >> 8)); - write_reg(HX8347D_REG_EPL, (uint8_t) (y + cy -1)); - write_reg(HX8347D_REG_EPH, (uint8_t) ((y + cy -1) >> 8)); -} - -static inline void reset_viewport(void) { - set_viewport(0, 0, GDISP.Width, GDISP.Height); -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ - -/** - * @brief Low level GDISP driver initialization. - * - * @notapi - */ -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { /* Initialise your display */ init_board(); // Hardware reset setpin_reset(TRUE); - delayms(1); + gfxSleepMilliseconds(1); setpin_reset(FALSE); - delayms(5); + gfxSleepMilliseconds(5); // Get the bus for the following initialisation commands acquire_bus(); @@ -154,329 +123,104 @@ bool_t gdisp_lld_init(void) { write_reg(HX8347D_REG_OSCCL, 0x01); /* OSC Control 2 */ write_reg(HX8347D_REG_DMODE, 0x00); /* Display Mode Control */ write_reg(HX8347D_REG_PWC6, 0x88); /* Power Control 6 */ - delayms(5); /* Delay 5 ms */ + gfxSleepMilliseconds(5); /* Delay 5 ms */ write_reg(HX8347D_REG_PWC6, 0x80); /* Power Control 6 */ - delayms(5); /* Delay 5 ms */ + gfxSleepMilliseconds(5); /* Delay 5 ms */ write_reg(HX8347D_REG_PWC6, 0x90); /* Power Control 6 */ - delayms(5); /* Delay 5 ms */ + gfxSleepMilliseconds(5); /* Delay 5 ms */ write_reg(HX8347D_REG_PWC6, 0xD0); /* Power Control 6 */ - delayms(5); /* Delay 5 ms */ + gfxSleepMilliseconds(5); /* Delay 5 ms */ write_reg(HX8347D_REG_COLMOD, 0x05); /* Colmod 16Bit/Pixel */ write_reg(HX8347D_REG_PCH, 0x00); /* Panel Characteristic */ write_reg(HX8347D_REG_DC3, 0x38); /* Display Control 3 */ - delayms(40); + gfxSleepMilliseconds(40); /* Delay 40 ms */ write_reg(HX8347D_REG_DC3, 0x3C); /* Display Control 3 */ write_reg(HX8347D_REG_MAC, 0x08); /* Memory access control */ - write_reg(HX8347D_REG_SCL, 0x00); - write_reg(HX8347D_REG_SCH, 0x00); - write_reg(HX8347D_REG_ECL, 0xef); - write_reg(HX8347D_REG_ECH, 0x00); - write_reg(HX8347D_REG_SPL, 0x00); - write_reg(HX8347D_REG_SPH, 0x00); - write_reg(HX8347D_REG_EPL, 0x3f); - write_reg(HX8347D_REG_EPH, 0x01); - // Release the bus release_bus(); /* Turn on the backlight */ set_backlight(GDISP_INITIAL_BACKLIGHT); - /* Initialise the GDISP structure */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = GDISP_INITIAL_BACKLIGHT; - GDISP.Contrast = GDISP_INITIAL_CONTRAST; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - acquire_bus(); - set_cursor(x, y); - write_ram((color >> 8) & 0xFF, color & 0xFF); - release_bus(); -} - -/* ---- Optional Routines ---- */ -/* - All the below routines are optional. - Defining them will increase speed but everything - will work if they are not defined. - If you are not using a routine - turn it off using - the appropriate GDISP_HARDWARE_XXXX macro. - Don't bother coding for obvious similar routines if - there is no performance penalty as the emulation software - makes a good job of using similar routines. - eg. If gfillarea() is defined there is little - point in defining clear() unless the - performance bonus is significant. - For good performance it is suggested to implement - fillarea() and blitarea(). -*/ - -#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) - /** - * @brief Clear the display. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] color The color of the pixel - * - * @notapi - */ - void gdisp_lld_clear(color_t color) { - unsigned i; - +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { acquire_bus(); - reset_viewport(); - stream_start(); - for(i = 0; i < GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT; i++) - write_ram16(color); - stream_stop(); + set_viewport(g); + busmode16(); + } + LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { + write_ram16(g->p.color); + } + LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { + busmode8(); release_bus(); } #endif -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - unsigned i, area; +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + switch(g->p.x) { + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(); + write_reg(HX8347D_REG_MAC, 0x08); /* Memory access control */ + release_bus(); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif + case GDISP_ROTATE_90: + acquire_bus(); + write_reg(HX8347D_REG_MAC, 0x68); /* Memory access control */ + release_bus(); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; - area = cx*cy; + case GDISP_ROTATE_180: + acquire_bus(); + write_reg(HX8347D_REG_MAC, 0xc8); /* Memory access control */ + release_bus(); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; - acquire_bus(); - set_viewport(x, y, cx, cy); - stream_start(); - for(i = 0; i < area; i++) - write_ram16(color); - stream_stop(); - release_bus(); - } -#endif + case GDISP_ROTATE_270: + acquire_bus(); + write_reg(HX8347D_REG_MAC, 0xa8); /* Memory access control */ + release_bus(); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a bitmap. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - coord_t endx, endy; - unsigned lg; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - acquire_bus(); - set_viewport(x, y, cx, cy); - stream_start(); - - endx = srcx + cx; - endy = y + cy; - lg = srccx - cx; - buffer += srcx + srcy * srccx; - for(; y < endy; y++, buffer += lg) - for(x=srcx; x < endx; x++) - write_data(*buffer++); - stream_stop(); - release_bus(); - } -#endif - -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) - /** - * @brief Get the color of a particular pixel. - * @note Optional. - * @note If x,y is off the screen, the result is undefined. - * - * @param[in] x, y The pixel to be read - * - * @notapi - */ - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - color_t color; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; - #endif -} -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @note Optional. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - static color_t buf[((GDISP_SCREEN_HEIGHT > GDISP_SCREEN_WIDTH ) ? GDISP_SCREEN_HEIGHT : GDISP_SCREEN_WIDTH)]; - coord_t row0, row1; - unsigned i, abslines, j; - static int gap; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - } -#endif - -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { - switch(what) { - case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) + default: return; - switch((gdisp_orientation_t)value) { - case GDISP_ROTATE_0: - acquire_bus(); - write_reg(HX8347D_REG_MAC, 0x08); /* Memory access control */ - write_reg(HX8347D_REG_ECL, 0xef); - write_reg(HX8347D_REG_ECH, 0x00); - write_reg(HX8347D_REG_EPL, 0x3f); - write_reg(HX8347D_REG_EPH, 0x01); - release_bus(); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; + } + g->g.Orientation = (orientation_t)value; + return; + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight((unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; - case GDISP_ROTATE_90: - acquire_bus(); - write_reg(HX8347D_REG_MAC, 0x68); /* Memory access control */ - write_reg(HX8347D_REG_ECL, 0x3f); - write_reg(HX8347D_REG_ECH, 0x01); - write_reg(HX8347D_REG_EPL, 0xef); - write_reg(HX8347D_REG_EPH, 0x00); - release_bus(); - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - - case GDISP_ROTATE_180: - acquire_bus(); - write_reg(HX8347D_REG_MAC, 0xc8); /* Memory access control */ - write_reg(HX8347D_REG_ECL, 0xef); - write_reg(HX8347D_REG_ECH, 0x00); - write_reg(HX8347D_REG_EPL, 0x3f); - write_reg(HX8347D_REG_EPH, 0x01); - release_bus(); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - - case GDISP_ROTATE_270: - acquire_bus(); - write_reg(HX8347D_REG_MAC, 0xa8); /* Memory access control */ - write_reg(HX8347D_REG_ECL, 0x3f); - write_reg(HX8347D_REG_ECH, 0x01); - write_reg(HX8347D_REG_EPL, 0xef); - write_reg(HX8347D_REG_EPH, 0x00); - release_bus(); - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - - default: - return; - } - - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; - return; - - case GDISP_CONTROL_BACKLIGHT: - if ((unsigned)value > 100) - value = (void *)100; - set_backlight((unsigned)value); - GDISP.Backlight = (unsigned)value; - return; - - default: - return; + default: + return; } } #endif diff --git a/drivers/gdisp/HX8347D/gdisp_lld_board_st_stm32f4_discovery.h b/drivers/gdisp/HX8347D/gdisp_lld_board_st_stm32f4_discovery.h index 984b92dd..8365fe74 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld_board_st_stm32f4_discovery.h +++ b/drivers/gdisp/HX8347D/gdisp_lld_board_st_stm32f4_discovery.h @@ -16,21 +16,31 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H -#define SET_RST palSetPad(GPIOB, 8); -#define CLR_RST palClearPad(GPIOB, 8); +// Overrides +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 50 +#endif + +/* Pin assignments */ +#define SET_RST palSetPad(GPIOB, 8) +#define CLR_RST palClearPad(GPIOB, 8) +#define SET_DATA palSetPad(GPIOB, 9) +#define CLR_DATA palClearPad(GPIOB, 9) +#define SET_CS palSetPad(GPIOA, 4) +#define CLR_CS palClearPad(GPIOA, 4) /* PWM configuration structure. We use timer 4 channel 2 (orange LED on board). */ static const PWMConfig pwmcfg = { - 1000000, /* 1 MHz PWM clock frequency. */ - 100, /* PWM period is 100 cycles. */ - NULL, - { - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL} - }, - 0 + 1000000, /* 1 MHz PWM clock frequency. */ + 100, /* PWM period is 100 cycles. */ + NULL, + { + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL} + }, + 0 }; /* @@ -38,12 +48,12 @@ static const PWMConfig pwmcfg = { * Speed 42MHz, CPHA=0, CPOL=0, 8bits frames, MSb transmitted first. * The slave select line is the pin 4 on the port GPIOA. */ -static const SPIConfig spi1cfg1 = { - NULL, - /* HW dependent part.*/ - GPIOA, - 4, - 0 //SPI_CR1_BR_0 +static const SPIConfig spi1cfg_8bit = { + NULL, + /* HW dependent part.*/ + GPIOA, + 4, + 0 //SPI_CR1_BR_0 }; /* @@ -51,48 +61,42 @@ static const SPIConfig spi1cfg1 = { * Speed 42MHz, CPHA=0, CPOL=0, 16bits frames, MSb transmitted first. * The slave select line is the pin 4 on the port GPIOA. */ -static const SPIConfig spi1cfg2 = { - NULL, - /* HW dependent part.*/ - GPIOA, - 4, - SPI_CR1_DFF //SPI_CR1_BR_0 +static const SPIConfig spi1cfg_16bit = { + NULL, + /* HW dependent part.*/ + GPIOA, + 4, + SPI_CR1_DFF //SPI_CR1_BR_0 }; /** * @brief Initialise the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins + * @notes This board definition uses GPIO and SPI. It assumes exclusive access to these GPIO pins but not necessarily the SPI port. * * @notapi */ static inline void init_board(void) { - /* Display backlight control */ /* TIM4 is an alternate function 2 (AF2) */ pwmStart(&PWMD4, &pwmcfg); palSetPadMode(GPIOD, 13, PAL_MODE_ALTERNATE(2)); pwmEnableChannel(&PWMD4, 1, 100); - palSetPadMode(GPIOB, 8, PAL_MODE_OUTPUT_PUSHPULL | - PAL_STM32_OSPEED_HIGHEST); /* RST */ - palSetPadMode(GPIOB, 9, PAL_MODE_OUTPUT_PUSHPULL | - PAL_STM32_OSPEED_HIGHEST); /* RS */ + palSetPadMode(GPIOB, 8, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST); /* RST */ + palSetPadMode(GPIOB, 9, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST); /* RS */ /* - * Initializes the SPI driver 1. The SPI1 signals are routed as follow: - * PB12 - NSS. - * PB13 - SCK. - * PB14 - MISO. - * PB15 - MOSI. - */ - spiStart(&SPID1, &spi1cfg1); - palSetPad(GPIOA, 4); - palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL | - PAL_STM32_OSPEED_HIGHEST); /* NSS. */ - palSetPadMode(GPIOA, 5, PAL_MODE_ALTERNATE(5) | - PAL_STM32_OSPEED_HIGHEST); /* SCK. */ - palSetPadMode(GPIOA, 6, PAL_MODE_ALTERNATE(5)); /* MISO. */ - palSetPadMode(GPIOA, 7, PAL_MODE_ALTERNATE(5) | - PAL_STM32_OSPEED_HIGHEST); /* MOSI. */ + * Initializes the SPI driver 1. The SPI1 signals are routed as follow: + * PB12 - NSS. + * PB13 - SCK. + * PB14 - MISO. + * PB15 - MOSI. + */ + SET_CS; SET_DATA; + spiStart(&SPID1, &spi1cfg_8bit); + palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST); /* NSS. */ + palSetPadMode(GPIOA, 5, PAL_MODE_ALTERNATE(5)|PAL_STM32_OSPEED_HIGHEST); /* SCK. */ + palSetPadMode(GPIOA, 6, PAL_MODE_ALTERNATE(5)); /* MISO. */ + palSetPadMode(GPIOA, 7, PAL_MODE_ALTERNATE(5)|PAL_STM32_OSPEED_HIGHEST); /* MOSI. */ } @@ -124,79 +128,70 @@ static inline void set_backlight(uint8_t percent) { /** * @brief Take exclusive control of the bus - * @note Not needed, not implemented - * * @notapi */ static inline void acquire_bus(void) { spiAcquireBus(&SPID1); + while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); // Safety + CLR_CS; } /** * @brief Release exclusive control of the bus - * @note Not needed, not implemented - * * @notapi */ static inline void release_bus(void) { + SET_CS; spiReleaseBus(&SPID1); } /** - * @brief Send data to the index register. + * @brief Set the bus in 16 bit mode + * @notapi + */ +static inline void busmode16(void) { + spiStart(&SPID1, &spi1cfg_16bit); +} + +/** + * @brief Set the bus in 8 bit mode (the default) + * @notapi + */ +static inline void busmode8(void) { + spiStart(&SPID1, &spi1cfg_8bit); +} + +/** + * @brief Set which index register to use. * * @param[in] index The index register to set * * @notapi */ static inline void write_index(uint8_t cmd) { - palClearPad(GPIOB, 9); - palClearPad(GPIOA, 4); - while((SPI1->SR & SPI_SR_TXE) == 0); + CLR_DATA; SPI1->DR = cmd; while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); - palSetPad(GPIOB, 9); + SET_DATA; } /** - * @brief Send data to the lcd. + * @brief Send a command to the lcd. * * @param[in] data The data to send * * @notapi */ -static inline void write_data(uint8_t data) { +static inline void write_reg(uint8_t cmd, uint8_t data) { + write_index(cmd); SPI1->DR = data; while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); - palSetPad(GPIOA, 4); -} - -static inline void write_ram8(uint8_t data1, uint8_t data2) { - SPI1->DR = data1; - while((SPI1->SR & SPI_SR_TXE) == 0); - SPI1->DR = data2; - while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); - palSetPad(GPIOA, 4); } static inline void write_ram16(uint16_t data) { - while((SPI1->SR & SPI_SR_TXE) == 0); SPI1->DR = data; + while((SPI1->SR & SPI_SR_TXE) == 0); } -#if GDISP_HARDWARE_READPIXEL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { -} -#endif - #endif /* _GDISP_LLD_BOARD_H */ /** @} */ diff --git a/drivers/gdisp/HX8347D/gdisp_lld_board_template.h b/drivers/gdisp/HX8347D/gdisp_lld_board_template.h index 295a7997..d3b71d97 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld_board_template.h +++ b/drivers/gdisp/HX8347D/gdisp_lld_board_template.h @@ -18,8 +18,6 @@ /** * @brief Initialise the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins - * * @notapi */ static inline void init_board(void) { @@ -50,8 +48,6 @@ static inline void set_backlight(uint8_t percent) { /** * @brief Take exclusive control of the bus - * @note Not needed, not implemented - * * @notapi */ static inline void acquire_bus(void) { @@ -60,8 +56,6 @@ static inline void acquire_bus(void) { /** * @brief Release exclusive control of the bus - * @note Not needed, not implemented - * * @notapi */ static inline void release_bus(void) { @@ -69,7 +63,23 @@ static inline void release_bus(void) { } /** - * @brief Send data to the index register. + * @brief Set the bus in 16 bit mode + * @notapi + */ +static inline void busmode16(void) { + +} + +/** + * @brief Set the bus in 8 bit mode (the default) + * @notapi + */ +static inline void busmode8(void) { + +} + +/** + * @brief Set which index register to use. * * @param[in] index The index register to set * @@ -80,19 +90,13 @@ static inline void write_index(uint8_t cmd) { } /** - * @brief Send data to the lcd. + * @brief Send a command to the lcd. * * @param[in] data The data to send * * @notapi */ -static inline void write_data(uint8_t data) { - - - -} - -static inline void write_ram8(uint8_t data1, uint8_t data2) { +static inline void write_reg(uint8_t cmd, uint8_t data) { } @@ -100,21 +104,6 @@ static inline void write_ram16(uint16_t data) { } -#if GDISP_HARDWARE_READPIXEL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} -#endif - #endif /* _GDISP_LLD_BOARD_H */ /** @} */ diff --git a/drivers/gdisp/HX8347D/gdisp_lld_config.h b/drivers/gdisp/HX8347D/gdisp_lld_config.h index 7bf47ade..a5a8e2b8 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld_config.h +++ b/drivers/gdisp/HX8347D/gdisp_lld_config.h @@ -23,12 +23,9 @@ /*===========================================================================*/ #define GDISP_DRIVER_NAME "HX8347D" +#define GDISP_DRIVER_STRUCT GDISP_HX8347D -#define GDISP_HARDWARE_CLEARS TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -#define GDISP_HARDWARE_SCROLL FALSE -#define GDISP_HARDWARE_PIXELREAD FALSE +#define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 From fd01f1a4f3569e84884c46388e2e3df7e1647365 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 16:25:46 +1000 Subject: [PATCH 033/160] ILI9320 driver ported to streaming interface. --- drivers/gdisp/ILI9320/gdisp_lld.c | 736 ++++++------------ .../gdisp_lld_board_olimex_pic32mx_lcd.h | 19 +- .../gdisp_lld_board_olimex_stm32_lcd.h | 18 +- .../gdisp/ILI9320/gdisp_lld_board_template.h | 20 +- drivers/gdisp/ILI9320/gdisp_lld_config.h | 12 +- 5 files changed, 293 insertions(+), 512 deletions(-) diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index c432cd35..8dc529dd 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -8,19 +8,14 @@ /** * @file drivers/gdisp/ILI9320/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for the ILI9320 display. - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" - -#include "gdisp_lld_board.h" +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -36,15 +31,20 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_SCREEN_WIDTH 240 -#define GDISP_SCREEN_HEIGHT 320 +#include "gdisp_lld_board.h" -#define GDISP_INITIAL_CONTRAST 50 -#define GDISP_INITIAL_BACKLIGHT 100 - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 320 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif /*===========================================================================*/ /* Driver local variables. */ @@ -54,531 +54,293 @@ uint32_t DISPLAY_CODE; /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -static inline void lld_lcdDelay(uint16_t us) { - gfxSleepMicroseconds(us); + +#define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } +#define write_reg(reg, data) { write_index(reg); write_data(data); } + +static void set_viewport(uint16_t x, uint16_t y, uint16_t cx, uint16_t cy) { + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + write_reg(0x0050, x); + write_reg(0x0051, x + cx - 1); + write_reg(0x0052, y); + write_reg(0x0053, y + cy - 1); + write_reg(0x0020, x); + write_reg(0x0021, y); + break; + + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + write_reg(0x0050, y); + write_reg(0x0051, y + cy - 1); + write_reg(0x0052, x); + write_reg(0x0053, x + cx - 1); + write_reg(0x0020, y); + write_reg(0x0021, x); + break; + } + write_index(0x0022); } -static inline void lld_lcdWriteIndex(uint16_t index) { - gdisp_lld_write_index(index); -} - -static inline void lld_lcdWriteData(uint16_t data) { - gdisp_lld_write_data(data); -} - -static inline void lld_lcdWriteReg(uint16_t lcdReg, uint16_t lcdRegValue) { - gdisp_lld_write_index(lcdReg); - gdisp_lld_write_data(lcdRegValue); -} - -static inline uint16_t lld_lcdReadData(void) { - return gdisp_lld_read_data(); -} - -static inline uint16_t lld_lcdReadReg(uint16_t lcdReg) { - volatile uint16_t dummy; - - gdisp_lld_write_index(lcdReg); - dummy = lld_lcdReadData(); - (void)dummy; - - return lld_lcdReadData(); -} - -static inline void lld_lcdWriteStreamStart(void) { - lld_lcdWriteIndex(0x0022); -} - -static inline void lld_lcdWriteStreamStop(void) { - -} - -static inline void lld_lcdWriteStream(uint16_t *buffer, uint16_t size) { - uint16_t i; - - for(i = 0; i < size; i++) - lld_lcdWriteData(buffer[i]); -} - -static inline void lld_lcdReadStreamStart(void) { - lld_lcdWriteIndex(0x0022); -} - -static inline void lld_lcdReadStreamStop(void) { - -} - -static inline void lld_lcdReadStream(uint16_t *buffer, size_t size) { - uint16_t i; - volatile uint16_t dummy; - - dummy = lld_lcdReadData(); - (void)dummy; - - for(i = 0; i < size; i++) - buffer[i] = lld_lcdReadData(); -} - -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { /* Initialise your display */ - gdisp_lld_init_board(); + init_board(); /* Hardware reset */ - gdisp_lld_reset_pin(TRUE); - lld_lcdDelay(1000); - gdisp_lld_reset_pin(FALSE); - lld_lcdDelay(1000); + setpin_reset(TRUE); + gfxSleepMicroseconds(1000); + setpin_reset(FALSE); + gfxSleepMicroseconds(1000); - DISPLAY_CODE = lld_lcdReadReg(0); - lld_lcdWriteReg(0x0000, 0x0001); //start Int. osc - lld_lcdDelay(500); - lld_lcdWriteReg(0x0001, 0x0100); //Set SS bit (shift direction of outputs is from S720 to S1) - lld_lcdWriteReg(0x0002, 0x0700); //select the line inversion - lld_lcdWriteReg(0x0003, 0x1038); //Entry mode(Horizontal : increment,Vertical : increment, AM=1) - lld_lcdWriteReg(0x0004, 0x0000); //Resize control(No resizing) - lld_lcdWriteReg(0x0008, 0x0202); //front and back porch 2 lines - lld_lcdWriteReg(0x0009, 0x0000); //select normal scan - lld_lcdWriteReg(0x000A, 0x0000); //display control 4 - lld_lcdWriteReg(0x000C, 0x0000); //system interface(2 transfer /pixel), internal sys clock, - lld_lcdWriteReg(0x000D, 0x0000); //Frame marker position - lld_lcdWriteReg(0x000F, 0x0000); //selects clk, enable and sync signal polarity, - lld_lcdWriteReg(0x0010, 0x0000); // - lld_lcdWriteReg(0x0011, 0x0000); //power control 2 reference voltages = 1:1, - lld_lcdWriteReg(0x0012, 0x0000); //power control 3 VRH - lld_lcdWriteReg(0x0013, 0x0000); //power control 4 VCOM amplitude - lld_lcdDelay(500); - lld_lcdWriteReg(0x0010, 0x17B0); //power control 1 BT,AP - lld_lcdWriteReg(0x0011, 0x0137); //power control 2 DC,VC - lld_lcdDelay(500); - lld_lcdWriteReg(0x0012, 0x0139); //power control 3 VRH - lld_lcdDelay(500); - lld_lcdWriteReg(0x0013, 0x1d00); //power control 4 vcom amplitude - lld_lcdWriteReg(0x0029, 0x0011); //power control 7 VCOMH - lld_lcdDelay(500); - lld_lcdWriteReg(0x0030, 0x0007); - lld_lcdWriteReg(0x0031, 0x0403); - lld_lcdWriteReg(0x0032, 0x0404); - lld_lcdWriteReg(0x0035, 0x0002); - lld_lcdWriteReg(0x0036, 0x0707); - lld_lcdWriteReg(0x0037, 0x0606); - lld_lcdWriteReg(0x0038, 0x0106); - lld_lcdWriteReg(0x0039, 0x0007); - lld_lcdWriteReg(0x003c, 0x0700); - lld_lcdWriteReg(0x003d, 0x0707); - lld_lcdWriteReg(0x0020, 0x0000); //starting Horizontal GRAM Address - lld_lcdWriteReg(0x0021, 0x0000); //starting Vertical GRAM Address - lld_lcdWriteReg(0x0050, 0x0000); //Horizontal GRAM Start Position - lld_lcdWriteReg(0x0051, 0x00EF); //Horizontal GRAM end Position - lld_lcdWriteReg(0x0052, 0x0000); //Vertical GRAM Start Position - lld_lcdWriteReg(0x0053, 0x013F); //Vertical GRAM end Position + acquire_bus(); + write_index(0); // Get controller version + dummy_read(); + DISPLAY_CODE = read_data(); + write_reg(0x0000, 0x0001); //start Int. osc + gfxSleepMicroseconds(500); + write_reg(0x0001, 0x0100); //Set SS bit (shift direction of outputs is from S720 to S1) + write_reg(0x0002, 0x0700); //select the line inversion + write_reg(0x0003, 0x1038); //Entry mode(Horizontal : increment,Vertical : increment, AM=1) + write_reg(0x0004, 0x0000); //Resize control(No resizing) + write_reg(0x0008, 0x0202); //front and back porch 2 lines + write_reg(0x0009, 0x0000); //select normal scan + write_reg(0x000A, 0x0000); //display control 4 + write_reg(0x000C, 0x0000); //system interface(2 transfer /pixel), internal sys clock, + write_reg(0x000D, 0x0000); //Frame marker position + write_reg(0x000F, 0x0000); //selects clk, enable and sync signal polarity, + write_reg(0x0010, 0x0000); // + write_reg(0x0011, 0x0000); //power control 2 reference voltages = 1:1, + write_reg(0x0012, 0x0000); //power control 3 VRH + write_reg(0x0013, 0x0000); //power control 4 VCOM amplitude + gfxSleepMicroseconds(500); + write_reg(0x0010, 0x17B0); //power control 1 BT,AP + write_reg(0x0011, 0x0137); //power control 2 DC,VC + gfxSleepMicroseconds(500); + write_reg(0x0012, 0x0139); //power control 3 VRH + gfxSleepMicroseconds(500); + write_reg(0x0013, 0x1d00); //power control 4 vcom amplitude + write_reg(0x0029, 0x0011); //power control 7 VCOMH + gfxSleepMicroseconds(500); + write_reg(0x0030, 0x0007); + write_reg(0x0031, 0x0403); + write_reg(0x0032, 0x0404); + write_reg(0x0035, 0x0002); + write_reg(0x0036, 0x0707); + write_reg(0x0037, 0x0606); + write_reg(0x0038, 0x0106); + write_reg(0x0039, 0x0007); + write_reg(0x003c, 0x0700); + write_reg(0x003d, 0x0707); + write_reg(0x0020, 0x0000); //starting Horizontal GRAM Address + write_reg(0x0021, 0x0000); //starting Vertical GRAM Address + write_reg(0x0050, 0x0000); //Horizontal GRAM Start Position + write_reg(0x0051, 0x00EF); //Horizontal GRAM end Position + write_reg(0x0052, 0x0000); //Vertical GRAM Start Position + write_reg(0x0053, 0x013F); //Vertical GRAM end Position switch (DISPLAY_CODE) { case 0x9320: - lld_lcdWriteReg(0x0060, 0x2700); //starts scanning from G1, and 320 drive lines + write_reg(0x0060, 0x2700); //starts scanning from G1, and 320 drive lines break; case 0x9325: - lld_lcdWriteReg(0x0060, 0xA700); //starts scanning from G1, and 320 drive lines + write_reg(0x0060, 0xA700); //starts scanning from G1, and 320 drive lines break; } - lld_lcdWriteReg(0x0061, 0x0001); //fixed base display - lld_lcdWriteReg(0x006a, 0x0000); //no scroll - lld_lcdWriteReg(0x0090, 0x0010); //set Clocks/Line =16, Internal Operation Clock Frequency=fosc/1, - lld_lcdWriteReg(0x0092, 0x0000); //set gate output non-overlap period=0 - lld_lcdWriteReg(0x0093, 0x0003); //set Source Output Position=3 - lld_lcdWriteReg(0x0095, 0x0110); //RGB interface(Clocks per line period=16 clocks) - lld_lcdWriteReg(0x0097, 0x0110); //set Gate Non-overlap Period 0 locksc - lld_lcdWriteReg(0x0098, 0x0110); // - lld_lcdWriteReg(0x0007, 0x0173); //display On + write_reg(0x0061, 0x0001); //fixed base display + write_reg(0x006a, 0x0000); //no scroll + write_reg(0x0090, 0x0010); //set Clocks/Line =16, Internal Operation Clock Frequency=fosc/1, + write_reg(0x0092, 0x0000); //set gate output non-overlap period=0 + write_reg(0x0093, 0x0003); //set Source Output Position=3 + write_reg(0x0095, 0x0110); //RGB interface(Clocks per line period=16 clocks) + write_reg(0x0097, 0x0110); //set Gate Non-overlap Period 0 locksc + write_reg(0x0098, 0x0110); // + write_reg(0x0007, 0x0173); //display On + release_bus(); // Turn on the backlight - gdisp_lld_backlight(GDISP_INITIAL_BACKLIGHT); + set_backlight(GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = GDISP_INITIAL_BACKLIGHT; - GDISP.Contrast = GDISP_INITIAL_CONTRAST; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -static void lld_lcdSetCursor(uint16_t x, uint16_t y) { - - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - lld_lcdWriteReg(0x0020, x); - lld_lcdWriteReg(0x0021, y); - break; - - case GDISP_ROTATE_90: - lld_lcdWriteReg(0x0020, y); - lld_lcdWriteReg(0x0021, x); - break; - - case GDISP_ROTATE_180: - lld_lcdWriteReg(0x0020, x); - lld_lcdWriteReg(0x0021, y); - break; - - case GDISP_ROTATE_270: - lld_lcdWriteReg(0x0020, y); - lld_lcdWriteReg(0x0021, x); - break; +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { + acquire_bus(); + set_viewport(g); } -} - -static void lld_lcdSetViewPort(uint16_t x, uint16_t y, uint16_t cx, uint16_t cy) { - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - lld_lcdWriteReg(0x0050, x); - lld_lcdWriteReg(0x0051, x + cx - 1); - lld_lcdWriteReg(0x0052, y); - lld_lcdWriteReg(0x0053, y + cy - 1); - break; - - case GDISP_ROTATE_90: - lld_lcdWriteReg(0x0050, y); - lld_lcdWriteReg(0x0051, y + cy - 1); - lld_lcdWriteReg(0x0052, x); - lld_lcdWriteReg(0x0053, x + cx - 1); - break; - - case GDISP_ROTATE_180: - lld_lcdWriteReg(0x0050, x); - lld_lcdWriteReg(0x0051, x + cx - 1); - lld_lcdWriteReg(0x0052, y); - lld_lcdWriteReg(0x0053, y + cy - 1); - break; - - case GDISP_ROTATE_270: - lld_lcdWriteReg(0x0050, y); - lld_lcdWriteReg(0x0051, y + cy - 1); - lld_lcdWriteReg(0x0052, x); - lld_lcdWriteReg(0x0053, x + cx - 1); - break; + LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { + write_data(g->p.color); } - - lld_lcdSetCursor(x, y); -} - -static inline void lld_lcdResetViewPort(void) { - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - case GDISP_ROTATE_180: - lld_lcdSetViewPort(0, 0, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT); - break; - case GDISP_ROTATE_90: - case GDISP_ROTATE_270: - lld_lcdSetViewPort(0, 0, GDISP_SCREEN_HEIGHT, GDISP_SCREEN_WIDTH); - break; - } -} - -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - lld_lcdSetCursor(x, y); - lld_lcdWriteReg(0x0022, color); -} - -#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) - void gdisp_lld_clear(color_t color) { - unsigned i; - - lld_lcdSetCursor(0, 0); - lld_lcdWriteStreamStart(); - - for(i = 0; i < GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT; i++) - lld_lcdWriteData(color); - - lld_lcdWriteStreamStop(); + LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { + release_bus(); } #endif -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - unsigned i, area; - - area = cx*cy; - lld_lcdSetViewPort(x, y, cx, cy); - lld_lcdWriteStreamStart(); - for(i = 0; i < area; i++) - lld_lcdWriteData(color); - lld_lcdWriteStreamStop(); - lld_lcdResetViewPort(); +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { + acquire_bus(); + set_viewport(g); + setreadmode(); + dummy_read(); + } + LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g) { + return read_data(); + } + LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g) { + setwritemode(); + release_bus(); } #endif -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - coord_t endx, endy; - unsigned lg; +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + acquire_bus(); + write_reg(0x0007, 0x0000); + write_reg(0x0010, 0x0000); + write_reg(0x0011, 0x0000); + write_reg(0x0012, 0x0000); + write_reg(0x0013, 0x0000); + release_bus(); - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif + set_backlight(0); + break; - lld_lcdSetViewPort(x, y, cx, cy); - lld_lcdWriteStreamStart(); + case powerOn: + //*************Power On sequence ******************// + acquire_bus(); + write_reg(0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ + write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + gfxSleepMicroseconds(2000); /* Dis-charge capacitor power voltage */ + write_reg(0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(0x0011, 0x0147); /* DC1[2:0], DC0[2:0], VC[2:0] */ + gfxSleepMicroseconds(500); + write_reg(0x0012, 0x013C); /* VREG1OUT voltage */ + gfxSleepMicroseconds(500); + write_reg(0x0013, 0x0E00); /* VDV[4:0] for VCOM amplitude */ + write_reg(0x0029, 0x0009); /* VCM[4:0] for VCOMH */ + gfxSleepMicroseconds(500); + write_reg(0x0007, 0x0173); /* 262K color and display ON */ + release_bus(); - endx = srcx + cx; - endy = y + cy; - lg = srccx - cx; - buffer += srcx + srcy * srccx; - for(; y < endy; y++, buffer += lg) - for(x=srcx; x < endx; x++) - lld_lcdWriteData(*buffer++); - lld_lcdWriteStreamStop(); - lld_lcdResetViewPort(); - } -#endif + set_backlight(g->g.Backlight); + if(g->g.Powermode != powerSleep || g->g.Powermode != powerDeepSleep) + gdisp_lld_init(); + break; -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - color_t color; + case powerSleep: + acquire_bus(); + write_reg(0x0007, 0x0000); /* display OFF */ + write_reg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ + write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + gfxSleepMicroseconds(2000); /* Dis-charge capacitor power voltage */ + write_reg(0x0010, 0x0002); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(); - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; - #endif + set_backlight(0); + break; - lld_lcdSetCursor(x, y); - lld_lcdWriteStreamStart(); + case powerDeepSleep: + acquire_bus(); + write_reg(0x0007, 0x0000); /* display OFF */ + write_reg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ + write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + gfxSleepMicroseconds(2000); /* Dis-charge capacitor power voltage */ + write_reg(0x0010, 0x0004); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(); - color = lld_lcdReadData(); - color = lld_lcdReadData(); + set_backlight(0); + break; - lld_lcdWriteStreamStop(); - - return color; - } -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - static color_t buf[((GDISP_SCREEN_HEIGHT > GDISP_SCREEN_WIDTH ) ? GDISP_SCREEN_HEIGHT : GDISP_SCREEN_WIDTH)]; - coord_t row0, row1; - unsigned i, gap, abslines; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - abslines = lines < 0 ? -lines : lines; - - if (abslines >= cy) { - abslines = cy; - gap = 0; - } else { - gap = cy - abslines; - for(i = 0; i < gap; i++) { - if(lines > 0) { - row0 = y + i + lines; - row1 = y + i; - } else { - row0 = (y - i - 1) + lines; - row1 = (y - i - 1); - } - - /* read row0 into the buffer and then write at row1*/ - lld_lcdSetViewPort(x, row0, cx, 1); - lld_lcdReadStreamStart(); - lld_lcdReadStream(buf, cx); - lld_lcdReadStreamStop(); - - lld_lcdSetViewPort(x, row1, cx, 1); - lld_lcdWriteStreamStart(); - lld_lcdWriteStream(buf, cx); - lld_lcdWriteStreamStop(); - } - } - - /* fill the remaining gap */ - lld_lcdSetViewPort(x, lines > 0 ? (y+gap) : y, cx, abslines); - lld_lcdWriteStreamStart(); - gap = cx*abslines; - for(i = 0; i < gap; i++) lld_lcdWriteData(bgcolor); - lld_lcdWriteStreamStop(); - lld_lcdResetViewPort(); - } -#endif - -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) - void gdisp_lld_control(unsigned what, void *value) { - switch(what) { - case GDISP_CONTROL_POWER: - if(GDISP.Powermode == (gdisp_powermode_t)value) + default: return; - switch((gdisp_powermode_t)value) { - case powerOff: - acquire_bus(); - lld_lcdWriteReg(0x0007, 0x0000); - lld_lcdWriteReg(0x0010, 0x0000); - lld_lcdWriteReg(0x0011, 0x0000); - lld_lcdWriteReg(0x0012, 0x0000); - lld_lcdWriteReg(0x0013, 0x0000); - release_bus(); - - gdisp_lld_backlight(0); - break; - - case powerOn: - //*************Power On sequence ******************// - acquire_bus(); - lld_lcdWriteReg(0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ - lld_lcdWriteReg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - lld_lcdWriteReg(0x0012, 0x0000); /* VREG1OUT voltage */ - lld_lcdWriteReg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ - lld_lcdDelay(2000); /* Dis-charge capacitor power voltage */ - lld_lcdWriteReg(0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ - lld_lcdWriteReg(0x0011, 0x0147); /* DC1[2:0], DC0[2:0], VC[2:0] */ - lld_lcdDelay(500); - lld_lcdWriteReg(0x0012, 0x013C); /* VREG1OUT voltage */ - lld_lcdDelay(500); - lld_lcdWriteReg(0x0013, 0x0E00); /* VDV[4:0] for VCOM amplitude */ - lld_lcdWriteReg(0x0029, 0x0009); /* VCM[4:0] for VCOMH */ - lld_lcdDelay(500); - lld_lcdWriteReg(0x0007, 0x0173); /* 262K color and display ON */ - release_bus(); - - gdisp_lld_backlight(GDISP.Backlight); - if(GDISP.Powermode != powerSleep || GDISP.Powermode != powerDeepSleep) - gdisp_lld_init(); - break; - - case powerSleep: - acquire_bus(); - lld_lcdWriteReg(0x0007, 0x0000); /* display OFF */ - lld_lcdWriteReg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - lld_lcdWriteReg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - lld_lcdWriteReg(0x0012, 0x0000); /* VREG1OUT voltage */ - lld_lcdWriteReg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ - lld_lcdDelay(2000); /* Dis-charge capacitor power voltage */ - lld_lcdWriteReg(0x0010, 0x0002); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - release_bus(); - - gdisp_lld_backlight(0); - break; - - case powerDeepSleep: - acquire_bus(); - lld_lcdWriteReg(0x0007, 0x0000); /* display OFF */ - lld_lcdWriteReg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - lld_lcdWriteReg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - lld_lcdWriteReg(0x0012, 0x0000); /* VREG1OUT voltage */ - lld_lcdWriteReg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ - lld_lcdDelay(2000); /* Dis-charge capacitor power voltage */ - lld_lcdWriteReg(0x0010, 0x0004); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - release_bus(); - - gdisp_lld_backlight(0); - break; - - default: - return; } - GDISP.Powermode = (gdisp_powermode_t)value; + g->g.Powermode = (powermode_t)g->p.ptr; return; case GDISP_CONTROL_ORIENTATION: - if(GDISP.Orientation == (gdisp_orientation_t)value) + if (g->g.Orientation == (orientation_t)g->p.ptr) return; - switch((gdisp_orientation_t)value) { - case GDISP_ROTATE_0: - acquire_bus(); - lld_lcdWriteReg(0x0001, 0x0100); - lld_lcdWriteReg(0x0003, 0x1038); - lld_lcdWriteReg(0x0060, 0x2700); - release_bus(); + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(); + write_reg(0x0001, 0x0100); + write_reg(0x0003, 0x1038); + write_reg(0x0060, 0x2700); + release_bus(); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; - case GDISP_ROTATE_90: - acquire_bus(); - lld_lcdWriteReg(0x0001, 0x0100); - lld_lcdWriteReg(0x0003, 0x1030); - lld_lcdWriteReg(0x0060, 0x2700); - release_bus(); + case GDISP_ROTATE_90: + acquire_bus(); + write_reg(0x0001, 0x0100); + write_reg(0x0003, 0x1030); + write_reg(0x0060, 0x2700); + release_bus(); - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - - case GDISP_ROTATE_180: - acquire_bus(); - lld_lcdWriteReg(0x0001, 0x0000); - lld_lcdWriteReg(0x0003, 0x1030); - lld_lcdWriteReg(0x0060, 0x2700); - release_bus(); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; + case GDISP_ROTATE_180: + acquire_bus(); + write_reg(0x0001, 0x0000); + write_reg(0x0003, 0x1030); + write_reg(0x0060, 0x2700); + release_bus(); + + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_270: + acquire_bus(); + write_reg(0x0001, 0x0000); + write_reg(0x0003, 0x1038); + write_reg(0x0060, 0xA700); + release_bus(); + + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; - case GDISP_ROTATE_270: - acquire_bus(); - lld_lcdWriteReg(0x0001, 0x0000); - lld_lcdWriteReg(0x0003, 0x1038); - lld_lcdWriteReg(0x0060, 0xA700); - release_bus(); - - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - - default: - return; + default: + return; } - - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; + g->g.Orientation = (orientation_t)value; return; - case GDISP_CONTROL_BACKLIGHT: - if((unsigned)value > 100) value = (void *)100; - gdisp_lld_backlight((unsigned)value); - GDISP.Backlight = (unsigned)value; - break; - + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight((unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; default: return; } } - #endif #endif /* GFX_USE_GDISP */ -/** @} */ - diff --git a/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_pic32mx_lcd.h b/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_pic32mx_lcd.h index 177a7cd8..faa54a3e 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_pic32mx_lcd.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_pic32mx_lcd.h @@ -20,7 +20,7 @@ #define noinline __attribute__((noinline)) #endif -static void gdisp_lld_init_board(void) { +static void init_board(void) { // RST palSetPadMode(IOPORTA, 7, PAL_MODE_OUTPUT); palClearPad(IOPORTA, 7); @@ -56,14 +56,14 @@ static void gdisp_lld_init_board(void) { #define PmpWaitBusy() do {} while (PMMODEbits.BUSY) -static noinline void gdisp_lld_reset_pin(bool_t state) { +static noinline void setpin_reset(bool_t state) { if (state) palClearPad(IOPORTA, 7); else palSetPad(IOPORTA, 7); } -static noinline void gdisp_lld_write_index(uint16_t data) { +static noinline void write_index(uint16_t data) { volatile uint16_t dummy; PmpWaitBusy(); @@ -76,18 +76,24 @@ static noinline void gdisp_lld_write_index(uint16_t data) { (void)dummy; } -static noinline void gdisp_lld_write_data(uint16_t data) { +static noinline void write_data(uint16_t data) { PMDIN = data; PmpWaitBusy(); } -static noinline uint16_t gdisp_lld_read_data(void) { +static inline void setreadmode(void) { +} + +static inline void setwritemode(void) { +} + +static noinline uint16_t read_data(void) { PmpWaitBusy(); return PMDIN; } /* if not available, just ignore the argument and return */ -static void gdisp_lld_backlight(uint8_t percentage) { +static void set_backlight(uint8_t percentage) { if (percentage) palClearPad(IOPORTD, 3); else @@ -101,6 +107,7 @@ static inline void acquire_bus(void) { static inline void release_bus(void) { /* Nothing to do here since LCD is the only device on that bus */ } + #endif /* GDISP_LLD_BOARD_H */ /** @} */ diff --git a/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h b/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h index 0d9f8364..1662385a 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h @@ -19,7 +19,7 @@ #define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ #define GDISP_RAM (*((volatile uint16_t *) 0x60100000)) /* RS = 1 */ -static inline void gdisp_lld_init_board(void) { +static inline void init_board(void) { /* FSMC setup for F1 */ rccEnableAHB(RCC_AHBENR_FSMCEN, 0); @@ -41,7 +41,7 @@ static inline void gdisp_lld_init_board(void) { FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; } -static inline void gdisp_lld_reset_pin(bool_t state) { +static inline void setpin_reset(bool_t state) { if(state) palClearPad(GPIOE, GPIOE_TFT_RST); else @@ -56,19 +56,25 @@ static inline void release_bus(void) { /* Nothing to do here since LCD is the only device on that bus */ } -static inline void gdisp_lld_write_index(uint16_t reg) { +static inline void write_index(uint16_t reg) { GDISP_REG = reg; } -static inline void gdisp_lld_write_data(uint16_t data) { +static inline void write_data(uint16_t data) { GDISP_RAM = data; } -static inline uint16_t gdisp_lld_read_data(void) { +static inline void setreadmode(void) { +} + +static inline void setwritemode(void) { +} + +static inline uint16_t read_data(void) { return GDISP_RAM; } -static inline void gdisp_lld_backlight(uint8_t percent) { +static inline void set_backlight(uint8_t percent) { if(percent == 100) palClearPad(GPIOD, GPIOD_TFT_LIGHT); else diff --git a/drivers/gdisp/ILI9320/gdisp_lld_board_template.h b/drivers/gdisp/ILI9320/gdisp_lld_board_template.h index dafaec48..201b3630 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_board_template.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_board_template.h @@ -16,11 +16,11 @@ #ifndef GDISP_LLD_BOARD_H #define GDISP_LLD_BOARD_H -static inline void gdisp_lld_init_board(void) { +static inline void init_board(void) { } -static inline void gdisp_lld_reset_pin(bool_t state) { +static inline void setpin_reset(bool_t state) { } @@ -32,19 +32,27 @@ static inline void release_bus(void) { } -static inline void gdisp_lld_write_index(uint16_t data) { +static inline void write_index(uint16_t data) { } -static inline void gdisp_lld_write_data(uint16_t data) { +static inline void write_data(uint16_t data) { } -static inline uint16_t gdisp_lld_read_data(void) { +static inline void setreadmode(void) { } -static inline uint16_t gdisp_lld_backlight(uint8_t percentage) { +static inline void setwritemode(void) { + +} + +static inline uint16_t read_data(void) { + +} + +static inline uint16_t set_backlight(uint8_t percentage) { } diff --git a/drivers/gdisp/ILI9320/gdisp_lld_config.h b/drivers/gdisp/ILI9320/gdisp_lld_config.h index 4907c6b8..7cf7457a 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_config.h @@ -23,13 +23,11 @@ /*===========================================================================*/ #define GDISP_DRIVER_NAME "ILI9320" - -#define GDISP_HARDWARE_CLEARS TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS FALSE -#define GDISP_HARDWARE_SCROLL FALSE -#define GDISP_HARDWARE_PIXELREAD TRUE -#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_DRIVER_STRUCT GDISP_ILI9320 + +#define GDISP_HARDWARE_STREAM_WRITE TRUE +#define GDISP_HARDWARE_STREAM_READ TRUE +#define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 From c132a5bb8ada70bc0a77832033ee6fd68293ceea Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 17:04:13 +1000 Subject: [PATCH 034/160] Tidy up some code so it looks more standard accross drivers --- drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 14 ++-- drivers/gdisp/SSD1289/gdisp_lld.c | 99 ++++++++++++-------------- 2 files changed, 53 insertions(+), 60 deletions(-) diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index a41ab3c9..ce0400d1 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -17,9 +17,6 @@ #if GFX_USE_GDISP -#define GDISP_LLD_DECLARATIONS -#include "gdisp/lld/gdisp_lld.h" - /** * This is for the EPSON (GE8) controller driving a Nokia6610 color LCD display. * Note that there is also a PHILIPS (GE12) controller for the same display that this code @@ -52,10 +49,6 @@ * orientation support and the streaming operations will be emulated (as described above). */ -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GDISP_SCREEN_HEIGHT @@ -65,7 +58,14 @@ #undef GDISP_SCREEN_WIDTH #endif +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" #include "gdisp_lld_board.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + #include "GE8.h" #define GDISP_SCAN_LINES 132 diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index c724e80b..7ec2b590 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -8,14 +8,11 @@ /** * @file drivers/gdisp/SSD1289/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for the SSD1289 display. - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP #define GDISP_LLD_DECLARATIONS #include "gdisp/lld/gdisp_lld.h" @@ -43,9 +40,8 @@ /*===========================================================================*/ // Some common routines and macros +#define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } #define write_reg(reg, data) { write_index(reg); write_data(data); } -#define delay(us) gfxSleepMicroseconds(us) -#define delayms(ms) gfxSleepMilliseconds(ms) static void set_viewport(GDISPDriver* g) { /* Reg 0x44 - Horizontal RAM address position @@ -107,54 +103,54 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { // Hardware reset setpin_reset(TRUE); - delayms(20); + gfxSleepMilliseconds(20); setpin_reset(FALSE); - delayms(20); + gfxSleepMilliseconds(20); // Get the bus for the following initialisation commands acquire_bus(); - write_reg(0x0000,0x0001); delay(5); - write_reg(0x0003,0xA8A4); delay(5); - write_reg(0x000C,0x0000); delay(5); - write_reg(0x000D,0x080C); delay(5); - write_reg(0x000E,0x2B00); delay(5); - write_reg(0x001E,0x00B0); delay(5); - write_reg(0x0001,0x2B3F); delay(5); - write_reg(0x0002,0x0600); delay(5); - write_reg(0x0010,0x0000); delay(5); - write_reg(0x0011,0x6070); delay(5); - write_reg(0x0005,0x0000); delay(5); - write_reg(0x0006,0x0000); delay(5); - write_reg(0x0016,0xEF1C); delay(5); - write_reg(0x0017,0x0003); delay(5); - write_reg(0x0007,0x0133); delay(5); - write_reg(0x000B,0x0000); delay(5); - write_reg(0x000F,0x0000); delay(5); - write_reg(0x0041,0x0000); delay(5); - write_reg(0x0042,0x0000); delay(5); - write_reg(0x0048,0x0000); delay(5); - write_reg(0x0049,0x013F); delay(5); - write_reg(0x004A,0x0000); delay(5); - write_reg(0x004B,0x0000); delay(5); - write_reg(0x0044,0xEF00); delay(5); - write_reg(0x0045,0x0000); delay(5); - write_reg(0x0046,0x013F); delay(5); - write_reg(0x0030,0x0707); delay(5); - write_reg(0x0031,0x0204); delay(5); - write_reg(0x0032,0x0204); delay(5); - write_reg(0x0033,0x0502); delay(5); - write_reg(0x0034,0x0507); delay(5); - write_reg(0x0035,0x0204); delay(5); - write_reg(0x0036,0x0204); delay(5); - write_reg(0x0037,0x0502); delay(5); - write_reg(0x003A,0x0302); delay(5); - write_reg(0x003B,0x0302); delay(5); - write_reg(0x0023,0x0000); delay(5); - write_reg(0x0024,0x0000); delay(5); - write_reg(0x0025,0x8000); delay(5); - write_reg(0x004f,0x0000); delay(5); - write_reg(0x004e,0x0000); delay(5); + write_reg(0x0000,0x0001); gfxSleepMicroseconds(5); + write_reg(0x0003,0xA8A4); gfxSleepMicroseconds(5); + write_reg(0x000C,0x0000); gfxSleepMicroseconds(5); + write_reg(0x000D,0x080C); gfxSleepMicroseconds(5); + write_reg(0x000E,0x2B00); gfxSleepMicroseconds(5); + write_reg(0x001E,0x00B0); gfxSleepMicroseconds(5); + write_reg(0x0001,0x2B3F); gfxSleepMicroseconds(5); + write_reg(0x0002,0x0600); gfxSleepMicroseconds(5); + write_reg(0x0010,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0011,0x6070); gfxSleepMicroseconds(5); + write_reg(0x0005,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0006,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0016,0xEF1C); gfxSleepMicroseconds(5); + write_reg(0x0017,0x0003); gfxSleepMicroseconds(5); + write_reg(0x0007,0x0133); gfxSleepMicroseconds(5); + write_reg(0x000B,0x0000); gfxSleepMicroseconds(5); + write_reg(0x000F,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0041,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0042,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0048,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0049,0x013F); gfxSleepMicroseconds(5); + write_reg(0x004A,0x0000); gfxSleepMicroseconds(5); + write_reg(0x004B,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0044,0xEF00); gfxSleepMicroseconds(5); + write_reg(0x0045,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0046,0x013F); gfxSleepMicroseconds(5); + write_reg(0x0030,0x0707); gfxSleepMicroseconds(5); + write_reg(0x0031,0x0204); gfxSleepMicroseconds(5); + write_reg(0x0032,0x0204); gfxSleepMicroseconds(5); + write_reg(0x0033,0x0502); gfxSleepMicroseconds(5); + write_reg(0x0034,0x0507); gfxSleepMicroseconds(5); + write_reg(0x0035,0x0204); gfxSleepMicroseconds(5); + write_reg(0x0036,0x0204); gfxSleepMicroseconds(5); + write_reg(0x0037,0x0502); gfxSleepMicroseconds(5); + write_reg(0x003A,0x0302); gfxSleepMicroseconds(5); + write_reg(0x003B,0x0302); gfxSleepMicroseconds(5); + write_reg(0x0023,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0024,0x0000); gfxSleepMicroseconds(5); + write_reg(0x0025,0x8000); gfxSleepMicroseconds(5); + write_reg(0x004f,0x0000); gfxSleepMicroseconds(5); + write_reg(0x004e,0x0000); gfxSleepMicroseconds(5); // Release the bus release_bus(); @@ -187,12 +183,10 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #if GDISP_HARDWARE_STREAM_READ LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { - uint16_t dummy; - acquire_bus(); set_viewport(g); setreadmode(); - dummy = read_data(); // dummy read + dummy_read(); } LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g) { return read_data(); @@ -318,4 +312,3 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif #endif /* GFX_USE_GDISP */ -/** @} */ From 7d95523946fe5bdacc6f92a2bad715f0bc492920 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 17:05:06 +1000 Subject: [PATCH 035/160] ILI9325 driver ported to streaming interface --- drivers/gdisp/ILI9320/gdisp_lld.c | 13 +- drivers/gdisp/ILI9325/gdisp_lld.c | 751 ++++++------------ .../ILI9325/gdisp_lld_board_hy_stm32_100p.h | 50 +- .../gdisp/ILI9325/gdisp_lld_board_template.h | 90 ++- drivers/gdisp/ILI9325/gdisp_lld_config.h | 12 +- 5 files changed, 393 insertions(+), 523 deletions(-) diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index 8dc529dd..d8bc411a 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -14,13 +14,6 @@ #if GFX_USE_GDISP -#define GDISP_LLD_DECLARATIONS -#include "gdisp/lld/gdisp_lld.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - /* This controller is only ever used with a 240 x 320 display */ #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." @@ -31,8 +24,14 @@ #undef GDISP_SCREEN_WIDTH #endif +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" #include "gdisp_lld_board.h" +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + #ifndef GDISP_SCREEN_HEIGHT #define GDISP_SCREEN_HEIGHT 320 #endif diff --git a/drivers/gdisp/ILI9325/gdisp_lld.c b/drivers/gdisp/ILI9325/gdisp_lld.c index d47adb3a..a30bea44 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld.c +++ b/drivers/gdisp/ILI9325/gdisp_lld.c @@ -17,15 +17,6 @@ #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" - -#include "gdisp_lld_board.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - /* This controller is only ever used with a 240 x 320 display */ #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." @@ -36,16 +27,27 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_SCREEN_WIDTH 240 -#define GDISP_SCREEN_HEIGHT 320 - -#define GDISP_INITIAL_CONTRAST 50 -#define GDISP_INITIAL_BACKLIGHT 100 +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" +#include "gdisp_lld_board.h" /*===========================================================================*/ -/* Driver exported variables. */ +/* Driver local definitions. */ /*===========================================================================*/ +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 320 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif + /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ @@ -54,524 +56,281 @@ uint32_t DISPLAY_CODE; /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -static inline void lld_lcdDelay(uint16_t us) { - gfxSleepMicroseconds(us); + +// Some common routines and macros +#define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } +#define write_reg(reg, data) { write_index(reg); write_data(data); } + +static void set_viewport(GDISPDriver* g) { + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + write_reg(0x0050, x); + write_reg(0x0051, x + cx - 1); + write_reg(0x0052, y); + write_reg(0x0053, y + cy - 1); + write_reg(0x0020, x); + write_reg(0x0021, y); + break; + + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + write_reg(0x0050, y); + write_reg(0x0051, y + cy - 1); + write_reg(0x0052, x); + write_reg(0x0053, x + cx - 1); + write_reg(0x0020, y); + write_reg(0x0021, x); + break; + } + write_reg(0x0022, color); } -static inline void lld_lcdWriteIndex(uint16_t index) { - gdisp_lld_write_index(index); -} - -static inline void lld_lcdWriteData(uint16_t data) { - gdisp_lld_write_data(data); -} - -static inline void lld_lcdWriteReg(uint16_t lcdReg, uint16_t lcdRegValue) { - gdisp_lld_write_index(lcdReg); - gdisp_lld_write_data(lcdRegValue); -} - -static inline uint16_t lld_lcdReadData(void) { - return gdisp_lld_read_data(); -} - -static inline uint16_t lld_lcdReadReg(uint16_t lcdReg) { - volatile uint16_t dummy; - - gdisp_lld_write_index(lcdReg); - dummy = lld_lcdReadData(); - (void)dummy; - - return lld_lcdReadData(); -} - -static inline void lld_lcdWriteStreamStart(void) { - lld_lcdWriteIndex(0x0022); -} - -static inline void lld_lcdWriteStreamStop(void) { - -} - -static inline void lld_lcdWriteStream(uint16_t *buffer, uint16_t size) { - uint16_t i; - - for(i = 0; i < size; i++) - lld_lcdWriteData(buffer[i]); -} - -static inline void lld_lcdReadStreamStart(void) { - lld_lcdWriteIndex(0x0022); -} - -static inline void lld_lcdReadStreamStop(void) { - -} - -static inline void lld_lcdReadStream(uint16_t *buffer, size_t size) { - uint16_t i; - volatile uint16_t dummy; - - dummy = lld_lcdReadData(); - (void)dummy; - - for(i = 0; i < size; i++) - buffer[i] = lld_lcdReadData(); -} - -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { /* Initialise your display */ - gdisp_lld_init_board(); + init_board(); /* Hardware reset */ - gdisp_lld_reset_pin(TRUE); - lld_lcdDelay(1000); - gdisp_lld_reset_pin(FALSE); - lld_lcdDelay(1000); + setpin_reset(TRUE); + gfxSleepMicroseconds(1000); + setpin_reset(FALSE); + gfxSleepMicroseconds(1000); - DISPLAY_CODE = lld_lcdReadReg(0); + acquire_bus(); + write_index(0); // Get controller version + dummy_read(); + DISPLAY_CODE = read_data(); // chinese code starts here - lld_lcdWriteReg(0x0000,0x0001); - lld_lcdDelay(10); + write_reg(0x0000,0x0001); + gfxSleepMilliseconds(10); - lld_lcdWriteReg(0x0015,0x0030); - lld_lcdWriteReg(0x0011,0x0040); - lld_lcdWriteReg(0x0010,0x1628); - lld_lcdWriteReg(0x0012,0x0000); - lld_lcdWriteReg(0x0013,0x104d); - lld_lcdDelay(10); - lld_lcdWriteReg(0x0012,0x0010); - lld_lcdDelay(10); - lld_lcdWriteReg(0x0010,0x2620); - lld_lcdWriteReg(0x0013,0x344d); //304d - lld_lcdDelay(10); + write_reg(0x0015,0x0030); + write_reg(0x0011,0x0040); + write_reg(0x0010,0x1628); + write_reg(0x0012,0x0000); + write_reg(0x0013,0x104d); + gfxSleepMilliseconds(10); + write_reg(0x0012,0x0010); + gfxSleepMilliseconds(10); + write_reg(0x0010,0x2620); + write_reg(0x0013,0x344d); //304d + gfxSleepMilliseconds(10); - lld_lcdWriteReg(0x0001,0x0100); - lld_lcdWriteReg(0x0002,0x0300); - lld_lcdWriteReg(0x0003,0x1038);//0x1030 - lld_lcdWriteReg(0x0008,0x0604); - lld_lcdWriteReg(0x0009,0x0000); - lld_lcdWriteReg(0x000A,0x0008); + write_reg(0x0001,0x0100); + write_reg(0x0002,0x0300); + write_reg(0x0003,0x1038);//0x1030 + write_reg(0x0008,0x0604); + write_reg(0x0009,0x0000); + write_reg(0x000A,0x0008); - lld_lcdWriteReg(0x0041,0x0002); - lld_lcdWriteReg(0x0060,0x2700); - lld_lcdWriteReg(0x0061,0x0001); - lld_lcdWriteReg(0x0090,0x0182); - lld_lcdWriteReg(0x0093,0x0001); - lld_lcdWriteReg(0x00a3,0x0010); - lld_lcdDelay(10); + write_reg(0x0041,0x0002); + write_reg(0x0060,0x2700); + write_reg(0x0061,0x0001); + write_reg(0x0090,0x0182); + write_reg(0x0093,0x0001); + write_reg(0x00a3,0x0010); + gfxSleepMilliseconds(10); //################# void Gamma_Set(void) ####################// - lld_lcdWriteReg(0x30,0x0000); - lld_lcdWriteReg(0x31,0x0502); - lld_lcdWriteReg(0x32,0x0307); - lld_lcdWriteReg(0x33,0x0305); - lld_lcdWriteReg(0x34,0x0004); - lld_lcdWriteReg(0x35,0x0402); - lld_lcdWriteReg(0x36,0x0707); - lld_lcdWriteReg(0x37,0x0503); - lld_lcdWriteReg(0x38,0x1505); - lld_lcdWriteReg(0x39,0x1505); - lld_lcdDelay(10); + write_reg(0x30,0x0000); + write_reg(0x31,0x0502); + write_reg(0x32,0x0307); + write_reg(0x33,0x0305); + write_reg(0x34,0x0004); + write_reg(0x35,0x0402); + write_reg(0x36,0x0707); + write_reg(0x37,0x0503); + write_reg(0x38,0x1505); + write_reg(0x39,0x1505); + gfxSleepMilliseconds(10); //################## void Display_ON(void) ####################// - lld_lcdWriteReg(0x0007,0x0001); - lld_lcdDelay(10); - lld_lcdWriteReg(0x0007,0x0021); - lld_lcdWriteReg(0x0007,0x0023); - lld_lcdDelay(10); - lld_lcdWriteReg(0x0007,0x0033); - lld_lcdDelay(10); - lld_lcdWriteReg(0x0007,0x0133); + write_reg(0x0007,0x0001); + gfxSleepMilliseconds(10); + write_reg(0x0007,0x0021); + write_reg(0x0007,0x0023); + gfxSleepMilliseconds(10); + write_reg(0x0007,0x0033); + gfxSleepMilliseconds(10); + write_reg(0x0007,0x0133); // chinese code ends here // Turn on the backlight - gdisp_lld_backlight(GDISP_INITIAL_BACKLIGHT); + set_backlight(GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = GDISP_INITIAL_BACKLIGHT; - GDISP.Contrast = GDISP_INITIAL_CONTRAST; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -static void lld_lcdSetCursor(uint16_t x, uint16_t y) { - - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - lld_lcdWriteReg(0x0020, x); - lld_lcdWriteReg(0x0021, y); - break; - - case GDISP_ROTATE_90: - lld_lcdWriteReg(0x0020, y); - lld_lcdWriteReg(0x0021, x); - break; - - case GDISP_ROTATE_180: - lld_lcdWriteReg(0x0020, x); - lld_lcdWriteReg(0x0021, y); - break; - - case GDISP_ROTATE_270: - lld_lcdWriteReg(0x0020, y); - lld_lcdWriteReg(0x0021, x); - break; +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { + acquire_bus(); + set_viewport(g); } -} - -static void lld_lcdSetViewPort(uint16_t x, uint16_t y, uint16_t cx, uint16_t cy) { - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - lld_lcdWriteReg(0x0050, x); - lld_lcdWriteReg(0x0051, x + cx - 1); - lld_lcdWriteReg(0x0052, y); - lld_lcdWriteReg(0x0053, y + cy - 1); - break; - - case GDISP_ROTATE_90: - lld_lcdWriteReg(0x0050, y); - lld_lcdWriteReg(0x0051, y + cy - 1); - lld_lcdWriteReg(0x0052, x); - lld_lcdWriteReg(0x0053, x + cx - 1); - break; - - case GDISP_ROTATE_180: - lld_lcdWriteReg(0x0050, x); - lld_lcdWriteReg(0x0051, x + cx - 1); - lld_lcdWriteReg(0x0052, y); - lld_lcdWriteReg(0x0053, y + cy - 1); - break; - - case GDISP_ROTATE_270: - lld_lcdWriteReg(0x0050, y); - lld_lcdWriteReg(0x0051, y + cy - 1); - lld_lcdWriteReg(0x0052, x); - lld_lcdWriteReg(0x0053, x + cx - 1); - break; - + LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { + write_data(g->p.color); } - - lld_lcdSetCursor(x, y); -} - -static inline void lld_lcdResetViewPort(void) { - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - case GDISP_ROTATE_180: - lld_lcdSetViewPort(0, 0, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT); - break; - case GDISP_ROTATE_90: - case GDISP_ROTATE_270: - lld_lcdSetViewPort(0, 0, GDISP_SCREEN_HEIGHT, GDISP_SCREEN_WIDTH); - break; - } -} - -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - lld_lcdSetCursor(x, y); - lld_lcdWriteReg(0x0022, color); -} - -#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) - void gdisp_lld_clear(color_t color) { - unsigned i; - - lld_lcdSetCursor(0, 0); - lld_lcdWriteStreamStart(); - - for(i = 0; i < GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT; i++) - lld_lcdWriteData(color); - - lld_lcdWriteStreamStop(); + LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { + release_bus(); } #endif -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - unsigned i, area; - - area = cx*cy; - lld_lcdSetViewPort(x, y, cx, cy); - lld_lcdWriteStreamStart(); - for(i = 0; i < area; i++) - lld_lcdWriteData(color); - lld_lcdWriteStreamStop(); - lld_lcdResetViewPort(); +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { + acquire_bus(); + set_viewport(g); + setreadmode(); + dummy_read(); + } + LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g) { + return read_data(); + } + LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g) { + setwritemode(); + release_bus(); } #endif -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - coord_t endx, endy; - unsigned lg; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - lld_lcdSetViewPort(x, y, cx, cy); - lld_lcdWriteStreamStart(); - - endx = srcx + cx; - endy = y + cy; - lg = srccx - cx; - buffer += srcx + srcy * srccx; - for(; y < endy; y++, buffer += lg) - for(x=srcx; x < endx; x++) - lld_lcdWriteData(*buffer++); - lld_lcdWriteStreamStop(); - lld_lcdResetViewPort(); - } -#endif - -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - color_t color; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; - #endif - - lld_lcdSetCursor(x, y); - lld_lcdWriteStreamStart(); - - color = lld_lcdReadData(); - color = lld_lcdReadData(); - - lld_lcdWriteStreamStop(); - - return color; - } -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - static color_t buf[((GDISP_SCREEN_HEIGHT > GDISP_SCREEN_WIDTH ) ? GDISP_SCREEN_HEIGHT : GDISP_SCREEN_WIDTH)]; - coord_t row0, row1; - unsigned i, gap, abslines; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - abslines = lines < 0 ? -lines : lines; - - if (abslines >= cy) { - abslines = cy; - gap = 0; - } else { - gap = cy - abslines; - for(i = 0; i < gap; i++) { - if(lines > 0) { - row0 = y + i + lines; - row1 = y + i; - } else { - row0 = (y - i - 1) + lines; - row1 = (y - i - 1); - } - - /* read row0 into the buffer and then write at row1*/ - lld_lcdSetViewPort(x, row0, cx, 1); - lld_lcdReadStreamStart(); - lld_lcdReadStream(buf, cx); - lld_lcdReadStreamStop(); - - lld_lcdSetViewPort(x, row1, cx, 1); - lld_lcdWriteStreamStart(); - lld_lcdWriteStream(buf, cx); - lld_lcdWriteStreamStop(); - } - } - - /* fill the remaining gap */ - lld_lcdSetViewPort(x, lines > 0 ? (y+gap) : y, cx, abslines); - lld_lcdWriteStreamStart(); - gap = cx*abslines; - for(i = 0; i < gap; i++) lld_lcdWriteData(bgcolor); - lld_lcdWriteStreamStop(); - lld_lcdResetViewPort(); - } -#endif - -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) - void gdisp_lld_control(unsigned what, void *value) { - switch(what) { - case GDISP_CONTROL_POWER: - if(GDISP.Powermode == (gdisp_powermode_t)value) - return; - switch((gdisp_powermode_t)value) { - case powerOff: - acquire_bus(); - lld_lcdWriteReg(0x0007, 0x0000); - lld_lcdWriteReg(0x0010, 0x0000); - lld_lcdWriteReg(0x0011, 0x0000); - lld_lcdWriteReg(0x0012, 0x0000); - lld_lcdWriteReg(0x0013, 0x0000); - release_bus(); - - gdisp_lld_backlight(0); - break; - - case powerOn: - //*************Power On sequence ******************// - acquire_bus(); - lld_lcdWriteReg(0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ - lld_lcdWriteReg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - lld_lcdWriteReg(0x0012, 0x0000); /* VREG1OUT voltage */ - lld_lcdWriteReg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ - lld_lcdDelay(2000); /* Dis-charge capacitor power voltage */ - lld_lcdWriteReg(0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ - lld_lcdWriteReg(0x0011, 0x0147); /* DC1[2:0], DC0[2:0], VC[2:0] */ - lld_lcdDelay(500); - lld_lcdWriteReg(0x0012, 0x013C); /* VREG1OUT voltage */ - lld_lcdDelay(500); - lld_lcdWriteReg(0x0013, 0x0E00); /* VDV[4:0] for VCOM amplitude */ - lld_lcdWriteReg(0x0029, 0x0009); /* VCM[4:0] for VCOMH */ - lld_lcdDelay(500); - lld_lcdWriteReg(0x0007, 0x0173); /* 262K color and display ON */ - release_bus(); - - gdisp_lld_backlight(GDISP.Backlight); - if(GDISP.Powermode != powerSleep || GDISP.Powermode != powerDeepSleep) - gdisp_lld_init(); - break; - - case powerSleep: - acquire_bus(); - lld_lcdWriteReg(0x0007, 0x0000); /* display OFF */ - lld_lcdWriteReg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - lld_lcdWriteReg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - lld_lcdWriteReg(0x0012, 0x0000); /* VREG1OUT voltage */ - lld_lcdWriteReg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ - lld_lcdDelay(2000); /* Dis-charge capacitor power voltage */ - lld_lcdWriteReg(0x0010, 0x0002); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - release_bus(); - - gdisp_lld_backlight(0); - break; - - case powerDeepSleep: - acquire_bus(); - lld_lcdWriteReg(0x0007, 0x0000); /* display OFF */ - lld_lcdWriteReg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - lld_lcdWriteReg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - lld_lcdWriteReg(0x0012, 0x0000); /* VREG1OUT voltage */ - lld_lcdWriteReg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ - lld_lcdDelay(2000); /* Dis-charge capacitor power voltage */ - lld_lcdWriteReg(0x0010, 0x0004); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - release_bus(); - - gdisp_lld_backlight(0); - break; - - default: - return; - } - GDISP.Powermode = (gdisp_powermode_t)value; +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) return; - - case GDISP_CONTROL_ORIENTATION: - if(GDISP.Orientation == (gdisp_orientation_t)value) - return; - switch((gdisp_orientation_t)value) { - case GDISP_ROTATE_0: - acquire_bus(); - lld_lcdWriteReg(0x0001, 0x0100); - lld_lcdWriteReg(0x0003, 0x1038); - lld_lcdWriteReg(0x0060, 0x2700); - release_bus(); - - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - - case GDISP_ROTATE_90: - acquire_bus(); - lld_lcdWriteReg(0x0001, 0x0000); - lld_lcdWriteReg(0x0003, 0x1030); - lld_lcdWriteReg(0x0060, 0x2700); - release_bus(); - - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - - case GDISP_ROTATE_180: - acquire_bus(); - lld_lcdWriteReg(0x0001, 0x0000); - lld_lcdWriteReg(0x0003, 0x1038); - lld_lcdWriteReg(0x0060, 0xa700); - release_bus(); - - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - - case GDISP_ROTATE_270: - acquire_bus(); - lld_lcdWriteReg(0x0001, 0x0100); - lld_lcdWriteReg(0x0003, 0x1030); - lld_lcdWriteReg(0x0060, 0xA700); - release_bus(); - - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - - default: - return; - } - - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; - return; - - case GDISP_CONTROL_BACKLIGHT: - if((unsigned)value > 100) value = (void *)100; - gdisp_lld_backlight((unsigned)value); - GDISP.Backlight = (unsigned)value; + switch((powermode_t)g->p.ptr) { + case powerOff: + acquire_bus(); + write_reg(0x0007, 0x0000); + write_reg(0x0010, 0x0000); + write_reg(0x0011, 0x0000); + write_reg(0x0012, 0x0000); + write_reg(0x0013, 0x0000); + release_bus(); + set_backlight(0); break; - + + case powerOn: + //*************Power On sequence ******************// + acquire_bus(); + write_reg(0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ + write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + gfxSleepMilliseconds(200); /* Dis-charge capacitor power voltage */ + write_reg(0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(0x0011, 0x0147); /* DC1[2:0], DC0[2:0], VC[2:0] */ + gfxSleepMilliseconds(50); + write_reg(0x0012, 0x013C); /* VREG1OUT voltage */ + gfxSleepMilliseconds(50); + write_reg(0x0013, 0x0E00); /* VDV[4:0] for VCOM amplitude */ + write_reg(0x0029, 0x0009); /* VCM[4:0] for VCOMH */ + gfxSleepMilliseconds(50); + write_reg(0x0007, 0x0173); /* 262K color and display ON */ + release_bus(); + set_backlight(g->g.Backlight); + break; + + case powerSleep: + acquire_bus(); + write_reg(0x0007, 0x0000); /* display OFF */ + write_reg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ + write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + gfxSleepMilliseconds(200); /* Dis-charge capacitor power voltage */ + write_reg(0x0010, 0x0002); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(); + gdisp_lld_backlight(0); + break; + + case powerDeepSleep: + acquire_bus(); + write_reg(0x0007, 0x0000); /* display OFF */ + write_reg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ + write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + gfxSleepMilliseconds(200); /* Dis-charge capacitor power voltage */ + write_reg(0x0010, 0x0004); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(); + gdisp_lld_backlight(0); + break; + default: return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(); + write_reg(0x0001, 0x0100); + write_reg(0x0003, 0x1038); + write_reg(0x0060, 0x2700); + release_bus(); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_90: + acquire_bus(); + write_reg(0x0001, 0x0000); + write_reg(0x0003, 0x1030); + write_reg(0x0060, 0x2700); + release_bus(); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + + case GDISP_ROTATE_180: + acquire_bus(); + write_reg(0x0001, 0x0000); + write_reg(0x0003, 0x1038); + write_reg(0x0060, 0xa700); + release_bus(); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_270: + acquire_bus(); + write_reg(0x0001, 0x0100); + write_reg(0x0003, 0x1030); + write_reg(0x0060, 0xA700); + release_bus(); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + + default: + return; + } + + g->g.Orientation = (orientation_t)value; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight((unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + default: + return; } } diff --git a/drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h b/drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h index 3c2cc78b..3e2c269b 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h +++ b/drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h @@ -32,7 +32,7 @@ #define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ #define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ -static inline void gdisp_lld_init_board(void) { +static inline void init_board(void) { /* FSMC setup for F1 */ rccEnableAHB(RCC_AHBENR_FSMCEN, 0); @@ -55,27 +55,63 @@ static inline void gdisp_lld_init_board(void) { } -static inline void gdisp_lld_reset_pin(bool_t state) { +static inline void setpin_reset(bool_t state) { if(state) palClearPad(GPIOE, GPIOE_TFT_RST); else palSetPad(GPIOE, GPIOE_TFT_RST); } -static inline void gdisp_lld_write_index(uint16_t reg) { +static inline void write_index(uint16_t reg) { GDISP_REG = reg; } -static inline void gdisp_lld_write_data(uint16_t data) { +static inline void write_data(uint16_t data) { GDISP_RAM = data; } -static inline uint16_t gdisp_lld_read_data(void) { +static inline uint16_t read_data(void) { return GDISP_RAM; } -static inline void gdisp_lld_backlight(uint8_t percent) { - percent=percent; // avoid a warning +static inline void set_backlight(uint8_t percent) { + (void)percent; +} + +/** + * @brief Take exclusive control of the bus + * + * @notapi + */ +static inline void acquire_bus(void) { + +} + +/** + * @brief Release exclusive control of the bus + * + * @notapi + */ +static inline void release_bus(void) { + +} + +/** + * @brief Set the bus in read mode + * + * @notapi + */ +static inline void setreadmode(void) { + +} + +/** + * @brief Set the bus back into write mode + * + * @notapi + */ +static inline void setwritemode(void) { + } #endif /* GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/ILI9325/gdisp_lld_board_template.h b/drivers/gdisp/ILI9325/gdisp_lld_board_template.h index 2dd346a3..c07b4ba1 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld_board_template.h +++ b/drivers/gdisp/ILI9325/gdisp_lld_board_template.h @@ -16,27 +16,105 @@ #ifndef GDISP_LLD_BOARD_H #define GDISP_LLD_BOARD_H -static inline void gdisp_lld_init_board(void) { +/** + * @brief Initialise the board for the display. + * + * @notapi + */ +static inline void init_board(void) { } -static inline void gdisp_lld_reset_pin(bool_t state) { +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(bool_t state) { } -static inline void gdisp_lld_write_index(uint16_t data) { +/** + * @brief Set the lcd back-light level. + * + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(uint8_t percent) { } -static inline void gdisp_lld_write_data(uint16_t data) { +/** + * @brief Take exclusive control of the bus + * + * @notapi + */ +static inline void acquire_bus(void) { } -static inline uint16_t gdisp_lld_read_data(void) { +/** + * @brief Release exclusive control of the bus + * + * @notapi + */ +static inline void release_bus(void) { } -static inline uint16_t gdisp_lld_backlight(uint8_t percentage) { +/** + * @brief Send data to the index register. + * + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(uint16_t index) { + +} + +/** + * @brief Send data to the lcd. + * + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(uint16_t data) { + +} + +/** + * @brief Set the bus in read mode + * + * @notapi + */ +static inline void setreadmode(void) { + +} + +/** + * @brief Set the bus back into write mode + * + * @notapi + */ +static inline void setwritemode(void) { + +} + +/** + * @brief Read data from the lcd. + * + * @return The data from the lcd + * @note The chip select may need to be asserted/de-asserted + * around the actual spi read + * + * @notapi + */ +static inline uint16_t read_data(void) { } diff --git a/drivers/gdisp/ILI9325/gdisp_lld_config.h b/drivers/gdisp/ILI9325/gdisp_lld_config.h index ac07173c..572b8361 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9325/gdisp_lld_config.h @@ -23,13 +23,11 @@ /*===========================================================================*/ #define GDISP_DRIVER_NAME "ILI9325" - -#define GDISP_HARDWARE_CLEARS TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS FALSE -#define GDISP_HARDWARE_SCROLL FALSE -#define GDISP_HARDWARE_PIXELREAD TRUE -#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_DRIVER_STRUCT GDISP_ILI9325 + +#define GDISP_HARDWARE_STREAM_WRITE TRUE +#define GDISP_HARDWARE_STREAM_READ TRUE +#define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 From 9413f04672b80baec6781b4f2058cdf6e167cd55 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 30 Sep 2013 17:31:58 +1000 Subject: [PATCH 036/160] Driver ILI9481 ported to streaming driver --- drivers/gdisp/ILI9481/gdisp_lld.c | 459 ++++-------------- .../gdisp_lld_board_firebullstm32f103.h | 29 +- .../gdisp/ILI9481/gdisp_lld_board_template.h | 20 +- drivers/gdisp/ILI9481/gdisp_lld_config.h | 8 +- drivers/gdisp/SSD1289/gdisp_lld.c | 3 + 5 files changed, 133 insertions(+), 386 deletions(-) diff --git a/drivers/gdisp/ILI9481/gdisp_lld.c b/drivers/gdisp/ILI9481/gdisp_lld.c index cb407dce..a70b7c03 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld.c +++ b/drivers/gdisp/ILI9481/gdisp_lld.c @@ -9,21 +9,11 @@ * @file drivers/gdisp/ILI9481/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for * the ILI9481 and compatible HVGA display - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ - -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ +#if GFX_USE_GDISP #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." @@ -34,55 +24,40 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_SCREEN_HEIGHT 480 -#define GDISP_SCREEN_WIDTH 320 +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" +#include "gdisp_lld_board.h" -#define GDISP_INITIAL_CONTRAST 50 -#define GDISP_INITIAL_BACKLIGHT 100 +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 480 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 320 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -#include "gdisp_lld_board.h" - // Some common routines and macros -#define write_reg(reg, data) { write_index(reg); write_data(data); } -#define stream_start() write_index(0x2C); -#define stream_stop() -#define delay(us) gfxSleepMicroseconds(us) -#define delayms(ms) gfxSleepMilliseconds(ms) +#define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } +#define write_reg(reg, data) { write_index(reg); write_data(data); } +#define write_reg2x16(reg, data1, data2) { write_index(reg); write_data((data1)>>8); write_data((uint8_t)(data1)); write_data((data2)>>8); write_data((uint8_t)(data2));} -static inline void set_cursor(coord_t x, coord_t y) { - write_index(0x2A); - write_data((x >> 8)); - write_data((uint8_t) x); - write_data((x) >> 8); - write_data((uint8_t) (x)); - - write_index(0x2B); - write_data((y >> 8)); - write_data((uint8_t) y); - write_data((y) >> 8); - write_data((uint8_t) (y)); -} - -static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { - write_index(0x2A); - write_data((x >> 8)); - write_data((uint8_t) x); - write_data((x + cx - 1) >> 8); - write_data((uint8_t) (x + cx - 1)); - - write_index(0x2B); - write_data((y >> 8)); - write_data((uint8_t) y); - write_data((y + cy - 1) >> 8); - write_data((uint8_t) (y + cy - 1)); -} - -static inline void reset_viewport(void) { - set_viewport(0, 0, GDISP.Width, GDISP.Height); +static void set_viewport(GDISPDriver* g) { + write_reg2x16(0x2A, g->p.x, g->p.x + g->p.cx - 1); + write_reg2x16(0x2B, g->p.y, g->p.y + g->p.cy - 1); + write_index(0x2C); } /*===========================================================================*/ @@ -93,33 +68,21 @@ static inline void reset_viewport(void) { /* Driver exported functions. */ /*===========================================================================*/ -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ - -/** - * @brief Low level GDISP driver initialization. - * - * @notapi - */ -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { /* Initialise your display */ init_board(); /* Hardware reset */ setpin_reset(TRUE); - delayms(20); + gfxSleepMilliseconds(20); setpin_reset(FALSE); - delayms(20); + gfxSleepMilliseconds(20); /* Get the bus for the following initialisation commands */ acquire_bus(); /* Enable Access to all Manufacturer commands (0xB0 and higher opcodes) */ - write_index(0xB0); - write_data(0x00); + write_reg(0xB0, 0x00); /* Frame Memory Access and Interface Setting */ write_index(0xB3); @@ -131,8 +94,7 @@ bool_t gdisp_lld_init(void) { /* Display Mode and Frame Memory Write Mode Setting (B4h) */ /* Use internal clock for synchronization */ /* Use DBI interface (only DB0-17, no HSYNC, VSYNC or CLK) */ - write_index(0xB4); - write_data(0x00); + write_reg(0xB4, 0x00); /* Internal Backlight Control */ /* write_index(0xB9); /*PWM Settings for Brightness Control */ @@ -167,8 +129,7 @@ bool_t gdisp_lld_init(void) { write_data(0x01); /* Interface Setting */ - write_index(0xC6); - write_data(0x02); + write_reg(0xC6, 0x02); /* Gamma Setting - should be changed if using a different panel */ write_index(0xC8); @@ -184,13 +145,11 @@ bool_t gdisp_lld_init(void) { write_data(0x60); /*0x23 */ /* Address Mode setting */ - write_index(0x36); - write_data(0x00); + write_reg(0x36, 0x00); /* Set Pixel Format = 16 bits per pixel */ /* The driver supports upto 24 bits per pixel, with dither */ - write_index(0x3A); - write_data(0x55); + write_reg(0x3A, 0x55); /* Exit Idle Mode */ write_index(0x38); @@ -216,11 +175,11 @@ bool_t gdisp_lld_init(void) { /* Exit Sleep Mode */ write_index(0x11); - delay(150); + gfxSleepMilliseconds(150); /* Display ON */ write_index(0x29); - delay(30); + gfxSleepMilliseconds(30); /* Release the bus */ release_bus(); @@ -228,297 +187,62 @@ bool_t gdisp_lld_init(void) { /* Turn on the back-light */ set_backlight(GDISP_INITIAL_BACKLIGHT); - /* Initialise the GDISP structure */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = GDISP_INITIAL_BACKLIGHT; - GDISP.Contrast = GDISP_INITIAL_CONTRAST; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - acquire_bus(); - - set_cursor(x, y); - write_reg(0x002c, color); - - release_bus(); -} - -/* ---- Optional Routines ---- */ -/* - All the below routines are optional. - Defining them will increase speed but everything - will work if they are not defined. - If you are not using a routine - turn it off using - the appropriate GDISP_HARDWARE_XXXX macro. - Don't bother coding for obvious similar routines if - there is no performance penalty as the emulation software - makes a good job of using similar routines. - eg. If gfillarea() is defined there is little - point in defining clear() unless the - performance bonus is significant. - For good performance it is suggested to implement - fillarea() and blitarea(). -*/ - -#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) - /** - * @brief Clear the display. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] color The color of the pixel - * - * @notapi - */ - void gdisp_lld_clear(color_t color) { - unsigned i; - +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { acquire_bus(); - reset_viewport(); - stream_start(); - for(i = 0; i < GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT; i++) - write_data(color); - stream_stop(); + set_viewport(g); + } + LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { + write_data(g->p.color); + } + LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { release_bus(); } #endif -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - unsigned i, area; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - area = cx*cy; - +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { acquire_bus(); - - set_viewport(x, y, cx, cy); - - stream_start(); - for(i = 0; i < area; i++) - write_data(color); - stream_stop(); - + set_viewport(g); + setreadmode(); + dummy_read(); + } + LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g) { + return read_data(); + } + LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g) { + setwritemode(); release_bus(); } #endif -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a bitmap. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - coord_t endx, endy; - unsigned lg; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - acquire_bus(); - set_viewport(x, y, cx, cy); - stream_start(); - - endx = srcx + cx; - endy = y + cy; - lg = srccx - cx; - buffer += srcx + srcy * srccx; - for(; y < endy; y++, buffer += lg) - for(x=srcx; x < endx; x++) - write_data(*buffer++); - stream_stop(); - release_bus(); - } -#endif - -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) - /** - * @brief Get the color of a particular pixel. - * @note Optional. - * @note If x,y is off the screen, the result is undefined. - * - * @param[in] x, y The pixel to be read - * - * @notapi - */ - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - color_t color; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; - #endif - - acquire_bus(); - set_cursor(x, y); - stream_start(); - color = read_data(); // dummy read - color = read_data(); - stream_stop(); - release_bus(); - - return color; - } -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @note Optional. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - static color_t buf[((GDISP_SCREEN_HEIGHT > GDISP_SCREEN_WIDTH ) ? GDISP_SCREEN_HEIGHT : GDISP_SCREEN_WIDTH)]; - coord_t row0, row1; - unsigned i, gap, abslines, j; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - abslines = lines < 0 ? -lines : lines; - - acquire_bus(); - if ((coord_t)abslines >= cy) { - abslines = cy; - gap = 0; - } else { - gap = cy - abslines; - for(i = 0; i < gap; i++) { - if(lines > 0) { - row0 = y + i + lines; - row1 = y + i; - } else { - row0 = (y - i - 1) + lines; - row1 = (y - i - 1); - } - - /* read row0 into the buffer and then write at row1*/ - set_viewport(x, row0, cx, 1); - stream_start(); - j = read_data(); // dummy read - for (j = 0; (coord_t)j < cx; j++) - buf[j] = read_data(); - stream_stop(); - - set_viewport(x, row1, cx, 1); - stream_start(); - for (j = 0; (coord_t)j < cx; j++) - write_data(buf[j]); - stream_stop(); - } - } - - /* fill the remaining gap */ - set_viewport(x, lines > 0 ? (y+(coord_t)gap) : y, cx, abslines); - stream_start(); - gap = cx*abslines; - for(i = 0; i < gap; i++) write_data(bgcolor); - stream_stop(); - release_bus(); - } -#endif - -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. - * GDISP_CONTROL_LLD - Low level driver control constants start at - * this value. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { - switch(what) { +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + switch(g->p.x) { case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) + if (g->g.Powermode == (powermode_t)g->p.ptr) return; - switch((gdisp_powermode_t)value) { + switch((powermode_t)g->p.ptr) { case powerOff: - acquire_bus(); - write_reg(0x0010, 0x0001); /* enter sleep mode */ - release_bus(); + acquire_bus(); + write_reg(0x0010, 0x0001); /* enter sleep mode */ + release_bus(); break; case powerOn: acquire_bus(); write_reg(0x0010, 0x0000); /* leave sleep mode */ release_bus(); - if (GDISP.Powermode != powerSleep) + if (g->g.Powermode != powerSleep) gdisp_lld_init(); break; case powerSleep: @@ -529,12 +253,13 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { default: return; } - GDISP.Powermode = (gdisp_powermode_t)value; + g->g.Powermode = (powermode_t)g->p.ptr; return; + case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) + if (g->g.Orientation == (orientation_t)g->p.ptr) return; - switch((gdisp_orientation_t)value) { + switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: acquire_bus(); @@ -542,8 +267,8 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { write_reg(0x36, 0x00); /* X and Y axes non-inverted */ release_bus(); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: acquire_bus(); @@ -552,8 +277,8 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { write_reg(0x36, 0x20); /* Invert X and Y axes */ release_bus(); - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: acquire_bus(); @@ -562,8 +287,8 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { write_reg(0x36, 0x00); /* X and Y axes non-inverted */ release_bus(); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: acquire_bus(); @@ -572,24 +297,18 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { write_reg(0x36, 0x20); /* Invert X and Y axes */ release_bus(); - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; break; default: return; } - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; + g->g.Orientation = (orientation_t)value; return; -/* - case GDISP_CONTROL_BACKLIGHT: - case GDISP_CONTROL_CONTRAST: -*/ + //case GDISP_CONTROL_BACKLIGHT: + //case GDISP_CONTROL_CONTRAST: + default: + return; } } #endif diff --git a/drivers/gdisp/ILI9481/gdisp_lld_board_firebullstm32f103.h b/drivers/gdisp/ILI9481/gdisp_lld_board_firebullstm32f103.h index cef9911d..7270cdaf 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld_board_firebullstm32f103.h +++ b/drivers/gdisp/ILI9481/gdisp_lld_board_firebullstm32f103.h @@ -113,7 +113,26 @@ static inline void write_data(uint16_t data) { CLR_WR; SET_WR; } -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) +/** + * @brief Set the bus in read mode + * + * @notapi + */ +static inline void setreadmode(void) { + // change pin mode to digital input + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); +} + +/** + * @brief Set the bus back into write mode + * + * @notapi + */ +static inline void setwritemode(void) { + // change pin mode back to digital output + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); +} + /** * @brief Read data from the lcd. * @@ -126,20 +145,12 @@ static inline void write_data(uint16_t data) { static inline uint16_t read_data(void) { uint16_t value; - // change pin mode to digital input - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); - CLR_RD; value = palReadPort(GPIOE); - value = palReadPort(GPIOE); SET_RD; - - // change pin mode back to digital output - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); return value; } -#endif #endif /* _GDISP_LLD_BOARD_H */ /** @} */ diff --git a/drivers/gdisp/ILI9481/gdisp_lld_board_template.h b/drivers/gdisp/ILI9481/gdisp_lld_board_template.h index 1bbcf282..e35f0c27 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld_board_template.h +++ b/drivers/gdisp/ILI9481/gdisp_lld_board_template.h @@ -88,7 +88,24 @@ static inline void write_data(uint16_t data) { } -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) +/** + * @brief Set the bus in read mode + * + * @notapi + */ +static inline void setreadmode(void) { + +} + +/** + * @brief Set the bus back into write mode + * + * @notapi + */ +static inline void setwritemode(void) { + +} + /** * @brief Read data from the lcd. * @@ -101,7 +118,6 @@ static inline void write_data(uint16_t data) { static inline uint16_t read_data(void) { } -#endif #endif /* _GDISP_LLD_BOARD_H */ /** @} */ diff --git a/drivers/gdisp/ILI9481/gdisp_lld_config.h b/drivers/gdisp/ILI9481/gdisp_lld_config.h index 79fea9f3..c41edd6b 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9481/gdisp_lld_config.h @@ -24,12 +24,10 @@ /*===========================================================================*/ #define GDISP_DRIVER_NAME "ILI9481" +#define GDISP_DRIVER_STRUCT GDISP_ILI9481 -#define GDISP_HARDWARE_CLEARS TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -#define GDISP_HARDWARE_SCROLL TRUE -#define GDISP_HARDWARE_PIXELREAD TRUE +#define GDISP_HARDWARE_STREAM_WRITE TRUE +#define GDISP_HARDWARE_STREAM_READ TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 7ec2b590..d2808604 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -257,6 +257,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } g->g.Powermode = (powermode_t)g->p.ptr; return; + case GDISP_CONTROL_ORIENTATION: if (g->g.Orientation == (orientation_t)g->p.ptr) return; @@ -298,12 +299,14 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } g->g.Orientation = (orientation_t)value; return; + case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; set_backlight((unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; + //case GDISP_CONTROL_CONTRAST: default: return; From 77872d856086241f671dd7b265c9869ed0c54984 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 1 Oct 2013 21:11:42 +1000 Subject: [PATCH 037/160] Nokia6610 GE12 driver ported to streaming. Also added orientation and power control. Untested. --- drivers/gdisp/Nokia6610GE12/gdisp_lld.c | 549 +++++------------- .../gdisp_lld_board_olimexsam7ex256.h | 90 ++- .../Nokia6610GE12/gdisp_lld_board_template.h | 18 +- .../gdisp/Nokia6610GE12/gdisp_lld_config.h | 11 +- drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 46 +- 5 files changed, 257 insertions(+), 457 deletions(-) diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c index a991a9a6..441ac82d 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c @@ -17,17 +17,6 @@ #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/* Controller definitions */ -#include "GE12.h" - -/* This controller is only ever used with a 132 x 132 display */ #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GDISP_SCREEN_HEIGHT @@ -36,11 +25,43 @@ #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_SCREEN_HEIGHT 132 -#define GDISP_SCREEN_WIDTH 132 -#define GDISP_INITIAL_CONTRAST 38 -#define GDISP_INITIAL_BACKLIGHT 100 +#define GDISP_LLD_DECLARATIONS +#include "gdisp/lld/gdisp_lld.h" +#include "gdisp_lld_board.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#include "GE12.h" + +#define GDISP_SCAN_LINES 132 +#define GDISP_SLEEP_SIZE 32 /* Sleep mode window lines - this must be 32 on this controller */ + +// Set parameters if they are not already set +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 130 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 130 +#endif +#ifndef GDISP_RAM_X_OFFSET + #define GDISP_RAM_X_OFFSET 0 /* Offset in RAM of visible area */ +#endif +#ifndef GDISP_RAM_Y_OFFSET + #define GDISP_RAM_Y_OFFSET 2 /* Offset in RAM of visible area */ +#endif +#endif +#ifndef GDISP_SLEEP_POS + #define GDISP_SLEEP_POS ((GDISP_SCAN_LINES-GDISP_SLEEP_SIZE)/2 & ~3) +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif /*===========================================================================*/ /* Driver exported variables. */ @@ -50,12 +71,14 @@ /* Driver local variables. */ /*===========================================================================*/ +static color_t savecolor; + +#define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0) + /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -#include "gdisp_lld_board.h" - // Some macros just to make reading the code easier #define delayms(ms) gfxSleepMilliseconds(ms) #define write_data2(d1, d2) { write_data(d1); write_data(d2); } @@ -64,33 +87,11 @@ #define write_cmd2(cmd, d1, d2) { write_cmd(cmd); write_data2(d1, d2); } #define write_cmd3(cmd, d1, d2, d3) { write_cmd(cmd); write_data3(d1, d2, d3); } -// A very common thing to do. -// An inline function has been used here incase the parameters have side effects with the internal calculations. -static inline void setviewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { - write_cmd2(CASET, x, x+cx-1); // Column address set - write_cmd2(PASET, y, y+cy-1); // Page address set -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ - -/** - * @brief Low level GDISP driver initialization. - * - * @notapi - */ -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { /* Initialise your display */ init_board(); @@ -100,402 +101,142 @@ bool_t gdisp_lld_init(void) { setpin_reset(FALSE); delayms(20); - // Get the bus for the following initialisation commands acquire_bus(); - - // UNTESTED - #if 1 - write_cmd(SLEEPOUT); // Sleep out - write_cmd(INVON); // Inversion on: seems to be required for this controller - write_cmd1(COLMOD, 0x03); // Color Interface Pixel Format - 0x03 = 12 bits-per-pixel - write_cmd1(MADCTL, 0xC8); // Memory access controler - 0xC0 = mirror x and y, reverse rgb - write_cmd1(SETCON, GDISP_INITIAL_CONTRAST); // Write contrast - delayms(20); - write_cmd(DISPON); // Display On - #else - // Alternative - write_cmd(SOFTRST); // Software Reset - delayms(20); - write_cmd(INITESC); // Initial escape - delayms(20); - write_cmd1(REFSET, 0x00); // Refresh set - write_cmd(DISPCTRL); // Set Display control - really 7 bytes of data - write_data(128); // Set the lenght of one selection term - write_data(128); // Set N inversion -> no N inversion - write_data(134); // Set frame frequence and bias rate -> 2 devision of frequency and 1/8 bias, 1/67 duty, 96x67 size - write_data(84); // Set duty parameter - write_data(69); // Set duty parameter - write_data(82); // Set duty parameter - write_data(67); // Set duty parameter - write_cmd(GRAYSCALE0); // Grey scale 0 position set - really 15 bytes of data - write_data(1); // GCP1 - gray lavel to be output when the RAM data is "0001" - write_data(2); // GCP2 - gray lavel to be output when the RAM data is "0010" - write_data(4); // GCP3 - gray lavel to be output when the RAM data is "0011" - write_data(8); // GCP4 - gray lavel to be output when the RAM data is "0100" - write_data(16); // GCP5 - gray lavel to be output when the RAM data is "0101" - write_data(30); // GCP6 - gray lavel to be output when the RAM data is "0110" - write_data(40); // GCP7 - gray lavel to be output when the RAM data is "0111" - write_data(50); // GCP8 - gray lavel to be output when the RAM data is "1000" - write_data(60); // GCP9 - gray lavel to be output when the RAM data is "1001" - write_data(70); // GCP10 - gray lavel to be output when the RAM data is "1010" - write_data(80); // GCP11 - gray lavel to be output when the RAM data is "1011" - write_data(90); // GCP12 - gray lavel to be output when the RAM data is "1100" - write_data(100); // GCP13 - gray lavel to be output when the RAM data is "1101" - write_data(110); // GCP14 - gray lavel to be output when the RAM data is "1110" - write_data(127); // GCP15 - gray lavel to be output when the RAM data is "1111" - write_cmd1(GAMMA, 0x01); // Gamma curve set - select gray scale - GRAYSCALE 0 or GREYSCALE 1 - Select grey scale 0 - write_cmd1(COMMONDRV, 0x00); // Command driver output - Set COM1-COM41 side come first, normal mod - write_cmd(NORMALMODE); // Set Normal mode (my) - // write_cmd(INVERSIONOFF); // Inversion off - write_cmd2(COLADDRSET, 0, 131); // Column address set - write_cmd2(PAGEADDRSET, 0, 131); // Page address set - write_cmd1(ACCESSCTRL, 0x40); // Memory access controler - 0x40 horizontal - // write_data(0x20); // vertical - write_cmd1(PWRCTRL, 0x04); // Power control - Internal resistance, V1OUT -> high power mode, oscilator devision rate - write_cmd(SLEEPOUT); // Sleep out - write_cmd(VOLTCTRL); // Voltage control - voltage control and write contrast define LCD electronic volume - // write_data(0x7f); // full voltage control - // write_data(0x03); // must be "1" - write_cmd1(CONTRAST, GDISP_INITIAL_CONTRAST); // Write contrast - delayms(20); - write_cmd(TEMPGRADIENT); // Temperature gradient - really 14 bytes of data - for(i=0; i<14; i++) - write_data(0); - write_cmd(BOOSTVON); // Booster voltage ON - write_cmd(DISPLAYON); // Finally - Display On - #endif - - // Release the bus + write_cmd(SLEEPOUT); // Sleep out + write_cmd1(COLMOD, 0x03); // Color Interface Pixel Format - 0x03 = 12 bits-per-pixel + write_cmd1(MADCTL, 0x00); // Memory access controller + write_cmd1(SETCON, 127*GDISP_INITIAL_CONTRAST/100-64); // Write contrast + delayms(20); release_bus(); /* Turn on the back-light */ set_backlight(GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure to match */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = GDISP_INITIAL_BACKLIGHT; - GDISP.Contrast = GDISP_INITIAL_CONTRAST; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - acquire_bus(); - setviewport(x, y, 1, 1); - write_cmd3(RAMWR, 0, (color>>8) & 0x0F, color & 0xFF); - release_bus(); -} - -/* ---- Optional Routines ---- */ - -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - unsigned i, tuples; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - tuples = (cx*cy+1)/2; // With an odd sized area we over-print by one pixel. - // This extra pixel is ignored by the controller. - +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { acquire_bus(); - setviewport(x, y, cx, cy); + write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set + write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set write_cmd(RAMWR); - for(i=0; i < tuples; i++) - write_data3(((color >> 4) & 0xFF), (((color << 4) & 0xF0)|((color >> 8) & 0x0F)), (color & 0xFF)); + g->flags &= ~GDISP_FLG_ODDBYTE; + } + LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { + if ((g->flags & GDISP_FLG_ODDBYTE)) { + // Write the pair of pixels to the display + write_data3(((savecolor >> 4) & 0xFF), (((savecolor << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); + g->flags &= ~GDISP_FLG_ODDBYTE; + } else { + savecolor = g->p.color; + g->flags |= GDISP_FLG_ODDBYTE; + } + } + LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { + if ((g->flags & GDISP_FLG_ODDBYTE)) { + write_data2(((savecolor >> 4) & 0xFF), ((savecolor << 4) & 0xF0)); + write_cmd(NOP); + } release_bus(); } #endif -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a bitmap. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - coord_t endx, endy, lg; - color_t c1, c2; - #if GDISP_PACKED_PIXELS - coord_t pos; - const uint8_t *p; - #endif - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - /* What are our end points */ - endx = srcx + cx; - endy = y + cy; - - acquire_bus(); - setviewport(x, y, cx, cy); - write_cmd(RAMWR); - - #if !GDISP_PACKED_PIXELS - // Although this controller uses packed pixels we support unpacked pixel - // formats in this blit by packing the data as we feed it to the controller. - lg = srccx - cx; - buffer += srcy * srccx + srcx; - x = srcx; - while (1) { - /* Get a pixel */ - c1 = *buffer++; - if (++x >= endx) { - if (++y >= endy) { - /* Odd pixel at end */ - write_data3(0, ((c1 >> 8) & 0x0F), (c1 & 0xFF)); - break; - } - x = srcx; - buffer += lg; - } - /* Get the next pixel */ - c2 = *buffer++; - write_data3(((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF)); - if (++x >= endx) { - if (++y >= endy) - break; - x = srcx; - buffer += lg; - } - } - - #else - - // Although this controller uses packed pixels, we may have to feed it into - // the controller with different packing to the source bitmap - #if !GDISP_PACKED_LINES - srccx = (srccx + 1) & ~1; - #endif - pos = srcy*srccx; - lg = (srccx - cx)/2*3; - p = ((const uint8_t *)buffer) + ((pos+srcx)/2 * 3); - - x = srcx; - while (1) { - /* Get a pixel */ - switch((pos+x)&1) { - case 0: c1 = (((color_t)p[0]) << 4)|(((color_t)p[1])>>4); break; - case 1: c1 = (((color_t)p[1]&0x0F) << 8)|((color_t)p[1]); break; - } - if (++x >= endx) { - if (++y >= endy) { - /* Odd pixel at end */ - write_data3(0, ((c1 >> 8) & 0x0F), (c1 & 0xFF)); - break; - } - x = srcx; - p += lg; - pos += srccx; - } - /* Get the next pixel */ - switch((pos+x)&1) { - case 0: c2 = (((color_t)p[0]) << 4)|(((color_t)p[1])>>4); break; - case 1: c2 = (((color_t)p[1]&0x0F) << 8)|((color_t)p[1]); break; - } - write_data3(((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF)); - if (++x >= endx) { - if (++y >= endy) - break; - x = srcx; - p += lg; - pos += srccx; - } - } - #endif - release_bus(); - } -#endif - -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) - /** - * @brief Get the color of a particular pixel. - * @note If x,y is off the screen, the result is undefined. - * - * @param[in] x, y The start of the text - * - * @notapi - */ - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - /* NOT IMPLEMENTED */ - /* Some board hardware might support this in the future. - * The Olimex board doesn't. - */ - } -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) - /** - * @brief Scroll vertically a section of the screen. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - /* NOT IMPLEMENTED */ - /* The hardware seems capable of doing this. - * It is just really complex so we leave it out for now. - */ - } -#endif - -#if GDISP_HARDWARE_CONTROL || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. - * GDISP_CONTROL_LLD - Low level driver control constants start at - * this value. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDISPDriver *g) { /* The hardware is capable of supporting... - * GDISP_CONTROL_POWER - not implemented yet - * GDISP_CONTROL_ORIENTATION - not implemented yet - * GDISP_CONTROL_BACKLIGHT - supported (the OlimexSAM7EX256 board.h currently only implements off/on although PWM is supported by the hardware) + * GDISP_CONTROL_POWER - supported + * GDISP_CONTROL_ORIENTATION - supported + * GDISP_CONTROL_BACKLIGHT - supported * GDISP_CONTROL_CONTRAST - supported */ - switch(what) { -#if 0 - // NOT IMPLEMENTED YET + switch(g->p.x) { case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + acquire_bus(); + write_cmd(SLEEPIN); + release_bus(); + break; + case powerOn: + acquire_bus(); + write_cmd(SLEEPOUT); + delayms(20); + write_cmd(NORON); // Set Normal mode (my) + release_bus(); + break; + case powerSleep: + acquire_bus(); + write_cmd(SLEEPOUT); + delayms(20); + write_cmd2(PTLAR, GDISP_SLEEP_POS, GDISP_SLEEP_POS+GDISP_SLEEP_SIZE) + write_cmd(PTLON); + release_bus(); + break; + default: return; - switch((gdisp_powermode_t)value) { - case powerOff: - // Code here - break; - case powerOn: - // Code here - /* You may need this --- - * if (GDISP.Powermode != powerSleep) - * gdisp_lld_init(); - */ - break; - case powerSleep: - /* Code here */ - break; - default: - return; } - GDISP.Powermode = (gdisp_powermode_t)value; + g->g.Powermode = (powermode_t)g->p.ptr; return; -#endif -#if 0 - // NOT IMPLEMENTED YET + case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(); + write_cmd1(MADCTL, 0x00); + release_bus(); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + acquire_bus(); + write_cmd1(MADCTL, 0xA0); // MY, MX, V, LAO, RGB, X, X, X + release_bus(); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + acquire_bus(); + write_cmd1(MADCTL, 0xC0); + release_bus(); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + acquire_bus(); + write_cmd1(MADCTL, 0x60); + release_bus(); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: return; - // WriteSpiData(0x48); // no mirror Y (temporary to satisfy Olimex bmptoarray utility) - // WriteSpiData(0xC8); // restore to (mirror x and y, reverse rgb) - switch((gdisp_orientation_t)value) { - case GDISP_ROTATE_0: - // Code here - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_90: - // Code here - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - case GDISP_ROTATE_180: - // Code here - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_270: - // Code here - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - default: - return; } - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; -#endif + case GDISP_CONTROL_BACKLIGHT: - if ((unsigned)value > 100) value = (void *)100; - set_backlight((unsigned)value); - GDISP.Backlight = (unsigned)value; + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; + set_backlight((unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; return; case GDISP_CONTROL_CONTRAST: - if ((unsigned)value > 100) value = (void *)100; + if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; acquire_bus(); - write_cmd1(CONTRAST,(unsigned)value); + write_cmd1(CONTRAST,(unsigned)127*g->p.ptr/100-64); release_bus(); - GDISP.Contrast = (unsigned)value; + g->g.Contrast = (unsigned)g->p.ptr; return; } } diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_olimexsam7ex256.h index ce0f7362..c8215c75 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_olimexsam7ex256.h +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_olimexsam7ex256.h @@ -1,12 +1,12 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ /** - * @file drivers/gdisp/Nokia6610GE12/gdisp_lld_board_olimexsam7ex256.h + * @file drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h * @brief GDISP Graphic Driver subsystem board interface for the Olimex SAM7-EX256 board. * * @addtogroup GDISP @@ -16,14 +16,46 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H +/* + * Set various display properties. These properties mostly depend on the exact controller chip you get. + * The defaults should work for most controllers. + */ +//#define GDISP_SCREEN_HEIGHT 130 // The visible display height +//#define GDISP_SCREEN_WIDTH 130 // The visible display width +//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area +//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area +//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display +//#define GDISP_INITIAL_CONTRAST 50 // The initial contrast percentage +//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage + // ****************************************************** // Pointers to AT91SAM7X256 peripheral data structures // ****************************************************** -volatile AT91PS_PIO pPIOA = AT91C_BASE_PIOA; -volatile AT91PS_PIO pPIOB = AT91C_BASE_PIOB; -volatile AT91PS_SPI pSPI = AT91C_BASE_SPI0; -volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; -volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_SPI0; +static volatile AT91PS_PIO pPIOA = AT91C_BASE_PIOA; +static volatile AT91PS_PIO pPIOB = AT91C_BASE_PIOB; +static volatile AT91PS_SPI pSPI = AT91C_BASE_SPI0; +static volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; +static volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_SPI0; + +/* The PWM backlight control is non-linear on this board. + * We pick values here that make it look a bit more linear. + */ +#define PWM_TOP_VALUE 500 +#define PWM_BOTTOM_VALUE 200 + +#define PWM_VALUE(x) (PWM_BOTTOM_VALUE+(PWM_TOP_VALUE-PWM_BOTTOM_VALUE)*(x)/100) + +/* PWM configuration structure. The LCD Backlight is on PWM1/PB20 ie PWM2/PIN1 in ChibiOS speak */ +static const PWMConfig pwmcfg = { + 1000000, /* 1 MHz PWM clock frequency. Ignored as we are using PWM_MCK_DIV_n */ + 1000, /* PWM period is 1000 cycles. */ + NULL, + { + {PWM_MCK_DIV_1 | PWM_OUTPUT_ACTIVE_HIGH | PWM_OUTPUT_PIN1 | PWM_DISABLEPULLUP_PIN1, NULL}, + }, +}; + +static bool_t pwmRunning = FALSE; /** * @brief Initialise the board for the display. @@ -78,14 +110,14 @@ static inline void init_board(void) { pPMC->PMC_PCER = 1 << AT91C_ID_SPI0; // Fixed mode - pSPI->SPI_CR = 0x81; //SPI Enable, Sowtware reset + pSPI->SPI_CR = 0x81; //SPI Enable, Software reset pSPI->SPI_CR = 0x01; //SPI Enable + pSPI->SPI_MR = 0xE0011; //Master mode, fixed select, disable decoder, PCS=1110 + pSPI->SPI_CSR[0] = 0x01010311; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/3 = 16MHz - //pSPI->SPI_MR = 0xE0019; //Master mode, fixed select, disable decoder, FDIV=1 (MCK), PCS=1110 - pSPI->SPI_MR = 0xE0011; //Master mode, fixed select, disable decoder, FDIV=0 (MCK), PCS=1110 - - //pSPI->SPI_CSR[0] = 0x01010C11; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/32*12 = 125kHz - pSPI->SPI_CSR[0] = 0x01010311; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/8 = 6MHz if using commented MR line above + /* Display backlight control at 100% */ + pwmRunning = FALSE; + palSetPad(IOPORT2, PIOB_LCD_BL); } /** @@ -113,10 +145,28 @@ static inline void setpin_reset(bool_t state) { * @notapi */ static inline void set_backlight(uint8_t percent) { - if (percent) + if (percent == 100) { + /* Turn the pin on - No PWM */ + if (pwmRunning) { + pwmStop(&PWMD2); + pwmRunning = FALSE; + } palSetPad(IOPORT2, PIOB_LCD_BL); - else + } else if (percent == 0) { + /* Turn the pin off - No PWM */ + if (pwmRunning) { + pwmStop(&PWMD2); + pwmRunning = FALSE; + } palClearPad(IOPORT2, PIOB_LCD_BL); + } else { + /* Use the PWM */ + if (!pwmRunning) { + pwmStart(&PWMD2, &pwmcfg); + pwmRunning = TRUE; + } + pwmEnableChannel(&PWMD2, 0, PWM_VALUE(percent)); + } } /** diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_template.h b/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_template.h index a1fa6050..d3594434 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_template.h +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_template.h @@ -6,8 +6,8 @@ */ /** - * @file drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board interface for the Nokia6610 GE8 display. + * @file drivers/gdisp/Nokia6610GE12/gdisp_lld_board_template.h + * @brief GDISP Graphic Driver subsystem board interface for the Nokia6610 GE12 display. * * @addtogroup GDISP * @{ @@ -16,6 +16,18 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H +/* + * Set various display properties. These properties mostly depend on the exact controller chip you get. + * The defaults should work for most controllers. + */ +//#define GDISP_SCREEN_HEIGHT 130 // The visible display height +//#define GDISP_SCREEN_WIDTH 130 // The visible display width +//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area +//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area +//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display +//#define GDISP_INITIAL_CONTRAST 50 // The initial contrast percentage +//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage + /** * @brief Initialise the board for the display. * @notes Performs the following functions: @@ -95,7 +107,7 @@ static inline void write_data(uint16_t data) { } -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) +#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL /** * @brief Read data from the lcd. * diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h b/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h index 57b8b916..edbf3290 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h @@ -23,13 +23,10 @@ /*===========================================================================*/ #define GDISP_DRIVER_NAME "Nokia6610GE12" - -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -#define GDISP_HARDWARE_CONTROL TRUE - -#define GDISP_SOFTWARE_TEXTFILLDRAW FALSE -#define GDISP_SOFTWARE_TEXTBLITCOLUMN FALSE +#define GDISP_DRIVER_STRUCT GDISP_Nokia6610GE12 + +#define GDISP_HARDWARE_CONTROL TRUE +#define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 /* This driver supports both packed and unpacked pixel formats and line formats. diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index ce0400d1..3f535369 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -518,29 +518,29 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return; acquire_bus(); switch((orientation_t)g->p.ptr) { - case GDISP_ROTATE_0: - write_cmd3(DATCTL, 0x00, 0x00, 0x02); // P1: page normal, column normal, scan in column direction - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_90: - write_cmd3(DATCTL, 0x05, 0x00, 0x02); // P1: page reverse, column normal, scan in page direction - g->g.Height = GDISP_SCREEN_WIDTH; - g->g.Width = GDISP_SCREEN_HEIGHT; - break; - case GDISP_ROTATE_180: - write_cmd3(DATCTL, 0x03, 0x00, 0x02); // P1: page reverse, column reverse, scan in column direction - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_270: - write_cmd3(DATCTL, 0x06, 0x00, 0x02); // P1: page normal, column reverse, scan in page direction - g->g.Height = GDISP_SCREEN_WIDTH; - g->g.Width = GDISP_SCREEN_HEIGHT; - break; - default: - release_bus(); - return; + case GDISP_ROTATE_0: + write_cmd3(DATCTL, 0x00, 0x00, 0x02); // P1: page normal, column normal, scan in column direction + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + write_cmd3(DATCTL, 0x05, 0x00, 0x02); // P1: page reverse, column normal, scan in page direction + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + write_cmd3(DATCTL, 0x03, 0x00, 0x02); // P1: page reverse, column reverse, scan in column direction + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + write_cmd3(DATCTL, 0x06, 0x00, 0x02); // P1: page normal, column reverse, scan in page direction + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + release_bus(); + return; } release_bus(); g->g.Orientation = (orientation_t)g->p.ptr; From 8408e020b4a80f40ccbc15378a85fa2ce09da361 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 2 Oct 2013 00:56:57 +1000 Subject: [PATCH 038/160] Compile error fix. Nokia GE8 - scale contrast correctly. --- drivers/gdisp/Nokia6610GE12/gdisp_lld.c | 1 - drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 8 ++++---- .../gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c index 441ac82d..c8071917 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c @@ -52,7 +52,6 @@ #ifndef GDISP_RAM_Y_OFFSET #define GDISP_RAM_Y_OFFSET 2 /* Offset in RAM of visible area */ #endif -#endif #ifndef GDISP_SLEEP_POS #define GDISP_SLEEP_POS ((GDISP_SCAN_LINES-GDISP_SLEEP_SIZE)/2 & ~3) #endif diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index 3f535369..d3e30d0e 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -93,7 +93,7 @@ #define GDISP_SLEEP_POS ((GDISP_SCAN_LINES-GDISP_SLEEP_SIZE)/2) #endif #ifndef GDISP_INITIAL_CONTRAST - #define GDISP_INITIAL_CONTRAST 38 + #define GDISP_INITIAL_CONTRAST 60 #endif #ifndef GDISP_INITIAL_BACKLIGHT #define GDISP_INITIAL_BACKLIGHT 100 @@ -162,8 +162,8 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { // P1: 0x00 = page address normal, column address normal, address scan in column direction // P2: 0x00 = RGB sequence (default value) // P3: 0x02 = 4 bits per colour (Type A) - write_cmd2(VOLCTR, GDISP_INITIAL_CONTRAST, 0x03); // Voltage control (contrast setting) - // P1 = Contrast + write_cmd2(VOLCTR, 63*GDISP_INITIAL_CONTRAST/100, 0x03); // Voltage control (contrast setting) + // P1 = Contrast (0..63) // P2 = 3 resistance ratio (only value that works) delayms(100); // Allow power supply to stabilise write_cmd(DISON); // Turn on the display @@ -554,7 +554,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { case GDISP_CONTROL_CONTRAST: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; acquire_bus(); - write_cmd2(VOLCTR, (unsigned)g->p.ptr, 0x03); + write_cmd2(VOLCTR, 63*(unsigned)g->p.ptr/100, 0x03); release_bus(); g->g.Contrast = (unsigned)g->p.ptr; return; diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h index 8afc3573..4eeea62f 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h @@ -227,7 +227,7 @@ static inline void write_data(uint16_t data) { */ static inline uint16_t read_data(void) { #error "gdispNokia6610GE8: GDISP_HARDWARE_READPIXEL and GDISP_HARDWARE_SCROLL are not supported on this board" - return 0; + return pSPI->SPI_RDR; } #endif From 884db04e8c13d9258c6aea10248e42615e10ab83 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 2 Oct 2013 16:29:02 +1000 Subject: [PATCH 039/160] New optimisation method for some streaming drivers. It should improve speed by about 30% for those controllers that support it. --- include/gdisp/lld/gdisp_lld.h | 38 +++++- src/gdisp/gdisp.c | 212 +++++++++++++++++++++++++++++++++- 2 files changed, 245 insertions(+), 5 deletions(-) diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 205b425a..4813d828 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -49,6 +49,17 @@ #define GDISP_HARDWARE_STREAM_READ FALSE #endif + /** + * @brief Hardware supports setting the cursor position within the stream window. + * @details If set to @p FALSE this routine is not available. + * @note This is used to optimise setting of individual pixels within a stream window. + * It should therefore not be implemented unless it is cheaper than just setting + * a new window. + */ + #ifndef GDISP_HARDWARE_STREAM_POS + #define GDISP_HARDWARE_STREAM_POS FALSE + #endif + /** * @brief Hardware accelerated draw pixel. * @details If set to @p FALSE software emulation is used. @@ -142,8 +153,9 @@ typedef struct GDISPDriver { #endif uint16_t flags; - #define GDISP_FLG_INSTREAM 0x0001 - #define GDISP_FLG_DRIVER 0x0002 // This flags and above are for use by the driver + #define GDISP_FLG_INSTREAM 0x0001 // We are in a user based stream operation + #define GDISP_FLG_SCRSTREAM 0x0002 // The stream area currently covers the whole screen + #define GDISP_FLG_DRIVER 0x0004 // This flags and above are for use by the driver // Multithread Mutex #if GDISP_NEED_MULTITHREAD @@ -216,6 +228,7 @@ typedef struct GDISPDriver { * @note The parameter variables must not be altered by the driver. * @note Streaming operations that wrap the defined window have * undefined results. + * @note This must be followed by a call to @p gdisp_lld_write_pos() if GDISP_HARDWARE_STREAM_POS is TRUE. */ LLDSPEC void gdisp_lld_write_start(GDISPDriver *g); @@ -239,6 +252,19 @@ typedef struct GDISPDriver { * @note The parameter variables must not be altered by the driver. */ LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g); + + #if GDISP_HARDWARE_STREAM_POS || defined(__DOXYGEN__) + /** + * @brief Change the current position within the current streaming window + * @pre GDISP_HARDWARE_STREAM_POS is TRUE and GDISP_HARDWARE_STREAM_WRITE is TRUE + * + * @param[in] g The driver structure + * @param[in] g->p.x,g->p.y The new position (which will always be within the existing stream window) + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_write_pos(GDISPDriver *g); + #endif #endif #if GDISP_HARDWARE_STREAM_READ || defined(__DOXYGEN__) @@ -278,7 +304,6 @@ typedef struct GDISPDriver { LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g); #endif - #if GDISP_HARDWARE_DRAWPIXEL || defined(__DOXYGEN__) /** * @brief Draw a pixel @@ -424,6 +449,7 @@ typedef struct GDISPDriver { typedef struct GDISPVMT { bool_t (*init)(GDISPDriver *g); void (*writestart)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy + void (*writepos)(GDISPDriver *g); // Uses p.x,p.y void (*writecolor)(GDISPDriver *g); // Uses p.color void (*writestop)(GDISPDriver *g); // Uses no parameters void (*readstart)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy @@ -446,6 +472,11 @@ typedef struct GDISPDriver { gdisp_lld_init, #if GDISP_HARDWARE_STREAM_WRITE gdisp_lld_write_start, + #if GDISP_HARDWARE_STREAM_POS + gdisp_lld_write_pos, + #else + 0, + #endif gdisp_lld_write_color, gdisp_lld_write_stop, #else @@ -509,6 +540,7 @@ typedef struct GDISPDriver { #else #define gdisp_lld_init(g) g->vmt->init(g) #define gdisp_lld_write_start(g) g->vmt->writestart(g) + #define gdisp_lld_write_pos(g) g->vmt->writepos(g) #define gdisp_lld_write_color(g) g->vmt->writecolor(g) #define gdisp_lld_write_stop(g) g->vmt->writestop(g) #define gdisp_lld_read_start(g) g->vmt->readstart(g) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index a135462d..756d5c1d 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -54,6 +54,17 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; /* Internal functions. */ /*==========================================================================*/ +#if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + static INLINE void setglobalwindow(void) { + coord_t x, y; + x = GC->p.x; y = GC->p.y; + GC->p.cx = GC->g.Width; GC->p.cy = GC->g.Height; + gdisp_lld_write_start(GC); + GC->p.x = x; GC->p.y = y; + GC->flags |= GDISP_FLG_SCRSTREAM; + } +#endif + // drawpixel_clip() // Parameters: x,y // Alters: cx, cy (if using streaming) @@ -67,6 +78,18 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; #else #define drawpixel_clip() gdisp_lld_draw_pixel(GC) #endif +#elif GDISP_HARDWARE_STREAM_POS + // Next best is cursor based streaming + static INLINE void drawpixel_clip(void) { + #if NEED_CLIPPING + if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1 || GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1) + return; + #endif + if (!(GC->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(); + gdisp_lld_write_pos(GC); + gdisp_lld_write_color(GC); + } #else // Worst is streaming static INLINE void drawpixel_clip(void) { @@ -86,6 +109,8 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; // Parameters: x,y cx,cy and color // Alters: nothing // Note: This is not clipped +// Resets the streaming area +// if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set. #if GDISP_HARDWARE_FILLS // Best is hardware accelerated area fill #define fillarea() gdisp_lld_fill_area(GC) @@ -96,7 +121,17 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; area = (uint32_t)GC->p.cx * GC->p.cy; + #if GDISP_HARDWARE_STREAM_POS + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif + gdisp_lld_write_start(GC); + #if GDISP_HARDWARE_STREAM_POS + gdisp_lld_write_pos(GC); + #endif for(; area; area--) gdisp_lld_write_color(GC); gdisp_lld_write_stop(GC); @@ -130,6 +165,8 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; // Parameters: x,y and x1 // Alters: x,y x1,y1 cx,cy +// Assumes the window covers the screen and a write_stop() will occur later +// if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set. static void hline_clip(void) { // Swap the points if necessary so it always goes from x to x1 if (GC->p.x1 < GC->p.x) { @@ -152,6 +189,12 @@ static void hline_clip(void) { #if GDISP_HARDWARE_DRAWPIXEL // Best is hardware accelerated pixel draw gdisp_lld_draw_pixel(GC); + #elif GDISP_HARDWARE_STREAM_POS + // Next best is cursor based streaming + if (!(GC->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(); + gdisp_lld_write_pos(GC); + gdisp_lld_write_color(GC); #else // Worst is streaming GC->p.cx = GC->p.cy = 1; @@ -168,6 +211,12 @@ static void hline_clip(void) { GC->p.cx = GC->p.x1 - GC->p.x + 1; GC->p.cy = 1; gdisp_lld_fill_area(GC); + #elif GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + // Next best is cursor based streaming + if (!(GC->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(); + gdisp_lld_write_pos(GC); + do { gdisp_lld_write_color(GC); } while(GC->p.cx--); #elif GDISP_HARDWARE_STREAM_WRITE // Next best is streaming GC->p.cx = GC->p.x1 - GC->p.x + 1; @@ -200,12 +249,18 @@ static void vline_clip(void) { // This is an optimization for the point case. It is only worthwhile however if we // have hardware fills or if we support both hardware pixel drawing and hardware streaming - #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) + #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) || (GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE) // Is this a point if (GC->p.y == GC->p.y1) { #if GDISP_HARDWARE_DRAWPIXEL // Best is hardware accelerated pixel draw gdisp_lld_draw_pixel(GC); + #elif GDISP_HARDWARE_STREAM_POS + // Next best is cursor based streaming + if (!(GC->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(); + gdisp_lld_write_pos(GC); + gdisp_lld_write_color(GC); #else // Worst is streaming GC->p.cx = GC->p.cy = 1; @@ -224,9 +279,18 @@ static void vline_clip(void) { gdisp_lld_fill_area(GC); #elif GDISP_HARDWARE_STREAM_WRITE // Next best is streaming + #if GDISP_HARDWARE_STREAM_POS + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif GC->p.cy = GC->p.y1 - GC->p.y + 1; GC->p.cx = 1; gdisp_lld_write_start(GC); + #if GDISP_HARDWARE_STREAM_POS + gdisp_lld_write_pos(GC); + #endif do { gdisp_lld_write_color(GC); } while(GC->p.cy--); gdisp_lld_write_stop(GC); #else @@ -363,6 +427,9 @@ void _gdispInit(void) { GC->p.cx = cx; GC->p.cy = cy; gdisp_lld_write_start(GC); + #if GDISP_HARDWARE_STREAM_POS + gdisp_lld_write_pos(GC); + #endif #else // Worst - save the parameters and use pixel drawing @@ -501,6 +568,12 @@ void gdispDrawPixel(coord_t x, coord_t y, color_t color) { GC->p.y = y; GC->p.color = color; drawpixel_clip(); + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -512,6 +585,12 @@ void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color GC->p.y1 = y1; GC->p.color = color; line_clip(); + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -541,6 +620,9 @@ void gdispClear(color_t color) { area = (uint32_t)GC->p.cx * GC->p.cy; gdisp_lld_write_start(GC); + #if GDISP_HARDWARE_STREAM_POS + gdisp_lld_write_pos(GC); + #endif for(; area; area--) gdisp_lld_write_color(GC); gdisp_lld_write_stop(GC); @@ -605,6 +687,9 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.cx = cx; GC->p.cy = cy; gdisp_lld_write_start(GC); + #if GDISP_HARDWARE_STREAM_POS + gdisp_lld_write_pos(GC); + #endif for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { for(GC->p.x = x; GC->p.x < srcx; GC->p.x++) { GC->p.color = *buffer++; @@ -716,6 +801,13 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.x = x + a; GC->p.y = y - b; drawpixel_clip(); GC->p.x = x - a; GC->p.y = y + b; drawpixel_clip(); GC->p.x = x - a; GC->p.y = y - b; drawpixel_clip(); + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } #endif @@ -750,6 +842,13 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, } while(a < b); GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } #endif @@ -787,6 +886,13 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, err -= (2*dy-1)*a2; } } while(dy >= 0); + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } #endif @@ -822,6 +928,13 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, err -= (2*dy-1)*a2; } } while(dy >= 0); + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } #endif @@ -888,8 +1001,16 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, if (full & 0x0C) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } if (full & 0x03) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } if (full & 0x30) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } - if (full == 0xFF) + if (full == 0xFF) { + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif + MUTEX_EXIT; return; + } } #if GFX_USE_GMISC && GMISC_NEED_FIXEDTRIG @@ -1002,6 +1123,13 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, if (((sbit & 0x10) && a >= sedge && a <= eedge) || ((sbit & 0x20) && a <= sedge && a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } } + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } #endif @@ -1499,6 +1627,12 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, break; } + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -1664,6 +1798,9 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, GC->p.cx = fx; GC->p.cy = 1; gdisp_lld_write_start(GC); + #if GDISP_HARDWARE_STREAM_POS + gdisp_lld_write_pos(GC); + #endif for(j = 0; j < fx; j++) { GC->p.color = GC->linebuf[j]; gdisp_lld_write_color(GC); @@ -1776,6 +1913,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { GC->p.x = cx; GC->p.y = y; GC->p.y1 = cy; vline_clip(); } } + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -1791,6 +1935,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+p[1].x; GC->p.y1=ty+p[1].y; line_clip(); } GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+pntarray->x; GC->p.y1=ty+pntarray->y; line_clip(); + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -1850,6 +2001,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { } if (!cnt) { + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); return; } @@ -1859,6 +2016,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { if (ymax == lpnt->y) { for (lpnt = lpnt <= pntarray ? epnts : lpnt-1; lpnt->y == y; cnt--) { if (!cnt) { + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); return; } @@ -1869,6 +2032,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { } else { for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) { if (!cnt) { + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); return; } @@ -1948,6 +2117,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { GC->t.clipy1 = y + font->height; GC->t.color = color; mf_render_character(font, x, y, c, drawcharline, GC); + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -1967,6 +2142,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { fillarea(); mf_render_character(font, x, y, c, fillcharline, GC); } + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -1980,6 +2161,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { GC->t.color = color; mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, GC); + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -1999,6 +2186,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { fillarea(); mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, GC); } + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -2026,6 +2220,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { y += (cy+1 - font->height)/2; mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, GC); + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } @@ -2063,6 +2264,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { /* Render */ mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, GC); } + + #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + if ((GC->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(GC); + GC->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif MUTEX_EXIT(); } From d7d02395d0c1afe27bc39eeddc17899084c72de9 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 2 Oct 2013 16:30:06 +1000 Subject: [PATCH 040/160] Updates to ported drivers to support new optimisation method. Includes Bug fixes. --- drivers/gdisp/ILI9320/gdisp_lld.c | 43 ++++++++++++++++------- drivers/gdisp/ILI9320/gdisp_lld_config.h | 1 + drivers/gdisp/ILI9325/gdisp_lld.c | 44 ++++++++++++++++-------- drivers/gdisp/ILI9325/gdisp_lld_config.h | 1 + drivers/gdisp/SSD1289/gdisp_lld.c | 37 +++++++++++++++----- drivers/gdisp/SSD1289/gdisp_lld_config.h | 1 + 6 files changed, 91 insertions(+), 36 deletions(-) diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index d8bc411a..68081b96 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -57,31 +57,43 @@ uint32_t DISPLAY_CODE; #define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } #define write_reg(reg, data) { write_index(reg); write_data(data); } -static void set_viewport(uint16_t x, uint16_t y, uint16_t cx, uint16_t cy) { +static void set_cursor(GDISPDriver *g) { switch(g->g.Orientation) { case GDISP_ROTATE_0: case GDISP_ROTATE_180: - write_reg(0x0050, x); - write_reg(0x0051, x + cx - 1); - write_reg(0x0052, y); - write_reg(0x0053, y + cy - 1); - write_reg(0x0020, x); - write_reg(0x0021, y); + write_reg(0x0020, g->p.x); + write_reg(0x0021, g->p.y); break; case GDISP_ROTATE_90: case GDISP_ROTATE_270: - write_reg(0x0050, y); - write_reg(0x0051, y + cy - 1); - write_reg(0x0052, x); - write_reg(0x0053, x + cx - 1); - write_reg(0x0020, y); - write_reg(0x0021, x); + write_reg(0x0020, g->p.y); + write_reg(0x0021, g->p.x); break; } write_index(0x0022); } +static void set_viewport(GDISPDriver *g) { + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + write_reg(0x0050, g->p.x); + write_reg(0x0051, g->p.x + g->p.cx - 1); + write_reg(0x0052, g->p.y); + write_reg(0x0053, g->p.y + g->p.cy - 1); + break; + + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + write_reg(0x0050, g->p.y); + write_reg(0x0051, g->p.y + g->p.cy - 1); + write_reg(0x0052, g->p.x); + write_reg(0x0053, g->p.x + g->p.cx - 1); + break; + } +} + LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { /* Initialise your display */ init_board(); @@ -181,12 +193,17 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { release_bus(); } + LLDSPEC void gdisp_lld_write_pos(GDISPDriver *g) { + set_cursor(g); + } + #endif #endif #if GDISP_HARDWARE_STREAM_READ LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { acquire_bus(); set_viewport(g); + set_cursor(g); setreadmode(); dummy_read(); } diff --git a/drivers/gdisp/ILI9320/gdisp_lld_config.h b/drivers/gdisp/ILI9320/gdisp_lld_config.h index 7cf7457a..02533e8b 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_config.h @@ -27,6 +27,7 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE +#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 diff --git a/drivers/gdisp/ILI9325/gdisp_lld.c b/drivers/gdisp/ILI9325/gdisp_lld.c index a30bea44..4795887e 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld.c +++ b/drivers/gdisp/ILI9325/gdisp_lld.c @@ -61,29 +61,41 @@ uint32_t DISPLAY_CODE; #define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } #define write_reg(reg, data) { write_index(reg); write_data(data); } -static void set_viewport(GDISPDriver* g) { +static void set_cursor(GDISPDriver *g) { switch(g->g.Orientation) { case GDISP_ROTATE_0: case GDISP_ROTATE_180: - write_reg(0x0050, x); - write_reg(0x0051, x + cx - 1); - write_reg(0x0052, y); - write_reg(0x0053, y + cy - 1); - write_reg(0x0020, x); - write_reg(0x0021, y); + write_reg(0x0020, g->p.x); + write_reg(0x0021, g->p.y); break; case GDISP_ROTATE_90: case GDISP_ROTATE_270: - write_reg(0x0050, y); - write_reg(0x0051, y + cy - 1); - write_reg(0x0052, x); - write_reg(0x0053, x + cx - 1); - write_reg(0x0020, y); - write_reg(0x0021, x); + write_reg(0x0020, g->p.y); + write_reg(0x0021, g->p.x); + break; + } + write_index(0x0022); +} + +static void set_viewport(GDISPDriver* g) { + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + write_reg(0x0050, g->p.x); + write_reg(0x0051, g->p.x + g->p.cx - 1); + write_reg(0x0052, g->p.y); + write_reg(0x0053, g->p.y + g->p.cy - 1); + break; + + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + write_reg(0x0050, g->p.y); + write_reg(0x0051, g->p.y + g->p.cy - 1); + write_reg(0x0052, g->p.x); + write_reg(0x0053, g->p.x + g->p.cx - 1); break; } - write_reg(0x0022, color); } LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { @@ -182,12 +194,16 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { release_bus(); } + LLDSPEC void gdisp_lld_write_pos(GDISPDriver *g) { + set_cursor(g); + } #endif #if GDISP_HARDWARE_STREAM_READ LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { acquire_bus(); set_viewport(g); + set_cursor(g); setreadmode(); dummy_read(); } diff --git a/drivers/gdisp/ILI9325/gdisp_lld_config.h b/drivers/gdisp/ILI9325/gdisp_lld_config.h index 572b8361..aabf768f 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9325/gdisp_lld_config.h @@ -27,6 +27,7 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE +#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index d2808604..09122d2f 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -43,6 +43,28 @@ #define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } #define write_reg(reg, data) { write_index(reg); write_data(data); } +static void set_cursor(GDISPDriver *g) { + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + write_reg(0x004e, g->p.x & 0x00FF); + write_reg(0x004f, g->p.y & 0x01FF); + break; + case GDISP_ROTATE_90: + write_reg(0x004e, g->p.y & 0x00FF); + write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); + break; + case GDISP_ROTATE_180: + write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF); + write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); + break; + case GDISP_ROTATE_270: + write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF); + write_reg(0x004f, g->p.x & 0x01FF); + break; + } + write_index(0x0022); +} + static void set_viewport(GDISPDriver* g) { /* Reg 0x44 - Horizontal RAM address position * Upper Byte - HEA @@ -60,33 +82,24 @@ static void set_viewport(GDISPDriver* g) { write_reg(0x44, (((g->p.x+g->p.cx-1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); write_reg(0x45, g->p.y & 0x01FF); write_reg(0x46, (g->p.y+g->p.cy-1) & 0x01FF); - write_reg(0x004e, g->p.x & 0x00FF); - write_reg(0x004f, g->p.y & 0x01FF); break; case GDISP_ROTATE_90: write_reg(0x44, (((g->p.y+g->p.cy-1) << 8) & 0xFF00 ) | (g->p.y & 0x00FF)); write_reg(0x45, (GDISP_SCREEN_HEIGHT-(g->p.x+g->p.cx)) & 0x01FF); write_reg(0x46, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); - write_reg(0x004e, g->p.y & 0x00FF); - write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); break; case GDISP_ROTATE_180: write_reg(0x44, (((GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (g->p.x+g->p.cx)) & 0x00FF)); write_reg(0x45, (GDISP_SCREEN_HEIGHT-(g->p.y+g->p.cy)) & 0x01FF); write_reg(0x46, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); - write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF); - write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); break; case GDISP_ROTATE_270: write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1); write_reg(0x44, (((GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH-(g->p.y+g->p.cy)) & 0x00FF)); write_reg(0x45, g->p.x & 0x01FF); write_reg(0x46, (g->p.x+g->p.cx-1) & 0x01FF); - write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF); - write_reg(0x004f, g->p.x & 0x01FF); break; } - write_index(0x0022); } /*===========================================================================*/ @@ -179,12 +192,16 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { release_bus(); } + LLDSPEC void gdisp_lld_stream_pos(GDISPDriver *g) { + set_cursor(g); + } #endif #if GDISP_HARDWARE_STREAM_READ LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { acquire_bus(); set_viewport(g); + set_cursor(g); setreadmode(); dummy_read(); } @@ -201,6 +218,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { acquire_bus(); set_viewport(g); + set_cursor(g); dma_with_noinc(&color, g->p.cx*g->p.cy) release_bus(); } @@ -215,6 +233,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { acquire_bus(); set_viewport(g); + set_cursor(g); if (g->p.x2 == g->p.cx) { dma_with_inc(buffer, g->p.cx*g->p.cy); } else { diff --git a/drivers/gdisp/SSD1289/gdisp_lld_config.h b/drivers/gdisp/SSD1289/gdisp_lld_config.h index 9c00ce39..fc04a798 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_config.h @@ -27,6 +27,7 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE +#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE #if defined(GDISP_USE_DMA) From b3ee216bd2565e8ab9298f1f54b8e6df762b7d58 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sat, 5 Oct 2013 02:32:35 +0200 Subject: [PATCH 041/160] Updates from main-line code --- gfxconf.example.h | 1 + include/gtimer/options.h | 73 ++++++++++++++++++++++------------------ src/gtimer/gtimer.c | 2 +- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/gfxconf.example.h b/gfxconf.example.h index 1f7d9c2e..e6be90db 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -146,6 +146,7 @@ #define GDISP_LINEBUF_SIZE 128 #define GEVENT_MAXIMUM_SIZE 32 #define GEVENT_MAX_SOURCE_LISTENERS 32 + #define GTIMER_THREAD_PRIORITY HIGH_PRIORITY #define GTIMER_THREAD_WORKAREA_SIZE 512 #define GADC_MAX_LOWSPEED_DEVICES 4 #define GWIN_BUTTON_LAZY_RELEASE FALSE diff --git a/include/gtimer/options.h b/include/gtimer/options.h index 958f89e4..17358abe 100644 --- a/include/gtimer/options.h +++ b/include/gtimer/options.h @@ -4,36 +4,43 @@ * * http://ugfx.org/license.html */ - -/** - * @file include/gtimer/options.h - * @brief GTIMER sub-system options header file. - * - * @addtogroup GTIMER - * @{ - */ - -#ifndef _GTIMER_OPTIONS_H -#define _GTIMER_OPTIONS_H - -/** - * @name GTIMER Functionality to be included - * @{ - */ -/** - * @} - * - * @name GTIMER Optional Sizing Parameters - * @{ - */ - /** - * @brief Defines the size of the timer threads work area (stack+structures). - * @details Defaults to 512 bytes - */ - #ifndef GTIMER_THREAD_WORKAREA_SIZE - #define GTIMER_THREAD_WORKAREA_SIZE 512 - #endif -/** @} */ - -#endif /* _GTIMER_OPTIONS_H */ -/** @} */ + +/** + * @file include/gtimer/options.h + * @brief GTIMER sub-system options header file. + * + * @addtogroup GTIMER + * @{ + */ + +#ifndef _GTIMER_OPTIONS_H +#define _GTIMER_OPTIONS_H + +/** + * @name GTIMER Functionality to be included + * @{ + */ +/** + * @} + * + * @name GTIMER Optional Sizing Parameters + * @{ + */ + /** + * @brief Defines the GTIMER thread priority + * @details Defaults to HIGH_PRIORITY + */ + #ifndef GTIMER_THREAD_PRIORITY + #define GTIMER_THREAD_PRIORITY HIGH_PRIORITY + #endif + /** + * @brief Defines the size of the timer threads work area (stack+structures). + * @details Defaults to 512 bytes + */ + #ifndef GTIMER_THREAD_WORKAREA_SIZE + #define GTIMER_THREAD_WORKAREA_SIZE 512 + #endif +/** @} */ + +#endif /* _GTIMER_OPTIONS_H */ +/** @} */ diff --git a/src/gtimer/gtimer.c b/src/gtimer/gtimer.c index e789ee74..25b7d804 100644 --- a/src/gtimer/gtimer.c +++ b/src/gtimer/gtimer.c @@ -132,7 +132,7 @@ void gtimerStart(GTimer *pt, GTimerFunction fn, void *param, bool_t periodic, de // Start our thread if not already going if (!hThread) { - hThread = gfxThreadCreate(waTimerThread, sizeof(waTimerThread), HIGH_PRIORITY, GTimerThreadHandler, NULL); + hThread = gfxThreadCreate(waTimerThread, sizeof(waTimerThread), GTIMER_PRIORITY, GTimerThreadHandler, NULL); if (hThread) gfxThreadClose(hThread); // We never really need the handle again } From d22bc07e7adf459b2b83fcd0e5bd6475c18e1e9a Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 12 Oct 2013 13:24:40 +1000 Subject: [PATCH 042/160] Multiple displays across one or more controllers is now fully supported. Only the Win32 driver supports this so far. Other drivers are currently broken due to API changes and will be fixed. --- drivers/multiple/Win32/gdisp_lld.c | 739 ++++--- drivers/multiple/Win32/gdisp_lld_config.h | 7 +- .../multiple/Win32/ginput_lld_toggle_config.h | 15 +- drivers/multiple/X/gdisp_lld_config.h | 9 +- gfxconf.example.h | 23 + include/gdisp/gdisp.h | 343 ++-- include/gdisp/lld/gdisp_lld.h | 319 ++- include/gdisp/options.h | 57 +- include/gfx_rules.h | 8 +- src/gdisp/gdisp.c | 1769 +++++++++-------- src/gfx.c | 1 - 11 files changed, 1862 insertions(+), 1428 deletions(-) diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 41141a90..65627e1c 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -9,12 +9,11 @@ * @file drivers/multiple/Win32/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for Win32. */ - #include "gfx.h" #if GFX_USE_GDISP -#define GDISP_LLD_DECLARATIONS +#define GDISP_DRIVER_VMT GDISPVMT_Win32 #include "gdisp/lld/gdisp_lld.h" #include @@ -31,51 +30,80 @@ #define GDISP_SCREEN_HEIGHT 480 #endif +#define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0) +#define GDISP_FLG_HASTOGGLE (GDISP_FLG_DRIVER<<1) +#define GDISP_FLG_HASMOUSE (GDISP_FLG_DRIVER<<2) + #if GINPUT_NEED_TOGGLE /* Include toggle support code */ #include "ginput/lld/toggle.h" #endif +#if GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 + #error "GDISP Win32: This driver currently only supports the RGB888 pixel format." +#endif + #if GINPUT_NEED_MOUSE /* Include mouse support code */ #include "ginput/lld/mouse.h" #endif +// Setting this to TRUE delays updating the screen +// to the windows paint routine. Due to the +// drawing lock this does not add as much speed +// as might be expected but it is still faster in +// all tested circumstances and for all operations +// even draw_pixel(). +// This is probably due to drawing operations being +// combined as the update regions are merged. +#define GDISP_WIN32_USE_INDIRECT_UPDATE TRUE + +// How far extra windows should be offset from the first. +#define DISPLAY_X_OFFSET 50 +#define DISPLAY_Y_OFFSET 50 + +static DWORD winThreadId; +static ATOM winClass; +static volatile bool_t QReady; +static HANDLE drawMutex; + + /*===========================================================================*/ /* Driver local routines . */ /*===========================================================================*/ -#define WIN32_USE_MSG_REDRAW FALSE #if GINPUT_NEED_TOGGLE #define WIN32_BUTTON_AREA 16 #else #define WIN32_BUTTON_AREA 0 #endif -#define APP_NAME "GDISP" +#define APP_NAME "uGFX" #define COLOR2BGR(c) ((((c) & 0xFF)<<16)|((c) & 0xFF00)|(((c)>>16) & 0xFF)) #define BGR2COLOR(c) COLOR2BGR(c) -static HWND winRootWindow = NULL; -static HDC dcBuffer = NULL; -static HBITMAP dcBitmap = NULL; -static HBITMAP dcOldBitmap; -static volatile bool_t isReady = FALSE; -static coord_t wWidth, wHeight; +typedef struct winPriv { + HWND hwnd; + HDC dcBuffer; + HBITMAP dcBitmap; + HBITMAP dcOldBitmap; + #if GINPUT_NEED_MOUSE + coord_t mousex, mousey; + uint16_t mousebuttons; + #endif + #if GINPUT_NEED_TOGGLE + uint8_t toggles; + #endif +} winPriv; -#if GINPUT_NEED_MOUSE - static coord_t mousex, mousey; - static uint16_t mousebuttons; -#endif -#if GINPUT_NEED_TOGGLE - static uint8_t toggles = 0; -#endif static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { - HDC dc; - PAINTSTRUCT ps; + HDC dc; + PAINTSTRUCT ps; + GDisplay * g; + winPriv * priv; #if GINPUT_NEED_TOGGLE HBRUSH hbrOn, hbrOff; HPEN pen; @@ -88,86 +116,135 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) switch (Msg) { case WM_CREATE: + // Get our GDisplay structure and attach it to the window + g = (GDisplay *)((LPCREATESTRUCT)lParam)->lpCreateParams; + priv = (winPriv *)g->priv; + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)g); + + // Fill in the private area + priv->hwnd = hWnd; + dc = GetDC(hWnd); + priv->dcBitmap = CreateCompatibleBitmap(dc, g->g.Width, g->g.Height); + priv->dcBuffer = CreateCompatibleDC(dc); + ReleaseDC(hWnd, dc); + priv->dcOldBitmap = SelectObject(priv->dcBuffer, priv->dcBitmap); + + // Mark the window as ready to go + g->flags |= GDISP_FLG_READY; break; - case WM_LBUTTONDOWN: - #if GINPUT_NEED_MOUSE - if ((coord_t)HIWORD(lParam) < wHeight) { - mousebuttons |= GINPUT_MOUSE_BTN_LEFT; - goto mousemove; - } - #endif - #if GINPUT_NEED_TOGGLE - bit = 1 << ((coord_t)LOWORD(lParam)*8/wWidth); - toggles ^= bit; - rect.left = 0; - rect.right = wWidth; - rect.top = wHeight; - rect.bottom = wHeight + WIN32_BUTTON_AREA; - InvalidateRect(hWnd, &rect, FALSE); - UpdateWindow(hWnd); - #if GINPUT_TOGGLE_POLL_PERIOD == TIME_INFINITE - ginputToggleWakeup(); + + #if GINPUT_NEED_MOUSE || GINPUT_NEED_TOGGLE + case WM_LBUTTONDOWN: + // Get our GDisplay structure + g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + priv = (winPriv *)g->priv; + + // Handle mouse down on the window + #if GINPUT_NEED_MOUSE + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + priv->mousebuttons |= GINPUT_MOUSE_BTN_LEFT; + goto mousemove; + } #endif - #endif - break; - case WM_LBUTTONUP: - #if GINPUT_NEED_TOGGLE - if ((toggles & 0x0F)) { - toggles &= ~0x0F; - rect.left = 0; - rect.right = wWidth; - rect.top = wHeight; - rect.bottom = wHeight + WIN32_BUTTON_AREA; - InvalidateRect(hWnd, &rect, FALSE); - UpdateWindow(hWnd); - #if GINPUT_TOGGLE_POLL_PERIOD == TIME_INFINITE - ginputToggleWakeup(); - #endif - } - #endif - #if GINPUT_NEED_MOUSE - if ((coord_t)HIWORD(lParam) < wHeight) { - mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT; + + // Handle mouse down on the toggle area + #if GINPUT_NEED_TOGGLE + if ((coord_t)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASTOGGLE)) { + bit = 1 << ((coord_t)LOWORD(lParam)*8/g->g.Width); + priv->toggles ^= bit; + rect.left = 0; + rect.right = GDISP_SCREEN_WIDTH; + rect.top = GDISP_SCREEN_HEIGHT; + rect.bottom = GDISP_SCREEN_HEIGHT + WIN32_BUTTON_AREA; + InvalidateRect(hWnd, &rect, FALSE); + UpdateWindow(hWnd); + #if GINPUT_TOGGLE_POLL_PERIOD == TIME_INFINITE + ginputToggleWakeup(); + #endif + } + #endif + break; + + case WM_LBUTTONUP: + // Get our GDisplay structure + g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + priv = (winPriv *)g->priv; + + // Handle mouse up on the toggle area + #if GINPUT_NEED_TOGGLE + if ((g->flags & GDISP_FLG_HASTOGGLE)) { + if ((priv->toggles & 0x0F)) { + priv->toggles &= ~0x0F; + rect.left = 0; + rect.right = GDISP_SCREEN_WIDTH; + rect.top = GDISP_SCREEN_HEIGHT; + rect.bottom = GDISP_SCREEN_HEIGHT + WIN32_BUTTON_AREA; + InvalidateRect(hWnd, &rect, FALSE); + UpdateWindow(hWnd); + #if GINPUT_TOGGLE_POLL_PERIOD == TIME_INFINITE + ginputToggleWakeup(); + #endif + } + } + #endif + + // Handle mouse up on the window + #if GINPUT_NEED_MOUSE + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + priv->mousebuttons &= ~GINPUT_MOUSE_BTN_LEFT; + goto mousemove; + } + #endif + break; + #endif + + #if GINPUT_NEED_MOUSE + case WM_MBUTTONDOWN: + g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + priv = (winPriv *)g->priv; + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + priv->mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE; goto mousemove; } - #endif - break; -#if GINPUT_NEED_MOUSE - case WM_MBUTTONDOWN: - if ((coord_t)HIWORD(lParam) < wHeight) { - mousebuttons |= GINPUT_MOUSE_BTN_MIDDLE; - goto mousemove; - } - break; - case WM_MBUTTONUP: - if ((coord_t)HIWORD(lParam) < wHeight) { - mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE; - goto mousemove; - } - break; - case WM_RBUTTONDOWN: - if ((coord_t)HIWORD(lParam) < wHeight) { - mousebuttons |= GINPUT_MOUSE_BTN_RIGHT; - goto mousemove; - } - break; - case WM_RBUTTONUP: - if ((coord_t)HIWORD(lParam) < wHeight) { - mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT; - goto mousemove; - } - break; - case WM_MOUSEMOVE: - if ((coord_t)HIWORD(lParam) >= wHeight) break; - mousemove: - mousex = (coord_t)LOWORD(lParam); - mousey = (coord_t)HIWORD(lParam); - #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE - ginputMouseWakeup(); - #endif - break; -#endif + case WM_MBUTTONUP: + g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + priv = (winPriv *)g->priv; + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + priv->mousebuttons &= ~GINPUT_MOUSE_BTN_MIDDLE; + goto mousemove; + } + break; + case WM_RBUTTONDOWN: + g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + priv = (winPriv *)g->priv; + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + priv->mousebuttons |= GINPUT_MOUSE_BTN_RIGHT; + goto mousemove; + } + break; + case WM_RBUTTONUP: + g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + priv = (winPriv *)g->priv; + if ((coord_t)HIWORD(lParam) < GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASMOUSE)) { + priv->mousebuttons &= ~GINPUT_MOUSE_BTN_RIGHT; + goto mousemove; + } + break; + case WM_MOUSEMOVE: + g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + priv = (winPriv *)g->priv; + if ((coord_t)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT || !(g->flags & GDISP_FLG_HASMOUSE)) + break; + mousemove: + priv->mousex = (coord_t)LOWORD(lParam); + priv->mousey = (coord_t)HIWORD(lParam); + #if GINPUT_MOUSE_POLL_PERIOD == TIME_INFINITE + ginputMouseWakeup(); + #endif + break; + #endif + case WM_SYSKEYDOWN: case WM_KEYDOWN: case WM_SYSKEYUP: @@ -178,26 +255,41 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) case WM_SYSCHAR: case WM_SYSDEADCHAR: break; + + case WM_ERASEBKGND: + // Pretend we have erased the background. + // We know we don't really need to do this as we + // redraw the entire surface in the WM_PAINT handler. + return TRUE; + case WM_PAINT: + // Get our GDisplay structure + g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + priv = (winPriv *)g->priv; + + // Paint the main window area + WaitForSingleObject(drawMutex, INFINITE); dc = BeginPaint(hWnd, &ps); BitBlt(dc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, - (ps.rcPaint.bottom > wHeight ? wHeight : ps.rcPaint.bottom) - ps.rcPaint.top, - dcBuffer, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY); + (ps.rcPaint.bottom > GDISP_SCREEN_HEIGHT ? GDISP_SCREEN_HEIGHT : ps.rcPaint.bottom) - ps.rcPaint.top, + priv->dcBuffer, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY); + + // Paint the toggle area #if GINPUT_NEED_TOGGLE - if (ps.rcPaint.bottom >= wHeight) { + if (ps.rcPaint.bottom >= GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASTOGGLE)) { pen = CreatePen(PS_SOLID, 1, COLOR2BGR(Black)); hbrOn = CreateSolidBrush(COLOR2BGR(Blue)); hbrOff = CreateSolidBrush(COLOR2BGR(Gray)); old = SelectObject(dc, pen); - MoveToEx(dc, 0, wHeight, &p); - LineTo(dc, wWidth, wHeight); + MoveToEx(dc, 0, GDISP_SCREEN_HEIGHT, &p); + LineTo(dc, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT); for(pos = 0, bit=1; pos < wWidth; pos=rect.right, bit <<= 1) { rect.left = pos; - rect.right = pos + wWidth/8; - rect.top = wHeight; - rect.bottom = wHeight + WIN32_BUTTON_AREA; - FillRect(dc, &rect, (toggles & bit) ? hbrOn : hbrOff); + rect.right = pos + GDISP_SCREEN_WIDTH/8; + rect.top = GDISP_SCREEN_HEIGHT; + rect.bottom = GDISP_SCREEN_HEIGHT + WIN32_BUTTON_AREA; + FillRect(dc, &rect, (priv->toggles & bit) ? hbrOn : hbrOff); if (pos > 0) { MoveToEx(dc, rect.left, rect.top, &p); LineTo(dc, rect.left, rect.bottom); @@ -209,74 +301,75 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) } #endif EndPaint(hWnd, &ps); + ReleaseMutex(drawMutex); break; + case WM_DESTROY: + // Get our GDisplay structure + g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA); + priv = (winPriv *)g->priv; + + // Restore the window and free our bitmaps + SelectObject(priv->dcBuffer, priv->dcOldBitmap); + DeleteDC(priv->dcBuffer); + DeleteObject(priv->dcBitmap); + + // Cleanup the private area + gfxFree(priv); + + // Quit the application PostQuitMessage(0); - SelectObject(dcBuffer, dcOldBitmap); - DeleteDC(dcBuffer); - DeleteObject(dcBitmap); - winRootWindow = NULL; + + // Actually the above doesn't work (who knows why) + ExitProcess(0); break; + default: return DefWindowProc(hWnd, Msg, wParam, lParam); } return 0; } -static void InitWindow(void) { - HANDLE hInstance; - WNDCLASS wc; - RECT rect; - HDC dc; - - hInstance = GetModuleHandle(NULL); - - wc.style = CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC; - wc.lpfnWndProc = (WNDPROC)myWindowProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = hInstance; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = GetStockObject(WHITE_BRUSH); - wc.lpszMenuName = NULL; - wc.lpszClassName = APP_NAME; - RegisterClass(&wc); - - rect.top = 0; rect.bottom = wHeight+WIN32_BUTTON_AREA; - rect.left = 0; rect.right = wWidth; - AdjustWindowRect(&rect, WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, 0); - winRootWindow = CreateWindow(APP_NAME, "", WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, 0, 0, - rect.right-rect.left, rect.bottom-rect.top, 0, 0, hInstance, NULL); - assert(winRootWindow != NULL); - - - GetClientRect(winRootWindow, &rect); - wWidth = rect.right-rect.left; - wHeight = rect.bottom - rect.top - WIN32_BUTTON_AREA; - - dc = GetDC(winRootWindow); - dcBitmap = CreateCompatibleBitmap(dc, wWidth, wHeight); - dcBuffer = CreateCompatibleDC(dc); - ReleaseDC(winRootWindow, dc); - dcOldBitmap = SelectObject(dcBuffer, dcBitmap); - - ShowWindow(winRootWindow, SW_SHOW); - UpdateWindow(winRootWindow); - isReady = TRUE; -} - static DECLARE_THREAD_STACK(waWindowThread, 1024); static DECLARE_THREAD_FUNCTION(WindowThread, param) { (void)param; MSG msg; - InitWindow(); + // Establish this thread as a message queue thread + winThreadId = GetCurrentThreadId(); + PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + QReady = TRUE; + do { gfxSleepMilliseconds(1); while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); + // Is this our special thread message to create a new window? + if (!msg.hwnd && msg.message == WM_USER) { + RECT rect; + GDisplay *g; + + g = (GDisplay *)msg.lParam; + + // Set the window rectangle + rect.top = 0; rect.bottom = g->g.Height; + rect.left = 0; rect.right = g->g.Width; + #if GINPUT_NEED_TOGGLE + if ((g->flags & GDISP_FLG_HASTOGGLE)) + rect.bottom += WIN32_BUTTON_AREA; + #endif + AdjustWindowRect(&rect, WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, 0); + + // Create the window + msg.hwnd = CreateWindow(APP_NAME, "", WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_BORDER, msg.wParam*DISPLAY_X_OFFSET, msg.wParam*DISPLAY_Y_OFFSET, + rect.right-rect.left, rect.bottom-rect.top, 0, 0, + GetModuleHandle(NULL), g); + assert(msg.hwnd != NULL); + + // Or just a normal window message + } else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } } } while (msg.message != WM_QUIT); ExitProcess(0); @@ -287,44 +380,89 @@ static DECLARE_THREAD_FUNCTION(WindowThread, param) { /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { - RECT rect; - gfxThreadHandle hth; +LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { + winPriv * priv; + char buf[132]; - /* Set the window dimensions */ - GetWindowRect(GetDesktopWindow(), &rect); - wWidth = rect.right - rect.left; - wHeight = rect.bottom - rect.top - WIN32_BUTTON_AREA; - if (wWidth > GDISP_SCREEN_WIDTH) - wWidth = GDISP_SCREEN_WIDTH; - if (wHeight > GDISP_SCREEN_HEIGHT) - wHeight = GDISP_SCREEN_HEIGHT; + // Initialise the window thread and the window class (if it hasn't been done already) + if (!QReady) { + gfxThreadHandle hth; + WNDCLASS wc; - /* Initialise the window */ - if (!(hth = gfxThreadCreate(waWindowThread, sizeof(waWindowThread), HIGH_PRIORITY, WindowThread, 0))) { - fprintf(stderr, "Cannot create window thread\n"); - exit(-1); + // Create the draw mutex + drawMutex = CreateMutex(NULL, FALSE, NULL); + + // Create the thread + hth = gfxThreadCreate(waWindowThread, sizeof(waWindowThread), HIGH_PRIORITY, WindowThread, 0); + assert(hth != NULL); + gfxThreadClose(hth); + + wc.style = CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC; + wc.lpfnWndProc = (WNDPROC)myWindowProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetModuleHandle(NULL); + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = APP_NAME; + winClass = RegisterClass(&wc); + assert(winClass != 0); + + // Wait for our thread to be ready + while (!QReady) + Sleep(1); } - gfxThreadClose(hth); - while (!isReady) - Sleep(1); - /* Initialise the GDISP structure to match */ + // Initialise the GDISP structure g->g.Orientation = GDISP_ROTATE_0; g->g.Powermode = powerOn; g->g.Backlight = 100; g->g.Contrast = 50; - g->g.Width = wWidth; - g->g.Height = wHeight; + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + + // Turn on toggles for the first GINPUT_TOGGLE_CONFIG_ENTRIES windows + #if GINPUT_NEED_TOGGLE + if (display < GINPUT_TOGGLE_CONFIG_ENTRIES) + g->flags |= GDISP_FLG_HASTOGGLE; + #endif + + // Only turn on mouse on the first window for now + #if GINPUT_NEED_MOUSE + if (!display) + g->flags |= GDISP_FLG_HASMOUSE; + #endif + + // Create a private area for this window + priv = (winPriv *)gfxAlloc(sizeof(winPriv)); + assert(priv != NULL); + memset(priv, 0, sizeof(winPriv)); + g->priv = priv; + + // Create the window in the message thread + PostThreadMessage(winThreadId, WM_USER, (WPARAM)display, (LPARAM)g); + + // Wait for the window creation to complete (for safety) + while(!(((volatile GDisplay *)g)->flags & GDISP_FLG_READY)) + Sleep(1); + + sprintf(buf, APP_NAME " - %u", display+1); + SetWindowText(priv->hwnd, buf); + ShowWindow(priv->hwnd, SW_SHOW); + UpdateWindow(priv->hwnd); + return TRUE; } #if GDISP_HARDWARE_DRAWPIXEL - LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) { - HDC dcScreen; + LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + winPriv * priv; int x, y; COLORREF color; + priv = g->priv; color = COLOR2BGR(g->p.color); #if GDISP_NEED_CONTROL @@ -352,23 +490,41 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif // Draw the pixel on the screen and in the buffer. - dcScreen = GetDC(winRootWindow); - SetPixel(dcScreen, x, y, color); - SetPixel(dcBuffer, x, y, color); - ReleaseDC(winRootWindow, dcScreen); + WaitForSingleObject(drawMutex, INFINITE); + SetPixel(priv->dcBuffer, x, y, color); + #if GDISP_WIN32_USE_INDIRECT_UPDATE + ReleaseMutex(drawMutex); + { + RECT r; + r.left = g->p.x; r.right = g->p.x+1; + r.top = g->p.y; r.bottom = g->p.y+1; + InvalidateRect(priv->hwnd, &r, FALSE); + } + #else + { + HDC dc; + dc = GetDC(priv->hwnd); + SetPixel(dc, x, y, color); + ReleaseDC(priv->hwnd, dc); + ReleaseMutex(drawMutex); + } + #endif } #endif /* ---- Optional Routines ---- */ #if GDISP_HARDWARE_FILLS - LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { - HDC dcScreen; + LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { + winPriv * priv; RECT rect; HBRUSH hbr; COLORREF color; + priv = g->priv; color = COLOR2BGR(g->p.color); + hbr = CreateSolidBrush(color); + #if GDISP_NEED_CONTROL switch(g->g.Orientation) { case GDISP_ROTATE_0: @@ -403,29 +559,34 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.right = rect.left + g->p.cx; #endif - hbr = CreateSolidBrush(color); - dcScreen = GetDC(winRootWindow); - FillRect(dcScreen, &rect, hbr); - FillRect(dcBuffer, &rect, hbr); - ReleaseDC(winRootWindow, dcScreen); + WaitForSingleObject(drawMutex, INFINITE); + FillRect(priv->dcBuffer, &rect, hbr); + #if GDISP_WIN32_USE_INDIRECT_UPDATE + ReleaseMutex(drawMutex); + InvalidateRect(priv->hwnd, &rect, FALSE); + #else + { + HDC dc; + dc = GetDC(priv->hwnd); + FillRect(dc, &rect, hbr); + ReleaseDC(priv->hwnd, dc); + ReleaseMutex(drawMutex); + } + #endif DeleteObject(hbr); } #endif #if GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL - static pixel_t *rotateimg(GDISPDriver *g, const pixel_t *buffer) { + static pixel_t *rotateimg(GDisplay *g, const pixel_t *buffer) { pixel_t *dstbuf; pixel_t *dst; const pixel_t *src; size_t sz; coord_t i, j; - // Shortcut. - if (g->g.Orientation == GDISP_ROTATE_0 && g->p.x1 == 0 && g->p.cx == g->p.x2) - return (pixel_t *)buffer; - // Allocate the destination buffer sz = (size_t)g->p.cx * (size_t)g->p.cy; if (!(dstbuf = (pixel_t *)malloc(sz * sizeof(pixel_t)))) @@ -433,11 +594,6 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { // Copy the bits we need switch(g->g.Orientation) { - case GDISP_ROTATE_0: - for(dst = dstbuf, src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) - for(i = 0; i < g->p.cx; i++) - *dst++ = *src++; - break; case GDISP_ROTATE_90: for(src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) { dst = dstbuf+sz-g->p.cy+j; @@ -463,16 +619,14 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif #if GDISP_HARDWARE_BITFILLS - LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g) { - BITMAPV4HEADER bmpInfo; - HDC dcScreen; - pixel_t * buffer; - #if GDISP_NEED_CONTROL - RECT rect; - pixel_t * srcimg; - #endif + LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { + winPriv * priv; + pixel_t * buffer; + RECT rect; + BITMAPV4HEADER bmpInfo; // Make everything relative to the start of the line + priv = g->priv; buffer = g->p.ptr; buffer += g->p.x2*g->p.y1; @@ -492,13 +646,10 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { bmpInfo.bV4CSType = 0; //LCS_sRGB; #if GDISP_NEED_CONTROL - bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(pixel_t); - srcimg = rotateimg(g, buffer); - if (!srcimg) return; - switch(g->g.Orientation) { case GDISP_ROTATE_0: - bmpInfo.bV4Width = g->p.cx; + bmpInfo.bV4SizeImage = (g->p.cy*g->p.x2) * sizeof(pixel_t); + bmpInfo.bV4Width = g->p.x2; bmpInfo.bV4Height = -g->p.cy; /* top-down image */ rect.top = g->p.y; rect.bottom = rect.top+g->p.cy; @@ -506,6 +657,8 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.right = rect.left+g->p.cx; break; case GDISP_ROTATE_90: + if (!(buffer = rotateimg(g, buffer))) return; + bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(pixel_t); bmpInfo.bV4Width = g->p.cy; bmpInfo.bV4Height = -g->p.cx; /* top-down image */ rect.bottom = g->g.Width - g->p.x; @@ -514,6 +667,8 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.right = rect.left+g->p.cy; break; case GDISP_ROTATE_180: + if (!(buffer = rotateimg(g, buffer))) return; + bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(pixel_t); bmpInfo.bV4Width = g->p.cx; bmpInfo.bV4Height = -g->p.cy; /* top-down image */ rect.bottom = g->g.Height-1 - g->p.y; @@ -522,6 +677,8 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.left = rect.right-g->p.cx; break; case GDISP_ROTATE_270: + if (!(buffer = rotateimg(g, buffer))) return; + bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(pixel_t); bmpInfo.bV4Width = g->p.cy; bmpInfo.bV4Height = -g->p.cx; /* top-down image */ rect.top = g->p.x; @@ -530,58 +687,78 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.left = rect.right-g->p.cy; break; } - dcScreen = GetDC(winRootWindow); - SetDIBitsToDevice(dcBuffer, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, srcimg, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); - SetDIBitsToDevice(dcScreen, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, srcimg, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); - ReleaseDC(winRootWindow, dcScreen); - if (srcimg != buffer) - free(srcimg); - #else + bmpInfo.bV4SizeImage = (g->p.cy*g->p.x2) * sizeof(pixel_t); bmpInfo.bV4Width = g->p.x2; bmpInfo.bV4Height = -g->p.cy; /* top-down image */ - bmpInfo.bV4SizeImage = (g->p.cy*g->p.x2) * sizeof(pixel_t); - dcScreen = GetDC(winRootWindow); - SetDIBitsToDevice(dcBuffer, g->p.x, g->p.y, g->p.cx, g->p.cy, g->p.x1, 0, 0, g->p.cy, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); - SetDIBitsToDevice(dcScreen, g->p.x, g->p.y, g->p.cx, g->p.cy, g->p.x1, 0, 0, g->p.cy, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); - ReleaseDC(winRootWindow, dcScreen); + rect.top = g->p.y; + rect.bottom = rect.top+g->p.cy; + rect.left = g->p.x; + rect.right = rect.left+g->p.cx; + #endif + + WaitForSingleObject(drawMutex, INFINITE); + SetDIBitsToDevice(priv->dcBuffer, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); + #if GDISP_WIN32_USE_INDIRECT_UPDATE + ReleaseMutex(drawMutex); + InvalidateRect(priv->hwnd, &rect, FALSE); + #else + { + HDC dc; + dc = GetDC(priv->hwnd); + SetDIBitsToDevice(dc, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS); + ReleaseDC(priv->hwnd, dc); + ReleaseMutex(drawMutex); + } + #endif + + #if GDISP_NEED_CONTROL + if (buffer != (pixel_t *)g->p.ptr) + free(srcimg); #endif } #endif #if GDISP_HARDWARE_PIXELREAD - LLDSPEC color_t gdisp_lld_get_pixel_color(GDISPDriver *g) { + LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { + winPriv * priv; COLORREF color; + priv = g->priv; + + WaitForSingleObject(drawMutex, INFINITE); #if GDISP_NEED_CONTROL switch(g->g.Orientation) { case GDISP_ROTATE_0: - color = GetPixel(dcBuffer, g->p.x, g->p.y); + color = GetPixel(priv->dcBuffer, g->p.x, g->p.y); break; case GDISP_ROTATE_90: - color = GetPixel(dcBuffer, g->p.y, g->g.Width - 1 - g->p.x); + color = GetPixel(priv->dcBuffer, g->p.y, g->g.Width - 1 - g->p.x); break; case GDISP_ROTATE_180: - color = GetPixel(dcBuffer, g->g.Width - 1 - g->p.x, g->g.Height - 1 - g->p.y); + color = GetPixel(priv->dcBuffer, g->g.Width - 1 - g->p.x, g->g.Height - 1 - g->p.y); break; case GDISP_ROTATE_270: - color = GetPixel(dcBuffer, g->g.Height - 1 - g->p.y, g->p.x); + color = GetPixel(priv->dcBuffer, g->g.Height - 1 - g->p.y, g->p.x); break; } #else - color = GetPixel(dcBuffer, g->p.x, g->p.y); + color = GetPixel(priv->dcBuffer, g->p.x, g->p.y); #endif + ReleaseMutex(drawMutex); return BGR2COLOR(color); } #endif #if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL - LLDSPEC void gdisp_lld_vertical_scroll(GDISPDriver *g) { - HDC dcScreen; + LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g) { + winPriv * priv; RECT rect; coord_t lines; + priv = g->priv; + #if GDISP_NEED_CONTROL switch(GC->g.Orientation) { case GDISP_ROTATE_0: @@ -611,10 +788,20 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.top -= lines; } if (g->p.cy >= lines && g->p.cy >= -lines) { - dcScreen = GetDC(winRootWindow); - ScrollDC(dcBuffer, 0, lines, &rect, 0, 0, 0); - ScrollDC(dcScreen, 0, lines, &rect, 0, 0, 0); - ReleaseDC(winRootWindow, dcScreen); + WaitForSingleObject(drawMutex, INFINITE); + ScrollDC(priv->dcBuffer, 0, lines, &rect, 0, 0, 0); + #if GDISP_WIN32_USE_INDIRECT_UPDATE + ReleaseMutex(drawMutex); + InvalidateRect(priv->hwnd, &rect, FALSE); + #else + { + HDC dc; + dc = GetDC(priv->hwnd); + ScrollDC(dc, 0, lines, &rect, 0, 0, 0); + ReleaseDC(priv->hwnd, dc); + ReleaseMutex(drawMutex); + } + #endif } break; case GDISP_ROTATE_270: @@ -630,10 +817,20 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.left -= lines; } if (g->p.cy >= lines && g->p.cy >= -lines) { - dcScreen = GetDC(winRootWindow); - ScrollDC(dcBuffer, lines, 0, &rect, 0, 0, 0); - ScrollDC(dcScreen, lines, 0, &rect, 0, 0, 0); - ReleaseDC(winRootWindow, dcScreen); + WaitForSingleObject(drawMutex, INFINITE); + ScrollDC(priv->dcBuffer, lines, 0, &rect, 0, 0, 0); + #if GDISP_WIN32_USE_INDIRECT_UPDATE + ReleaseMutex(drawMutex); + InvalidateRect(priv->hwnd, &rect, FALSE); + #else + { + HDC dc; + dc = GetDC(priv->hwnd); + ScrollDC(dc, lines, 0, &rect, 0, 0, 0); + ReleaseDC(priv->hwnd, dc); + ReleaseMutex(drawMutex); + } + #endif } break; } @@ -649,17 +846,27 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { rect.top -= lines; } if (g->p.cy >= lines && g->p.cy >= -lines) { - dcScreen = GetDC(winRootWindow); - ScrollDC(dcBuffer, 0, lines, &rect, 0, 0, 0); - ScrollDC(dcScreen, 0, lines, &rect, 0, 0, 0); - ReleaseDC(winRootWindow, dcScreen); + WaitForSingleObject(drawMutex, INFINITE); + ScrollDC(priv->dcBuffer, 0, lines, &rect, 0, 0, 0); + #if GDISP_WIN32_USE_INDIRECT_UPDATE + ReleaseMutex(drawMutex); + InvalidateRect(priv->hwnd, &rect, FALSE); + #else + { + HDC dc; + dc = GetDC(priv->hwnd); + ScrollDC(dc, 0, lines, &rect, 0, 0, 0); + ReleaseDC(priv->hwnd, dc); + ReleaseMutex(drawMutex); + } + #endif } #endif } #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + LLDSPEC void gdisp_lld_control(GDisplay *g) { switch(g->p.x) { case GDISP_CONTROL_ORIENTATION: if (g->g.Orientation == (orientation_t)g->p.ptr) @@ -667,13 +874,13 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: case GDISP_ROTATE_180: - g->g.Width = wWidth; - g->g.Height = wHeight; + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_90: case GDISP_ROTATE_270: - g->g.Height = wWidth; - g->g.Width = wHeight; + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; break; default: return; @@ -692,20 +899,38 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #if GINPUT_NEED_MOUSE void ginput_lld_mouse_init(void) {} void ginput_lld_mouse_get_reading(MouseReading *pt) { - pt->x = mousex; - pt->y = mousey > wHeight ? wHeight : mousey; - pt->z = (mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; - pt->buttons = mousebuttons; + GDisplay *g; + + g = GDISP_WIN32; + pt->x = g->priv->mousex; + pt->y = g->priv->mousey > g->g.Height ? g->g.Height : mousey; + pt->z = (g->priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; + pt->buttons = g->priv->mousebuttons; } #endif /* GINPUT_NEED_MOUSE */ #if GINPUT_NEED_TOGGLE - const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES] = { - {0, 0xFF, 0x00, 0}, - }; - void ginput_lld_toggle_init(const GToggleConfig *ptc) { (void) ptc; } - unsigned ginput_lld_toggle_getbits(const GToggleConfig *ptc) { (void) ptc; return toggles; } -#endif /* GINPUT_NEED_MOUSE */ + #if GINPUT_TOGGLE_CONFIG_ENTRIES > GDISP_DRIVER_COUNT_WIN32 + #error "GDISP Win32: GINPUT_TOGGLE_CONFIG_ENTRIES must not be greater than GDISP_DRIVER_COUNT_WIN32" + #endif + + GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES]; + + void ginput_lld_toggle_init(const GToggleConfig *ptc) { + // Save the associated window struct + ptc->id = &GDISP_WIN32[ptc - GInputToggleConfigTable]; + + // We have 8 buttons per window. + ptc->mask = 0xFF; + + // No inverse or special mode + ptc->invert = 0x00; + ptc->mode = 0; + } + unsigned ginput_lld_toggle_getbits(const GToggleConfig *ptc) { + return ((GDisplay *)(ptc->id))->priv->toggles; + } +#endif /* GINPUT_NEED_TOGGLE */ #endif /* GFX_USE_GDISP */ diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h index b8a030ef..5720eaed 100644 --- a/drivers/multiple/Win32/gdisp_lld_config.h +++ b/drivers/multiple/Win32/gdisp_lld_config.h @@ -16,15 +16,12 @@ #ifndef _GDISP_LLD_CONFIG_H #define _GDISP_LLD_CONFIG_H -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP /*===========================================================================*/ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "Win32" -#define GDISP_DRIVER_STRUCT GDISP_Win32 - #define GDISP_HARDWARE_DRAWPIXEL TRUE #define GDISP_HARDWARE_FILLS TRUE #define GDISP_HARDWARE_PIXELREAD TRUE @@ -32,7 +29,7 @@ #define GDISP_HARDWARE_BITFILLS TRUE #define GDISP_HARDWARE_SCROLL TRUE -#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 +#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 #endif /* GFX_USE_GDISP */ diff --git a/drivers/multiple/Win32/ginput_lld_toggle_config.h b/drivers/multiple/Win32/ginput_lld_toggle_config.h index 2e61d073..dd0c9b5c 100644 --- a/drivers/multiple/Win32/ginput_lld_toggle_config.h +++ b/drivers/multiple/Win32/ginput_lld_toggle_config.h @@ -20,9 +20,16 @@ #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE -#define GINPUT_TOGGLE_POLL_PERIOD TIME_INFINITE // We are interrupt driven (or polled - ether works here) -#define GINPUT_TOGGLE_NUM_PORTS 8 // The total number of toggle inputs -#define GINPUT_TOGGLE_CONFIG_ENTRIES 1 // The total number of GToggleConfig entries +#define GINPUT_TOGGLE_POLL_PERIOD TIME_INFINITE // We are interrupt driven (or polled - either works here) + +// This driver is unique in that it can support 8 buttons per window across multiple windows. +// GINPUT_TOGGLE_CONFIG_ENTRIES just must be less than the number of GDISP windows (GDISP_DRIVER_COUNT_WIN32). +#ifndef GINPUT_TOGGLE_CONFIG_ENTRIES + #define GINPUT_TOGGLE_CONFIG_ENTRIES 1 // The total number of GToggleConfig entries +#endif + +// The total number of toggle inputs +#define GINPUT_TOGGLE_NUM_PORTS (8 * GINPUT_TOGGLE_CONFIG_ENTRIES) #define GINPUT_TOGGLE_SW1 0 // Switch 1 - Toggle #define GINPUT_TOGGLE_SW2 1 // Switch 2 - Toggle @@ -33,6 +40,8 @@ #define GINPUT_TOGGLE_MOMENTARY2 5 // Switch 6 - Momentary #define GINPUT_TOGGLE_MOMENTARY3 6 // Switch 7 - Momentary #define GINPUT_TOGGLE_MOMENTARY4 7 // Switch 8 - Momentary + +// This pattern of switch and momentary action is repeated across all windows. #endif /* GFX_USE_GDISP && GINPUT_NEED_TOGGLE */ diff --git a/drivers/multiple/X/gdisp_lld_config.h b/drivers/multiple/X/gdisp_lld_config.h index 0bd76a2c..7c04b1b9 100644 --- a/drivers/multiple/X/gdisp_lld_config.h +++ b/drivers/multiple/X/gdisp_lld_config.h @@ -22,7 +22,12 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "Linux emulator - X11" +#ifndef GDISP_DRIVER_COUNT_X11 + #define GDISP_DRIVER_COUNT_X11 1 +#endif +#define GDISP_DRIVER_COUNT GDISP_DRIVER_COUNT_X11 + +#define GDISP_DRIVER_NAME "Linux emulator - X11" #define GDISP_DRIVER_STRUCT GDISP_X11 #define GDISP_HARDWARE_DRAWPIXEL TRUE @@ -32,7 +37,7 @@ #define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_HARDWARE_CONTROL FALSE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 +#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 #endif /* GFX_USE_GDISP */ diff --git a/gfxconf.example.h b/gfxconf.example.h index e6be90db..f3a1e165 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -141,6 +141,29 @@ #define GMISC_NEED_FIXEDTRIG FALSE #define GMISC_NEED_INVSQRT FALSE +/* Optional Multiple Display support */ +/* + #define GDISP_TOTAL_DISPLAYS 1 + #define GDISP_TOTAL_CONTROLLERS 1 + + // Extra stuff needed for when GDISP_TOTAL_CONTROLLERS > 1 + #define GDISP_CONTROLLER_LIST GDISPVMT_Win32, GDISPVMT_Win32 + #define GDISP_CONTROLLER_DISPLAYS 1, 1 + #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 + #define GDISP_HARDWARE_STREAM_WRITE FALSE + #define GDISP_HARDWARE_STREAM_READ FALSE + #define GDISP_HARDWARE_STREAM_POS FALSE + #define GDISP_HARDWARE_DRAWPIXEL FALSE + #define GDISP_HARDWARE_CLEARS FALSE + #define GDISP_HARDWARE_FILLS FALSE + #define GDISP_HARDWARE_BITFILLS FALSE + #define GDISP_HARDWARE_SCROLL FALSE + #define GDISP_HARDWARE_PIXELREAD FALSE + #define GDISP_HARDWARE_CONTROL FALSE + #define GDISP_HARDWARE_QUERY FALSE + #define GDISP_HARDWARE_CLIP FALSE +*/ + /* Optional Parameters for various subsystems */ /* #define GDISP_LINEBUF_SIZE 128 diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index 6b2f5b47..7f0f8012 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -17,6 +17,10 @@ * * @pre GFX_USE_GDISP must be set to TRUE in gfxconf.h * + * @note Each drawing routine supports a gispXXXX and a gdispGXXXX function. The difference is that the + * gdispXXXX function does not require a display to be specified. Note there is a slight anomoly + * in the naming with gdispGBlitArea() vs gdispBlitAreaEx() and gdispBlitArea(), the later of + * which is now deprecated. * @{ */ @@ -79,7 +83,18 @@ typedef struct GDISPControl { uint8_t Contrast; } GDISPControl; -extern GDISPControl *GDISP; +/* + * Our black box display structure. We know only one thing about it... + * The first member is a GDISPControl structure. + */ +typedef struct GDisplay GDisplay; + +/** + * @brief The default screen to use for the gdispXXXX calls. + * @note This is set by default to the first display in the system. You can change + * it by calling @p gdispGSetDisplay(). + */ +extern GDisplay *GDISP; /*===========================================================================*/ /* Constants. */ @@ -150,75 +165,69 @@ extern GDISPControl *GDISP; /* Defines relating to the display hardware */ /*===========================================================================*/ -#if GDISP_MULTIPLE_DRIVERS || defined(__DOXYGEN__) - /** - * @name GDISP pixel format choices - * @{ - */ - /** - * @brief The pixel format. - * @default It generally defaults to the hardware pixel format. - * @note This doesn't need to match the hardware pixel format. - * It is definitely more efficient when it does. - * @note When GDISP_MULTIPLE_DRIVERS is defined, this should - * also be explicitly defined to ensure the best match - * with your hardware across all devices. - * @note Should be set to one of the following: - * GDISP_PIXELFORMAT_RGB565 - * GDISP_PIXELFORMAT_BGR565 - * GDISP_PIXELFORMAT_RGB888 - * GDISP_PIXELFORMAT_RGB444 - * GDISP_PIXELFORMAT_RGB332 - * GDISP_PIXELFORMAT_RGB666 - * GDISP_PIXELFORMAT_CUSTOM - * @note If you set GDISP_PIXELFORMAT_CUSTOM you need to also define - * color_t, RGB2COLOR(r,g,b), HTML2COLOR(h), - * RED_OF(c), GREEN_OF(c), BLUE_OF(c), - * COLOR(c) and MASKCOLOR. - */ - #ifndef GDISP_PIXELFORMAT - #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_ERROR - #endif - /** - * @brief Do pixels require packing for a blit - * @note Is only valid for a pixel format that doesn't fill it's datatype. ie formats: - * GDISP_PIXELFORMAT_RGB888 - * GDISP_PIXELFORMAT_RGB444 - * GDISP_PIXELFORMAT_RGB666 - * GDISP_PIXELFORMAT_CUSTOM - * @note If you use GDISP_PIXELFORMAT_CUSTOM and packed bit fills - * you need to also define @p gdispPackPixels(buf,cx,x,y,c) - * @note If you are using GDISP_HARDWARE_BITFILLS = FALSE then the pixel - * format must not be a packed format as the software blit does - * not support packed pixels - * @note Very few cases should actually require packed pixels as the low - * level driver can also pack on the fly as it is sending it - * to the graphics device. - */ - #ifndef GDISP_PACKED_PIXELS - #define GDISP_PACKED_PIXELS FALSE - #endif - - /** - * @brief Do lines of pixels require packing for a blit - * @note Ignored if GDISP_PACKED_PIXELS is FALSE - */ - #ifndef GDISP_PACKED_LINES - #define GDISP_PACKED_LINES FALSE - #endif - /** @} */ -#else +#if !defined(GDISP_TOTAL_CONTROLLERS) || GDISP_TOTAL_CONTROLLERS == 1 + // Pull in the default hardware configuration for a single controller. + // If we have multiple controllers the settings must be set in the + // users gfxconf.h file. #include "gdisp_lld_config.h" +#endif + +/** + * @name GDISP pixel format choices + * @{ + */ + /** + * @brief The pixel format. + * @default It generally defaults to the hardware pixel format. + * @note This doesn't need to match the hardware pixel format. + * It is definitely more efficient when it does. + * @note When GDISP_TOTAL_CONTROLLERS > 1, this should + * also be explicitly defined to ensure the best match + * with your hardware across all devices. + * @note Should be set to one of the following: + * GDISP_PIXELFORMAT_RGB565 + * GDISP_PIXELFORMAT_BGR565 + * GDISP_PIXELFORMAT_RGB888 + * GDISP_PIXELFORMAT_RGB444 + * GDISP_PIXELFORMAT_RGB332 + * GDISP_PIXELFORMAT_RGB666 + * GDISP_PIXELFORMAT_CUSTOM + * @note If you set GDISP_PIXELFORMAT_CUSTOM you need to also define + * color_t, RGB2COLOR(r,g,b), HTML2COLOR(h), + * RED_OF(c), GREEN_OF(c), BLUE_OF(c), + * COLOR(c) and MASKCOLOR. + */ #ifndef GDISP_PIXELFORMAT - #define GDISP_PIXELFORMAT GDISP_LLD_PIXELFORMAT + #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_ERROR #endif + /** + * @brief Do pixels require packing for a blit + * @note Is only valid for a pixel format that doesn't fill it's datatype. ie formats: + * GDISP_PIXELFORMAT_RGB888 + * GDISP_PIXELFORMAT_RGB444 + * GDISP_PIXELFORMAT_RGB666 + * GDISP_PIXELFORMAT_CUSTOM + * @note If you use GDISP_PIXELFORMAT_CUSTOM and packed bit fills + * you need to also define @p gdispPackPixels(buf,cx,x,y,c) + * @note If you are using GDISP_HARDWARE_BITFILLS = FALSE then the pixel + * format must not be a packed format as the software blit does + * not support packed pixels + * @note Very few cases should actually require packed pixels as the low + * level driver can also pack on the fly as it is sending it + * to the graphics device. + */ #ifndef GDISP_PACKED_PIXELS #define GDISP_PACKED_PIXELS FALSE #endif + + /** + * @brief Do lines of pixels require packing for a blit + * @note Ignored if GDISP_PACKED_PIXELS is FALSE + */ #ifndef GDISP_PACKED_LINES #define GDISP_PACKED_LINES FALSE #endif -#endif +/** @} */ /*===========================================================================*/ /* Defines related to the pixel format */ @@ -356,48 +365,68 @@ extern "C" { */ color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); +/** + * @brief Set the current default display to the specified display + * @note The default display is used for the gdispXxxx functions. + * @note Displays are numbered from 0 to GDISP_TOTAL_DISPLAYS - 1 + * @note If an invalid display number is specified the request is ignored. + * + * @param[in] display The display number (0..n) + * + * @api + */ +void gdispSetDisplay(unsigned display); + /* Drawing Functions */ /** * @brief Clear the display to the specified color. * + * @param[in] g The display to use * @param[in] color The color to use when clearing the screen * * @api */ -void gdispClear(color_t color); +void gdispGClear(GDisplay *g, color_t color); +#define gdispClear(c) gdispGClear(GDISP, c) /** * @brief Set a pixel in the specified color. * + * @param[in] g The display to use * @param[in] x,y The position to set the pixel. * @param[in] color The color to use * * @api */ -void gdispDrawPixel(coord_t x, coord_t y, color_t color); +void gdispGDrawPixel(GDisplay *g, coord_t x, coord_t y, color_t color); +#define gdispDrawPixel(x,y,c) gdispGDrawPixel(GDISP,x,y,c) /** * @brief Draw a line. * + * @param[in] g The display to use * @param[in] x0,y0 The start position * @param[in] x1,y1 The end position * @param[in] color The color to use * * @api */ -void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); +void gdispGDrawLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); +#define gdispDrawLine(x0,y0,x1,y1,c) gdispGDrawLine(GDISP,x0,y0,x1,y1,c) /** * @brief Fill an area with a color. * + * @param[in] g The display to use * @param[in] x,y The start position * @param[in] cx,cy The size of the box (outside dimensions) * @param[in] color The color to use * * @api */ -void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); +void gdispGFillArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); +#define gdispFillArea(x,y,cx,cy,c) gdispGFillArea(GDISP,x,y,cx,cy,c) /** * @brief Fill an area using the supplied bitmap. @@ -409,6 +438,7 @@ void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * or at least retained until this call has finished the blit. You can * tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE. * + * @param[in] g The display to use * @param[in] x,y The start position * @param[in] cx,cy The size of the filled area * @param[in] srcx,srcy The bitmap position to start the fill form @@ -417,18 +447,21 @@ void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ -void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer); +void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer); +#define gdispBlitAreaEx(x,y,cx,cy,sx,sy,rx,b) gdispGBlitArea(GDISP,x,y,cx,cy,sx,sy,rx,b) /** * @brief Draw a rectangular box. * + * @param[in] g The display to use * @param[in] x,y The start position * @param[in] cx,cy The size of the box (outside dimensions) * @param[in] color The color to use * * @api */ -void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); +void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); +#define gdispDrawBox(x,y,cx,cy,c) gdispGDrawBox(GDISP,x,y,cx,cy,c) /* Streaming Functions */ @@ -450,12 +483,14 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * @note A streaming operation may be terminated early (without writing to every location * in the stream area) by calling @p gdispStreamStop(). * + * @param[in] g The display to use * @param[in] x,y The start position * @param[in] cx,cy The size of the streamable area * * @api */ - void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy); + void gdispGStreamStart(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy); + #define gdispStreamStart(x,y,cx,cy) gdispGStreamStart(GDISP,x,y,cx,cy) /** * @brief Send pixel data to the stream. @@ -464,11 +499,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * @note If the gdispStreamStart() has not been called (or failed due to clipping), the * data provided here is simply thrown away. * + * @param[in] g The display to use * @param[in] color The color of the pixel to write * * @api */ - void gdispStreamColor(color_t color); + void gdispGStreamColor(GDisplay *g, color_t color); + #define gdispStreamColor(c) gdispGStreamColor(GDISP,c) /** * @brief Finish the current streaming operation. @@ -477,9 +514,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * @note If the gdispStreamStart() has not been called (or failed due to clipping), this * call is simply ignored. * + * @param[in] g The display to use + * * @api */ - void gdispStreamStop(void); + void gdispGStreamStop(GDisplay *g); + #define gdispStreamStop() gdispGStreamStop(GDISP) #endif /* Clipping Functions */ @@ -488,12 +528,14 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); /** * @brief Clip all drawing to the defined area. * - * @param[in] x,y The start position - * @param[in] cx,cy The size of the clip area + * @param[in] g The display to use + * @param[in] x,y The start position + * @param[in] cx,cy The size of the clip area * * @api */ - void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy); + void gdispGSetClip(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy); + #define gdispSetClip(x,y,cx,cy) gdispGSetClip(GDISP,x,y,cx,cy) #endif /* Circle Functions */ @@ -502,24 +544,28 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); /** * @brief Draw a circle. * + * @param[in] g The display to use * @param[in] x,y The center of the circle * @param[in] radius The radius of the circle * @param[in] color The color to use * * @api */ - void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color); + void gdispGDrawCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color); + #define gdispDrawCircle(x,y,r,c) gdispGDrawCircle(GDISP,x,y,r,c) /** * @brief Draw a filled circle. * + * @param[in] g The display to use * @param[in] x,y The center of the circle * @param[in] radius The radius of the circle * @param[in] color The color to use * * @api */ - void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color); + void gdispGFillCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color); + #define gdispFillCircle(x,y,r,c) gdispGFillCircle(GDISP,x,y,r,c) #endif /* Ellipse Functions */ @@ -528,24 +574,28 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); /** * @brief Draw an ellipse. * - * @param[in] x,y The center of the ellipse - * @param[in] a,b The dimensions of the ellipse - * @param[in] color The color to use + * @param[in] g The display to use + * @param[in] x,y The center of the ellipse + * @param[in] a,b The dimensions of the ellipse + * @param[in] color The color to use * * @api */ - void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + void gdispGDrawEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + #define gdispDrawEllipse(x,y,a,b,c) gdispGDrawEllipse(GDISP,x,y,a,b,c) /** * @brief Draw a filled ellipse. * - * @param[in] x,y The center of the ellipse - * @param[in] a,b The dimensions of the ellipse - * @param[in] color The color to use + * @param[in] g The display to use + * @param[in] x,y The center of the ellipse + * @param[in] a,b The dimensions of the ellipse + * @param[in] color The color to use * * @api */ - void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + void gdispGFillEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + #define gdispFillEllipse(x,y,a,b,c) gdispGFillEllipse(GDISP,x,y,a,b,c) #endif /* Arc Functions */ @@ -554,6 +604,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); /* * @brief Draw an arc. * + * @param[in] g The display to use * @param[in] x0,y0 The center point * @param[in] radius The radius of the arc * @param[in] start The start angle (0 to 360) @@ -562,12 +613,14 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + void gdispGDrawArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + #define gdispDrawArc(x,y,r,s,e,c) gdispGDrawArc(GDISP,x,y,r,s,e,c) /* * @brief Draw a filled arc. * @note Not very efficient currently - does lots of overdrawing * + * @param[in] g The display to use * @param[in] x0,y0 The center point * @param[in] radius The radius of the arc * @param[in] start The start angle (0 to 360) @@ -576,7 +629,8 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + void gdispGFillArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + #define gdispFillArc(x,y,r,s,e,c) gdispGFillArc(GDISP,x,y,r,s,e,c) #endif /* Read a pixel Function */ @@ -586,11 +640,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * @brief Get the color of a pixel. * @return The color of the pixel. * - * @param[in] x,y The position of the pixel + * @param[in] g The display to use + * @param[in] x,y The position of the pixel * * @api */ - color_t gdispGetPixelColor(coord_t x, coord_t y); + color_t gdispGGetPixelColor(GDisplay *g, coord_t x, coord_t y); + #define gdispGetPixelColor(x,y) gdispGGetPixelColor(GDISP,x,y) #endif /* Scrolling Function - clears the area scrolled out */ @@ -602,14 +658,16 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * @note Optional. * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. + * @param[in] g The display to use + * @param[in] x, y The start of the area to be scrolled + * @param[in] cx, cy The size of the area to be scrolled + * @param[in] lines The number of lines to scroll (Can be positive or negative) + * @param[in] bgcolor The color to fill the newly exposed area. * * @api */ - void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor); + void gdispGVerticalScroll(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor); + #define gdispVerticalScroll(x,y,cx,cy,l,b) gdispGVerticalScroll(GDISP,x,y,cx,cy,l,b) #endif /* Set driver specific control */ @@ -620,12 +678,14 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * @note Depending on the hardware implementation this function may not * support some codes. They will be ignored. * + * @param[in] g The display to use * @param[in] what what you want to control * @param[in] value The value to be assigned * * @api */ - void gdispControl(unsigned what, void *value); + void gdispGControl(GDisplay *g, unsigned what, void *value); + #define gdispControl(w,v) gdispGControl(GDISP,w,v) #endif /* Query driver specific data */ @@ -636,17 +696,20 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * @note The result must be typecast to the correct type. * @note An unsupported query will return (void *)-1. * + * @param[in] g The display to use * @param[in] what What to query * * @api */ - void *gdispQuery(unsigned what); + void *gdispGQuery(GDisplay *g, unsigned what); + #define gdispQuery(w) gdispGQuery(GDISP,w) #endif #if GDISP_NEED_CONVEX_POLYGON || defined(__DOXYGEN__) /** * @brief Draw an enclosed polygon (convex, non-convex or complex). * + * @param[in] g The display to use * @param[in] tx, ty Transform all points in pntarray by tx, ty * @param[in] pntarray An array of points * @param[in] cnt The number of points in the array @@ -654,12 +717,14 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispDrawPoly(coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color); + void gdispGDrawPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color); + #define gdispDrawPoly(x,y,p,i,c) gdispGDrawPoly(GDISP,x,y,p,i,c) /** * @brief Fill a convex polygon * @details Doesn't handle non-convex or complex polygons. * + * @param[in] g The display to use * @param[in] tx, ty Transform all points in pntarray by tx, ty * @param[in] pntarray An array of points * @param[in] cnt The number of points in the array @@ -675,7 +740,8 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispFillConvexPoly(coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color); + void gdispGFillConvexPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color); + #define gdispFillConvexPoly(x,y,p,i,c) gdispGFillConvexPoly(GDISP,x,y,p,i,c) #endif /* Text Functions */ @@ -684,6 +750,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); /** * @brief Draw a text character. * + * @param[in] g The display to use * @param[in] x,y The position for the text * @param[in] c The character to draw * @param[in] font The font to use @@ -691,11 +758,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color); + void gdispGDrawChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color); + #define gdispDrawChar(x,y,s,f,c) gdispGDrawChar(GDISP,x,y,s,f,c) /** * @brief Draw a text character with a filled background. * + * @param[in] g The display to use * @param[in] x,y The position for the text * @param[in] c The character to draw * @param[in] font The font to use @@ -704,11 +773,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispFillChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor); + void gdispGFillChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor); + #define gdispFillChar(x,y,s,f,c,b) gdispGFillChar(GDISP,x,y,s,f,c,b) /** * @brief Draw a text string. * + * @param[in] g The display to use * @param[in] x,y The position for the text * @param[in] font The font to use * @param[in] str The string to draw @@ -716,11 +787,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispDrawString(coord_t x, coord_t y, const char *str, font_t font, color_t color); + void gdispGDrawString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color); + #define gdispDrawString(x,y,s,f,c) gdispGDrawString(GDISP,x,y,s,f,c) /** * @brief Draw a text string. * + * @param[in] g The display to use * @param[in] x,y The position for the text * @param[in] str The string to draw * @param[in] font The font to use @@ -729,11 +802,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispFillString(coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor); + void gdispGFillString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor); + #define gdispFillString(x,y,s,f,c,b) gdispGFillString(GDISP,x,y,s,f,c,b) /** * @brief Draw a text string vertically centered within the specified box. * + * @param[in] g The display to use * @param[in] x,y The position for the text (need to define top-right or base-line - check code) * @param[in] cx,cy The width and height of the box * @param[in] str The string to draw @@ -743,12 +818,14 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispDrawStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify); + void gdispGDrawStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify); + #define gdispDrawStringBox(x,y,cx,cy,s,f,c,j) gdispGDrawStringBox(GDISP,x,y,cx,cy,s,f,c,j) /** * @brief Draw a text string vertically centered within the specified box. The box background is filled with the specified background color. * @note The entire box is filled * + * @param[in] g The display to use * @param[in] x,y The position for the text (need to define top-right or base-line - check code) * @param[in] cx,cy The width and height of the box * @param[in] str The string to draw @@ -759,7 +836,8 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispFillStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgColor, justify_t justify); + void gdispGFillStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgColor, justify_t justify); + #define gdispFillStringBox(x,y,cx,cy,s,f,c,b,j) gdispGFillStringBox(GDISP,x,y,cx,cy,s,f,c,b,j) /** * @brief Get a metric of a font. @@ -844,6 +922,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); /** * @brief Draw a rectangular box with rounded corners * + * @param[in] g The display to use * @param[in] x,y The start position * @param[in] cx,cy The size of the box (outside dimensions) * @param[in] radius The radius of the rounded corners @@ -851,11 +930,13 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispDrawRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color); + void gdispGDrawRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color); + #define gdispDrawRoundedBox(x,y,cx,cy,r,c) gdispGDrawRoundedBox(GDISP,x,y,cx,cy,r,c) /** * @brief Draw a filled rectangular box with rounded corners * + * @param[in] g The display to use * @param[in] x,y The start position * @param[in] cx,cy The size of the box (outside dimensions) * @param[in] radius The radius of the rounded corners @@ -863,7 +944,8 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ - void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color); + void gdispGFillRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color); + #define gdispFillRoundedBox(x,y,cx,cy,r,c) gdispGFillRoundedBox(GDISP,x,y,cx,cy,r,c) #endif /* @@ -871,7 +953,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); */ /* Now obsolete functions */ -#define gdispBlitArea(x, y, cx, cy, buffer) gdispBlitAreaEx(x, y, cx, cy, 0, 0, cx, buffer) +#define gdispBlitArea(x, y, cx, cy, buffer) gdispGBlitArea(GDISP, x, y, cx, cy, 0, 0, cx, buffer) /* Macro definitions for common gets and sets */ @@ -879,26 +961,31 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * @brief Set the display power mode. * @note Ignored if not supported by the display. * + * @param[in] g The display to use * @param[in] powerMode The new power mode * * @api */ -#define gdispSetPowerMode(powerMode) gdispControl(GDISP_CONTROL_POWER, (void *)(unsigned)(powerMode)) +#define gdispGSetPowerMode(g, powerMode) gdispGControl((g), GDISP_CONTROL_POWER, (void *)(unsigned)(powerMode)) +#define gdispSetPowerMode(powerMode) gdispGControl(GDISP, GDISP_CONTROL_POWER, (void *)(unsigned)(powerMode)) /** * @brief Set the display orientation. * @note Ignored if not supported by the display. * + * @param[in] g The display to use * @param[in] newOrientation The new orientation * * @api */ -#define gdispSetOrientation(newOrientation) gdispControl(GDISP_CONTROL_ORIENTATION, (void *)(unsigned)(newOrientation)) +#define gdispGSetOrientation(g, newOrientation) gdispGControl((g), GDISP_CONTROL_ORIENTATION, (void *)(unsigned)(newOrientation)) +#define gdispSetOrientation(newOrientation) gdispGControl(GDISP, GDISP_CONTROL_ORIENTATION, (void *)(unsigned)(newOrientation)) /** * @brief Set the display backlight. * @note Ignored if not supported by the display. * + * @param[in] g The display to use * @param[in] percent The new brightness (0 - 100%) * * @note For displays that only support backlight off and on, @@ -906,68 +993,92 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); * * @api */ -#define gdispSetBacklight(percent) gdispControl(GDISP_CONTROL_BACKLIGHT, (void *)(unsigned)(percent)) +#define gdispGSetBacklight(g, percent) gdispGControl((g), GDISP_CONTROL_BACKLIGHT, (void *)(unsigned)(percent)) +#define gdispSetBacklight(percent) gdispGControl(GDISP, GDISP_CONTROL_BACKLIGHT, (void *)(unsigned)(percent)) /** * @brief Set the display contrast. * @note Ignored if not supported by the display. * + * @param[in] g The display to use * @param[in] percent The new contrast (0 - 100%) * * @api */ -#define gdispSetContrast(percent) gdispControl(GDISP_CONTROL_CONTRAST, (void *)(unsigned)(percent)) +#define gdispGSetContrast(g, percent) gdispGControl((g), GDISP_CONTROL_CONTRAST, (void *)(unsigned)(percent)) +#define gdispSetContrast(percent) gdispGControl(GDISP, GDISP_CONTROL_CONTRAST, (void *)(unsigned)(percent)) /** * @brief Get the display width in pixels. * + * @param[in] g The display to use + * * @api */ -#define gdispGetWidth() (GDISP->Width) +#define gdispGGetWidth(g) (((GDISPControl *)(g))->Width) +#define gdispGetWidth() gdispGGetWidth(GDISP) /** * @brief Get the display height in pixels. * + * @param[in] g The display to use + * * @api */ -#define gdispGetHeight() (GDISP->Height) +#define gdispGGetHeight(g) (((GDISPControl *)(g))->Height) +#define gdispGetHeight() gdispGGetHeight(GDISP) /** * @brief Get the current display power mode. * + * @param[in] g The display to use + * * @api */ -#define gdispGetPowerMode() (GDISP->Powermode) +#define gdispGGetPowerMode(g) (((GDISPControl *)(g))->Powermode) +#define gdispGetPowerMode() gdispGGetPowerMode(GDISP) /** * @brief Get the current display orientation. * + * @param[in] g The display to use + * * @api */ -#define gdispGetOrientation() (GDISP->Orientation) +#define gdispGGetOrientation(g) (((GDISPControl *)(g))->Orientation) +#define gdispGetOrientation() gdispGGetOrientation(GDISP) /** * @brief Get the current display backlight brightness. * + * @param[in] g The display to use + * * @api */ -#define gdispGetBacklight() (GDISP->Backlight) +#define gdispGGetBacklight(g) (((GDISPControl *)(g))->Backlight) +#define gdispGetBacklight() gdispGGetBacklight(GDISP) /** * @brief Get the current display contrast. * + * @param[in] g The display to use + * * @api */ -#define gdispGetContrast() (GDISP->Contrast) +#define gdispGGetContrast(g) (((GDISPControl *)(g))->Contrast) +#define gdispGetContrast() gdispGGetContrast(GDISP) /* More interesting macro's */ /** * @brief Reset the clip area to the full screen * + * @param[in] g The display to use + * * @api */ -#define gdispUnsetClip() gdispSetClip(0,0,gdispGetWidth(),gdispGetHeight()) +#define gdispGUnsetClip(g) gdispGSetClip((g),0,0,(g)->Width,(g)->Height) +#define gdispUnsetClip() gdispGUnsetClip(GDISP) #ifdef __cplusplus } diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 4813d828..2a6f90b7 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -18,140 +18,136 @@ #if GFX_USE_GDISP || defined(__DOXYGEN__) -#if GDISP_MULTIPLE_DRIVERS && defined(GDISP_LLD_DECLARATIONS) - // include hardware definitions - #include "gdisp_lld_config.h" -#endif - /*===========================================================================*/ /* Error checks. */ /*===========================================================================*/ -#if !GDISP_MULTIPLE_DRIVERS || defined(GDISP_LLD_DECLARATIONS) +/** + * @name GDISP hardware accelerated support + * @{ + */ /** - * @name GDISP hardware accelerated support - * @{ + * @brief Hardware streaming writing is supported. + * @details If set to @p FALSE software emulation is used. + * @note Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver */ - /** - * @brief Hardware streaming writing is supported. - * @details If set to @p FALSE software emulation is used. - * @note Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver - */ - #ifndef GDISP_HARDWARE_STREAM_WRITE - #define GDISP_HARDWARE_STREAM_WRITE FALSE - #endif + #ifndef GDISP_HARDWARE_STREAM_WRITE + #define GDISP_HARDWARE_STREAM_WRITE FALSE + #endif - /** - * @brief Hardware streaming reading of the display surface is supported. - * @details If set to @p FALSE this routine is not available. - */ - #ifndef GDISP_HARDWARE_STREAM_READ - #define GDISP_HARDWARE_STREAM_READ FALSE - #endif + /** + * @brief Hardware streaming reading of the display surface is supported. + * @details If set to @p FALSE this routine is not available. + */ + #ifndef GDISP_HARDWARE_STREAM_READ + #define GDISP_HARDWARE_STREAM_READ FALSE + #endif - /** - * @brief Hardware supports setting the cursor position within the stream window. - * @details If set to @p FALSE this routine is not available. - * @note This is used to optimise setting of individual pixels within a stream window. - * It should therefore not be implemented unless it is cheaper than just setting - * a new window. - */ - #ifndef GDISP_HARDWARE_STREAM_POS - #define GDISP_HARDWARE_STREAM_POS FALSE - #endif + /** + * @brief Hardware supports setting the cursor position within the stream window. + * @details If set to @p FALSE this routine is not available. + * @note This is used to optimise setting of individual pixels within a stream window. + * It should therefore not be implemented unless it is cheaper than just setting + * a new window. + */ + #ifndef GDISP_HARDWARE_STREAM_POS + #define GDISP_HARDWARE_STREAM_POS FALSE + #endif - /** - * @brief Hardware accelerated draw pixel. - * @details If set to @p FALSE software emulation is used. - * @note Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver - */ - #ifndef GDISP_HARDWARE_DRAWPIXEL - #define GDISP_HARDWARE_DRAWPIXEL FALSE - #endif + /** + * @brief Hardware accelerated draw pixel. + * @details If set to @p FALSE software emulation is used. + * @note Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver + */ + #ifndef GDISP_HARDWARE_DRAWPIXEL + #define GDISP_HARDWARE_DRAWPIXEL FALSE + #endif - /** - * @brief Hardware accelerated screen clears. - * @details If set to @p FALSE software emulation is used. - * @note This clears the entire display surface regardless of the clipping area currently set - */ - #ifndef GDISP_HARDWARE_CLEARS - #define GDISP_HARDWARE_CLEARS FALSE - #endif + /** + * @brief Hardware accelerated screen clears. + * @details If set to @p FALSE software emulation is used. + * @note This clears the entire display surface regardless of the clipping area currently set + */ + #ifndef GDISP_HARDWARE_CLEARS + #define GDISP_HARDWARE_CLEARS FALSE + #endif - /** - * @brief Hardware accelerated rectangular fills. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_FILLS - #define GDISP_HARDWARE_FILLS FALSE - #endif + /** + * @brief Hardware accelerated rectangular fills. + * @details If set to @p FALSE software emulation is used. + */ + #ifndef GDISP_HARDWARE_FILLS + #define GDISP_HARDWARE_FILLS FALSE + #endif - /** - * @brief Hardware accelerated fills from an image. - * @details If set to @p FALSE software emulation is used. - */ - #ifndef GDISP_HARDWARE_BITFILLS - #define GDISP_HARDWARE_BITFILLS FALSE - #endif + /** + * @brief Hardware accelerated fills from an image. + * @details If set to @p FALSE software emulation is used. + */ + #ifndef GDISP_HARDWARE_BITFILLS + #define GDISP_HARDWARE_BITFILLS FALSE + #endif - /** - * @brief Hardware accelerated scrolling. - * @details If set to @p FALSE there is no support for scrolling. - */ - #ifndef GDISP_HARDWARE_SCROLL - #define GDISP_HARDWARE_SCROLL FALSE - #endif + /** + * @brief Hardware accelerated scrolling. + * @details If set to @p FALSE there is no support for scrolling. + */ + #ifndef GDISP_HARDWARE_SCROLL + #define GDISP_HARDWARE_SCROLL FALSE + #endif - /** - * @brief Reading back of pixel values. - * @details If set to @p FALSE there is no support for pixel read-back. - */ - #ifndef GDISP_HARDWARE_PIXELREAD - #define GDISP_HARDWARE_PIXELREAD FALSE - #endif + /** + * @brief Reading back of pixel values. + * @details If set to @p FALSE there is no support for pixel read-back. + */ + #ifndef GDISP_HARDWARE_PIXELREAD + #define GDISP_HARDWARE_PIXELREAD FALSE + #endif - /** - * @brief The driver supports one or more control commands. - * @details If set to @p FALSE there is no support for control commands. - */ - #ifndef GDISP_HARDWARE_CONTROL - #define GDISP_HARDWARE_CONTROL FALSE - #endif + /** + * @brief The driver supports one or more control commands. + * @details If set to @p FALSE there is no support for control commands. + */ + #ifndef GDISP_HARDWARE_CONTROL + #define GDISP_HARDWARE_CONTROL FALSE + #endif - /** - * @brief The driver supports a non-standard query. - * @details If set to @p FALSE there is no support for non-standard queries. - */ - #ifndef GDISP_HARDWARE_QUERY - #define GDISP_HARDWARE_QUERY FALSE - #endif + /** + * @brief The driver supports a non-standard query. + * @details If set to @p FALSE there is no support for non-standard queries. + */ + #ifndef GDISP_HARDWARE_QUERY + #define GDISP_HARDWARE_QUERY FALSE + #endif - /** - * @brief The driver supports a clipping in hardware. - * @details If set to @p FALSE there is no support for non-standard queries. - * @note If this is defined the driver must perform its own clipping on all calls to - * the driver and respond appropriately if a parameter is outside the display area. - * @note If this is not defined then the software ensures that all calls to the - * driver do not exceed the display area (provided GDISP_NEED_CLIP or GDISP_NEED_VALIDATION - * has been set). - */ - #ifndef GDISP_HARDWARE_CLIP - #define GDISP_HARDWARE_CLIP FALSE - #endif - /** @} */ -#endif + /** + * @brief The driver supports a clipping in hardware. + * @details If set to @p FALSE there is no support for non-standard queries. + * @note If this is defined the driver must perform its own clipping on all calls to + * the driver and respond appropriately if a parameter is outside the display area. + * @note If this is not defined then the software ensures that all calls to the + * driver do not exceed the display area (provided GDISP_NEED_CLIP or GDISP_NEED_VALIDATION + * has been set). + */ + #ifndef GDISP_HARDWARE_CLIP + #define GDISP_HARDWARE_CLIP FALSE + #endif +/** @} */ /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ -typedef struct GDISPDriver { - GDISPControl g; +typedef struct GDisplay { + GDISPControl g; // The public GDISP stuff - must be the first element - #if GDISP_MULTIPLE_DRIVERS - const struct GDISPVMT const * vmt; + #if GDISP_TOTAL_CONTROLLERS > 1 + const struct GDISPVMT const * vmt; // The Virtual Method Table #endif + void * priv; // A private area just for the drivers use. + + uint16_t flags; #define GDISP_FLG_INSTREAM 0x0001 // We are in a user based stream operation #define GDISP_FLG_SCRSTREAM 0x0002 // The stream area currently covers the whole screen @@ -163,7 +159,7 @@ typedef struct GDISPDriver { #endif // Software clipping - #if (GDISP_MULTIPLE_DRIVERS || !GDISP_HARDWARE_CLIP) && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + #if !GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) coord_t clipx0, clipy0; coord_t clipx1, clipy1; /* not inclusive */ #endif @@ -195,10 +191,10 @@ typedef struct GDISPDriver { color_t linebuf[GDISP_LINEBUF_SIZE]; #endif -} GDISPDriver; +} GDisplay; -#if !GDISP_MULTIPLE_DRIVERS || defined(GDISP_LLD_DECLARATIONS) || defined(__DOXYGEN__) - #if GDISP_MULTIPLE_DRIVERS +#if GDISP_TOTAL_CONTROLLERS == 1 || defined(GDISP_DRIVER_VMT) || defined(__DOXYGEN__) + #if GDISP_TOTAL_CONTROLLERS > 1 #define LLDSPEC static #else #define LLDSPEC @@ -212,9 +208,10 @@ typedef struct GDISPDriver { * @brief Initialize the driver. * @return TRUE if successful. * @param[in] g The driver structure + * @param[in] display The display number for this controller 0..n * @param[out] g->g The driver must fill in the GDISPControl structure */ - LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g); + LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display); #if GDISP_HARDWARE_STREAM_WRITE || defined(__DOXYGEN__) /** @@ -230,7 +227,7 @@ typedef struct GDISPDriver { * undefined results. * @note This must be followed by a call to @p gdisp_lld_write_pos() if GDISP_HARDWARE_STREAM_POS is TRUE. */ - LLDSPEC void gdisp_lld_write_start(GDISPDriver *g); + LLDSPEC void gdisp_lld_write_start(GDisplay *g); /** * @brief Send a pixel to the current streaming position and then increment that position @@ -241,7 +238,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_write_color(GDISPDriver *g); + LLDSPEC void gdisp_lld_write_color(GDisplay *g); /** * @brief End the current streaming write operation @@ -251,7 +248,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g); + LLDSPEC void gdisp_lld_write_stop(GDisplay *g); #if GDISP_HARDWARE_STREAM_POS || defined(__DOXYGEN__) /** @@ -263,7 +260,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_write_pos(GDISPDriver *g); + LLDSPEC void gdisp_lld_write_pos(GDisplay *g); #endif #endif @@ -280,7 +277,7 @@ typedef struct GDISPDriver { * @note Streaming operations that wrap the defined window have * undefined results. */ - LLDSPEC void gdisp_lld_read_start(GDISPDriver *g); + LLDSPEC void gdisp_lld_read_start(GDisplay *g); /** * @brief Read a pixel from the current streaming position and then increment that position @@ -291,7 +288,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g); + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g); /** * @brief End the current streaming operation @@ -301,7 +298,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g); + LLDSPEC void gdisp_lld_read_stop(GDisplay *g); #endif #if GDISP_HARDWARE_DRAWPIXEL || defined(__DOXYGEN__) @@ -315,7 +312,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g); + LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g); #endif #if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) @@ -328,7 +325,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_clear(GDISPDriver *g); + LLDSPEC void gdisp_lld_clear(GDisplay *g); #endif #if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) @@ -343,7 +340,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g); + LLDSPEC void gdisp_lld_fill_area(GDisplay *g); #endif #if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) @@ -360,7 +357,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g); + LLDSPEC void gdisp_lld_blit_area(GDisplay *g); #endif #if GDISP_HARDWARE_PIXELREAD || defined(__DOXYGEN__) @@ -374,7 +371,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC color_t gdisp_lld_get_pixel_color(GDISPDriver *g); + LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g); #endif #if (GDISP_HARDWARE_SCROLL && GDISP_NEED_SCROLL) || defined(__DOXYGEN__) @@ -393,7 +390,7 @@ typedef struct GDISPDriver { * @note Clearing the exposed area on the scroll operation is not * needed as the high level code handles this. */ - LLDSPEC void gdisp_lld_vertical_scroll(GDISPDriver *g); + LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g); #endif #if (GDISP_HARDWARE_CONTROL && GDISP_NEED_CONTROL) || defined(__DOXYGEN__) @@ -407,7 +404,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_control(GDISPDriver *g); + LLDSPEC void gdisp_lld_control(GDisplay *g); #endif #if (GDISP_HARDWARE_QUERY && GDISP_NEED_QUERY) || defined(__DOXYGEN__) @@ -421,7 +418,7 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void *gdisp_lld_query(GDISPDriver *g); // Uses p.x (=what); + LLDSPEC void *gdisp_lld_query(GDisplay *g); // Uses p.x (=what); #endif #if (GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION)) || defined(__DOXYGEN__) @@ -435,40 +432,39 @@ typedef struct GDISPDriver { * * @note The parameter variables must not be altered by the driver. */ - LLDSPEC void gdisp_lld_set_clip(GDISPDriver *g); + LLDSPEC void gdisp_lld_set_clip(GDisplay *g); #endif #ifdef __cplusplus } #endif -#endif // !GDISP_MULTIPLE_DRIVERS || defined(GDISP_LLD_DECLARATIONS) +#endif // GDISP_TOTAL_CONTROLLERS == 1 || defined(GDISP_DRIVER_VMT) -#if GDISP_MULTIPLE_DRIVERS +#if GDISP_TOTAL_CONTROLLERS > 1 typedef struct GDISPVMT { - bool_t (*init)(GDISPDriver *g); - void (*writestart)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy - void (*writepos)(GDISPDriver *g); // Uses p.x,p.y - void (*writecolor)(GDISPDriver *g); // Uses p.color - void (*writestop)(GDISPDriver *g); // Uses no parameters - void (*readstart)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy - color_t (*readcolor)(GDISPDriver *g); // Uses no parameters - void (*readstop)(GDISPDriver *g); // Uses no parameters - void (*pixel)(GDISPDriver *g); // Uses p.x,p.y p.color - void (*clear)(GDISPDriver *g); // Uses p.color - void (*fill)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy p.color - void (*blit)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer) - color_t (*get)(GDISPDriver *g); // Uses p.x,p.y - void (*vscroll)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy, p.y1 (=lines) p.color - void (*control)(GDISPDriver *g); // Uses p.x (=what) p.ptr (=value) - void *(*query)(GDISPDriver *g); // Uses p.x (=what); - void (*setclip)(GDISPDriver *g); // Uses p.x,p.y p.cx,p.cy + bool_t (*init)(GDisplay *g, unsigned display); + void (*writestart)(GDisplay *g); // Uses p.x,p.y p.cx,p.cy + void (*writepos)(GDisplay *g); // Uses p.x,p.y + void (*writecolor)(GDisplay *g); // Uses p.color + void (*writestop)(GDisplay *g); // Uses no parameters + void (*readstart)(GDisplay *g); // Uses p.x,p.y p.cx,p.cy + color_t (*readcolor)(GDisplay *g); // Uses no parameters + void (*readstop)(GDisplay *g); // Uses no parameters + void (*pixel)(GDisplay *g); // Uses p.x,p.y p.color + void (*clear)(GDisplay *g); // Uses p.color + void (*fill)(GDisplay *g); // Uses p.x,p.y p.cx,p.cy p.color + void (*blit)(GDisplay *g); // Uses p.x,p.y p.cx,p.cy p.x1,p.y1 (=srcx,srcy) p.x2 (=srccx), p.ptr (=buffer) + color_t (*get)(GDisplay *g); // Uses p.x,p.y + void (*vscroll)(GDisplay *g); // Uses p.x,p.y p.cx,p.cy, p.y1 (=lines) p.color + void (*control)(GDisplay *g); // Uses p.x (=what) p.ptr (=value) + void *(*query)(GDisplay *g); // Uses p.x (=what); + void (*setclip)(GDisplay *g); // Uses p.x,p.y p.cx,p.cy } GDISPVMT; - #ifdef GDISP_LLD_DECLARATIONS - #define GDISP_DRIVER_STRUCT_INIT {{0}, &VMT} - static const GDISPVMT VMT = { + #if defined(GDISP_DRIVER_VMT) + const GDISPVMT const GDISP_DRIVER_VMT[1] = {{ gdisp_lld_init, #if GDISP_HARDWARE_STREAM_WRITE gdisp_lld_write_start, @@ -480,7 +476,7 @@ typedef struct GDISPDriver { gdisp_lld_write_color, gdisp_lld_write_stop, #else - 0, 0, 0, + 0, 0, 0, 0, #endif #if GDISP_HARDWARE_STREAM_READ gdisp_lld_read_start, @@ -534,11 +530,10 @@ typedef struct GDISPDriver { #else 0, #endif - }; - GDISPDriver GDISP_DRIVER_STRUCT = {{0}, &VMT}; + }}; #else - #define gdisp_lld_init(g) g->vmt->init(g) + #define gdisp_lld_init(g, display) g->vmt->init(g, display) #define gdisp_lld_write_start(g) g->vmt->writestart(g) #define gdisp_lld_write_pos(g) g->vmt->writepos(g) #define gdisp_lld_write_color(g) g->vmt->writecolor(g) @@ -555,19 +550,9 @@ typedef struct GDISPDriver { #define gdisp_lld_control(g) g->vmt->control(g) #define gdisp_lld_query(g) g->vmt->query(g) #define gdisp_lld_set_clip(g) g->vmt->setclip(g) - - extern GDISPDriver GDISP_DRIVER_STRUCT; - #endif // GDISP_LLD_DECLARATIONS -#else // GDISP_MULTIPLE_DRIVERS - #ifdef GDISP_LLD_DECLARATIONS - GDISPDriver GDISP_DRIVER_STRUCT; - #else - extern GDISPDriver GDISP_DRIVER_STRUCT; - #endif - -#endif // GDISP_MULTIPLE_DRIVERS +#endif // GDISP_TOTAL_CONTROLLERS > 1 /* Verify information for packed pixels and define a non-packed pixel macro */ #if !GDISP_PACKED_PIXELS diff --git a/include/gdisp/options.h b/include/gdisp/options.h index 1a0f6907..9af7788f 100644 --- a/include/gdisp/options.h +++ b/include/gdisp/options.h @@ -20,19 +20,6 @@ * @name GDISP Functionality to be included * @{ */ - /** - * @brief Should support for multiple displays be provided. - * @details Defaults to FALSE. - * @note Setting this to TRUE can significantly increase code size as many - * optimizations that remove code through conditional compilation can't - * be done. It may also slow some graphics operations as extra tests must - * be performed to determine how to do a particular operation. For these - * reasons do not set it to TRUE unless you really need multiple display - * support. - */ - #ifndef GDISP_MULTIPLE_DRIVERS - #define GDISP_MULTIPLE_DRIVERS FALSE - #endif /** * @brief Should all operations be clipped to the screen and colors validated. * @details Defaults to TRUE. @@ -155,6 +142,50 @@ #ifndef GDISP_NEED_IMAGE #define GDISP_NEED_IMAGE FALSE #endif +/** + * @} + * + * @name GDISP Multiple Display Support + * @{ + */ + /** + * @brief The total number of displays. + * @note This can be on just one type of controller or spread across several different controllers + */ + #ifndef GDISP_TOTAL_DISPLAYS + #define GDISP_TOTAL_DISPLAYS 1 + #endif + /** + * @brief The total number of controllers. + * @note If this is greater than one, all the hardware acceleration options below + * and the pixel format must be manually specified in your gfxconf.h along with + * @p GDISP_CONTROLLER_LIST. See the gdisp_lld_config.h in each driver to get a list + * of hardware capabilities for each driver in order to work out the common set across + * all the controllers you want to use. + */ + #ifndef GDISP_TOTAL_CONTROLLERS + #define GDISP_TOTAL_CONTROLLERS 1 + #endif + + #if defined(__DOXYGEN__) + /** + * @brief The list of controllers. + * @note This is required if @p GDISP_TOTAL_CONTROLLERS is greater than one. + * @note The number of entries must match @p GDISP_TOTAL_CONTROLLERS. + * @note See the gdisp_lld.c in each driver (near the top) to get the name of the VMT for a driver. + * @note Replace this example with your own definition in your gfxconf.h file. + */ + #define GDISP_CONTROLLER_LIST GDISPVMT_Win32, GDISPVMT_SSD1963 + /** + * @brief The number of displays for each controller. + * @note This is required if @p GDISP_TOTAL_CONTROLLERS is greater than one. + * @note The number of entries must match @p GDISP_TOTAL_CONTROLLERS. + * @note The sum of all the display counts must equal @p GDISP_TOTAL_DISPLAYS (3 for this example) + * or bad things will happen. + * @note Replace this example with your own definition in your gfxconf.h file. + */ + #define GDISP_CONTROLLER_DISPLAYS 2, 1 + #endif /** * @} * diff --git a/include/gfx_rules.h b/include/gfx_rules.h index a8dd031e..c58fc5ba 100644 --- a/include/gfx_rules.h +++ b/include/gfx_rules.h @@ -134,12 +134,14 @@ #endif #if GFX_USE_GDISP - #if GDISP_MULTIPLE_DRIVERS + #if GDISP_TOTAL_CONTROLLERS > 1 + #ifndef GDISP_CONTROLLER_LIST + #error "GDISP Multiple Controllers: You must specify a value for GDISP_CONTROLLER_LIST" + #endif #ifndef GDISP_PIXELFORMAT #if GFX_DISPLAY_RULE_WARNINGS - #warning "GDISP: GDISP_MULTIPLE_DRIVERS requires GDISP_PIXELFORMAT to be set. It has been defaulted to GDISP_PIXELFORMAT_RGB565." + #error "GDISP Multiple Controllers: You must specify a value for GDISP_PIXELFORMAT" #endif - #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif #endif #if GDISP_NEED_ANTIALIAS && !GDISP_NEED_PIXELREAD diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 756d5c1d..41f2f0f9 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -31,81 +31,92 @@ #define INLINE #endif +// Number of milliseconds for the startup logo - 0 means disabled. +#define GDISP_STARTUP_LOGO_TIMEOUT 1000 + /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ -#define GC ((GDISPDriver *)GDISP) -GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; +// The controller array, the display array and the default display +#if GDISP_TOTAL_CONTROLLERS > 1 + typedef const struct GDISPVMT const VMTEL[1]; + extern VMTEL GDISP_CONTROLLER_LIST; + static const struct GDISPVMT const * ControllerList[GDISP_TOTAL_CONTROLLERS] = {GDISP_CONTROLLER_LIST}; + static const unsigned DisplayCountList[GDISP_TOTAL_CONTROLLERS] = {GDISP_CONTROLLER_DISPLAYS}; +#endif +static GDisplay GDisplayArray[GDISP_TOTAL_DISPLAYS]; +GDisplay *GDISP = GDisplayArray; #if GDISP_NEED_MULTITHREAD - #define MUTEX_INIT() gfxMutexInit(&GC->mutex) - #define MUTEX_ENTER() gfxMutexEnter(&GC->mutex) - #define MUTEX_EXIT() gfxMutexExit(&GC->mutex) + #define MUTEX_INIT(g) gfxMutexInit(&(g)->mutex) + #define MUTEX_ENTER(g) gfxMutexEnter(&(g)->mutex) + #define MUTEX_EXIT(g) gfxMutexExit(&(g)->mutex) #else - #define MUTEX_INIT() - #define MUTEX_ENTER() - #define MUTEX_EXIT() + #define MUTEX_INIT(g) + #define MUTEX_ENTER(g) + #define MUTEX_EXIT(g) #endif #define NEED_CLIPPING (!GDISP_HARDWARE_CLIP && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP)) + /*==========================================================================*/ /* Internal functions. */ /*==========================================================================*/ #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - static INLINE void setglobalwindow(void) { + static INLINE void setglobalwindow(GDisplay *g) { coord_t x, y; - x = GC->p.x; y = GC->p.y; - GC->p.cx = GC->g.Width; GC->p.cy = GC->g.Height; - gdisp_lld_write_start(GC); - GC->p.x = x; GC->p.y = y; - GC->flags |= GDISP_FLG_SCRSTREAM; + x = g->p.x; y = g->p.y; + g->p.cx = g->g.Width; g->p.cy = g->g.Height; + gdisp_lld_write_start(g); + g->p.x = x; g->p.y = y; + g->flags |= GDISP_FLG_SCRSTREAM; } #endif -// drawpixel_clip() +// drawpixel_clip(g) // Parameters: x,y // Alters: cx, cy (if using streaming) #if GDISP_HARDWARE_DRAWPIXEL // Best is hardware accelerated pixel draw #if NEED_CLIPPING - static INLINE void drawpixel_clip(void) { - if (GC->p.x >= GC->clipx0 && GC->p.x < GC->clipx1 && GC->p.y >= GC->clipy0 && GC->p.y < GC->clipy1) - gdisp_lld_draw_pixel(GC); + static INLINE void drawpixel_clip(GDisplay *g) { + if (g->p.x >= g->clipx0 && g->p.x < g->clipx1 && g->p.y >= g->clipy0 && g->p.y < g->clipy1) + gdisp_lld_draw_pixel(g); } #else - #define drawpixel_clip() gdisp_lld_draw_pixel(GC) + #define drawpixel_clip(g) gdisp_lld_draw_pixel(g) #endif #elif GDISP_HARDWARE_STREAM_POS // Next best is cursor based streaming - static INLINE void drawpixel_clip(void) { + static INLINE void drawpixel_clip(GDisplay *g) { #if NEED_CLIPPING - if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1 || GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1) + if (g->p.x < g->clipx0 || g->p.x >= g->clipx1 || g->p.y < g->clipy0 || g->p.y >= g->clipy1) return; #endif - if (!(GC->flags & GDISP_FLG_SCRSTREAM)) - setglobalwindow(); - gdisp_lld_write_pos(GC); - gdisp_lld_write_color(GC); + if (!(g->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(g); + gdisp_lld_write_pos(g); + gdisp_lld_write_color(g); } #else // Worst is streaming - static INLINE void drawpixel_clip(void) { + static INLINE void drawpixel_clip(GDisplay *g) { #if NEED_CLIPPING - if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1 || GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1) + if (g->p.x < g->clipx0 || g->p.x >= g->clipx1 || g->p.y < g->clipy0 || g->p.y >= g->clipy1) return; #endif - GC->p.cx = GC->p.cy = 1; - gdisp_lld_write_start(GC); - gdisp_lld_write_color(GC); - gdisp_lld_write_stop(GC); + g->p.cx = g->p.cy = 1; + gdisp_lld_write_start(g); + gdisp_lld_write_color(g); + gdisp_lld_write_stop(g); } #endif -// fillarea() +// fillarea(g) // Parameters: x,y cx,cy and color // Alters: nothing // Note: This is not clipped @@ -113,94 +124,94 @@ GDISPControl *GDISP = &GDISP_DRIVER_STRUCT.g; // if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set. #if GDISP_HARDWARE_FILLS // Best is hardware accelerated area fill - #define fillarea() gdisp_lld_fill_area(GC) + #define fillarea(g) gdisp_lld_fill_area(g) #elif GDISP_HARDWARE_STREAM_WRITE // Next best is hardware streaming - static INLINE void fillarea(void) { + static INLINE void fillarea(GDisplay *g) { uint32_t area; - area = (uint32_t)GC->p.cx * GC->p.cy; + area = (uint32_t)g->p.cx * g->p.cy; #if GDISP_HARDWARE_STREAM_POS - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - gdisp_lld_write_start(GC); + gdisp_lld_write_start(g); #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(GC); + gdisp_lld_write_pos(g); #endif for(; area; area--) - gdisp_lld_write_color(GC); - gdisp_lld_write_stop(GC); + gdisp_lld_write_color(g); + gdisp_lld_write_stop(g); } #else // Worst is drawing pixels - static INLINE void fillarea(void) { + static INLINE void fillarea(GDisplay *g) { coord_t x0, y0, x1, y1; - x0 = GC->p.x; - y0 = GC->p.y; - x1 = GC->p.x + GC->p.cx; - y1 = GC->p.y + GC->p.cy; - for(; GC->p.y < y1; GC->p.y++, GC->p.x = x0) - for(; GC->p.x < x1; GC->p.x++) - gdisp_lld_draw_pixel(GC); - GC->p.y = y0; + x0 = g->p.x; + y0 = g->p.y; + x1 = g->p.x + g->p.cx; + y1 = g->p.y + g->p.cy; + for(; g->p.y < y1; g->p.y++, g->p.x = x0) + for(; g->p.x < x1; g->p.x++) + gdisp_lld_draw_pixel(g); + g->p.y = y0; } #endif #if NEED_CLIPPING - #define TEST_CLIP_AREA(x,y,cx,cy) \ - if ((x) < GC->clipx0) { (cx) -= GC->clipx0 - (x); (x) = GC->clipx0; } \ - if ((y) < GC->clipy0) { (cy) -= GC->clipy0 - (y); (y) = GC->clipy0; } \ - if ((x) + (cx) > GC->clipx1) (cx) = GC->clipx1 - (x); \ - if ((y) + (cy) > GC->clipy1) (cy) = GC->clipy1 - (y); \ - if ((cx) > 0 && (cy) > 0) + #define TEST_CLIP_AREA(g) \ + if ((g)->p.x < (g)->clipx0) { (g)->p.cx -= (g)->clipx0 - (g)->p.x; (g)->p.x = (g)->clipx0; } \ + if ((g)->p.y < (g)->clipy0) { (g)->p.cy -= (g)->clipy0 - (g)->p.y; (g)->p.y = (g)->clipy0; } \ + if ((g)->p.x + (g)->p.cx > (g)->clipx1) (g)->p.cx = (g)->clipx1 - (g)->p.x; \ + if ((g)->p.y + (g)->p.cy > (g)->clipy1) (g)->p.cy = (g)->clipy1 - (g)->p.y; \ + if ((g)->p.cx > 0 && (g)->p.cy > 0) #else - #define TEST_CLIP_AREA(x,y,cx,cy) + #define TEST_CLIP_AREA(g) #endif // Parameters: x,y and x1 // Alters: x,y x1,y1 cx,cy // Assumes the window covers the screen and a write_stop() will occur later // if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set. -static void hline_clip(void) { +static void hline_clip(GDisplay *g) { // Swap the points if necessary so it always goes from x to x1 - if (GC->p.x1 < GC->p.x) { - GC->p.cx = GC->p.x; GC->p.x = GC->p.x1; GC->p.x1 = GC->p.cx; + if (g->p.x1 < g->p.x) { + g->p.cx = g->p.x; g->p.x = g->p.x1; g->p.x1 = g->p.cx; } // Clipping #if NEED_CLIPPING - if (GC->p.y < GC->clipy0 || GC->p.y >= GC->clipy1) return; - if (GC->p.x < GC->clipx0) GC->p.x = GC->clipx0; - if (GC->p.x1 >= GC->clipx1) GC->p.x1 = GC->clipx1 - 1; - if (GC->p.x1 < GC->p.x) return; + if (g->p.y < g->clipy0 || g->p.y >= g->clipy1) return; + if (g->p.x < g->clipx0) g->p.x = g->clipx0; + if (g->p.x1 >= g->clipx1) g->p.x1 = g->clipx1 - 1; + if (g->p.x1 < g->p.x) return; #endif // This is an optimization for the point case. It is only worthwhile however if we // have hardware fills or if we support both hardware pixel drawing and hardware streaming #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) // Is this a point - if (GC->p.x == GC->p.x1) { + if (g->p.x == g->p.x1) { #if GDISP_HARDWARE_DRAWPIXEL // Best is hardware accelerated pixel draw - gdisp_lld_draw_pixel(GC); + gdisp_lld_draw_pixel(g); #elif GDISP_HARDWARE_STREAM_POS // Next best is cursor based streaming - if (!(GC->flags & GDISP_FLG_SCRSTREAM)) - setglobalwindow(); - gdisp_lld_write_pos(GC); - gdisp_lld_write_color(GC); + if (!(g->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(g); + gdisp_lld_write_pos(g); + gdisp_lld_write_color(g); #else // Worst is streaming - GC->p.cx = GC->p.cy = 1; - gdisp_lld_write_start(GC); - gdisp_lld_write_color(GC); - gdisp_lld_write_stop(GC); + g->p.cx = g->p.cy = 1; + gdisp_lld_write_start(g); + gdisp_lld_write_color(g); + gdisp_lld_write_stop(g); #endif return; } @@ -208,65 +219,65 @@ static void hline_clip(void) { #if GDISP_HARDWARE_FILLS // Best is hardware accelerated area fill - GC->p.cx = GC->p.x1 - GC->p.x + 1; - GC->p.cy = 1; - gdisp_lld_fill_area(GC); + g->p.cx = g->p.x1 - g->p.x + 1; + g->p.cy = 1; + gdisp_lld_fill_area(g); #elif GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE // Next best is cursor based streaming - if (!(GC->flags & GDISP_FLG_SCRSTREAM)) - setglobalwindow(); - gdisp_lld_write_pos(GC); - do { gdisp_lld_write_color(GC); } while(GC->p.cx--); + if (!(g->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(g); + gdisp_lld_write_pos(g); + do { gdisp_lld_write_color(g); } while(g->p.cx--); #elif GDISP_HARDWARE_STREAM_WRITE // Next best is streaming - GC->p.cx = GC->p.x1 - GC->p.x + 1; - GC->p.cy = 1; - gdisp_lld_write_start(GC); - do { gdisp_lld_write_color(GC); } while(GC->p.cx--); - gdisp_lld_write_stop(GC); + g->p.cx = g->p.x1 - g->p.x + 1; + g->p.cy = 1; + gdisp_lld_write_start(g); + do { gdisp_lld_write_color(g); } while(g->p.cx--); + gdisp_lld_write_stop(g); #else // Worst is drawing pixels - for(; GC->p.x <= GC->p.x1; GC->p.x++) - gdisp_lld_draw_pixel(GC); + for(; g->p.x <= g->p.x1; g->p.x++) + gdisp_lld_draw_pixel(g); #endif } // Parameters: x,y and y1 // Alters: x,y x1,y1 cx,cy -static void vline_clip(void) { +static void vline_clip(GDisplay *g) { // Swap the points if necessary so it always goes from y to y1 - if (GC->p.y1 < GC->p.y) { - GC->p.cy = GC->p.y; GC->p.y = GC->p.y1; GC->p.y1 = GC->p.cy; + if (g->p.y1 < g->p.y) { + g->p.cy = g->p.y; g->p.y = g->p.y1; g->p.y1 = g->p.cy; } // Clipping #if NEED_CLIPPING - if (GC->p.x < GC->clipx0 || GC->p.x >= GC->clipx1) return; - if (GC->p.y < GC->clipy0) GC->p.y = GC->clipy0; - if (GC->p.y1 >= GC->clipy1) GC->p.y1 = GC->clipy1 - 1; - if (GC->p.y1 < GC->p.y) return; + if (g->p.x < g->clipx0 || g->p.x >= g->clipx1) return; + if (g->p.y < g->clipy0) g->p.y = g->clipy0; + if (g->p.y1 >= g->clipy1) g->p.y1 = g->clipy1 - 1; + if (g->p.y1 < g->p.y) return; #endif // This is an optimization for the point case. It is only worthwhile however if we // have hardware fills or if we support both hardware pixel drawing and hardware streaming #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) || (GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE) // Is this a point - if (GC->p.y == GC->p.y1) { + if (g->p.y == g->p.y1) { #if GDISP_HARDWARE_DRAWPIXEL // Best is hardware accelerated pixel draw - gdisp_lld_draw_pixel(GC); + gdisp_lld_draw_pixel(g); #elif GDISP_HARDWARE_STREAM_POS // Next best is cursor based streaming - if (!(GC->flags & GDISP_FLG_SCRSTREAM)) - setglobalwindow(); - gdisp_lld_write_pos(GC); - gdisp_lld_write_color(GC); + if (!(g->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(g); + gdisp_lld_write_pos(g); + gdisp_lld_write_color(g); #else // Worst is streaming - GC->p.cx = GC->p.cy = 1; - gdisp_lld_write_start(GC); - gdisp_lld_write_color(GC); - gdisp_lld_write_stop(GC); + g->p.cx = g->p.cy = 1; + gdisp_lld_write_start(g); + gdisp_lld_write_color(g); + gdisp_lld_write_stop(g); #endif return; } @@ -274,48 +285,48 @@ static void vline_clip(void) { #if GDISP_HARDWARE_FILLS // Best is hardware accelerated area fill - GC->p.cy = GC->p.y1 - GC->p.y + 1; - GC->p.cx = 1; - gdisp_lld_fill_area(GC); + g->p.cy = g->p.y1 - g->p.y + 1; + g->p.cx = 1; + gdisp_lld_fill_area(g); #elif GDISP_HARDWARE_STREAM_WRITE // Next best is streaming #if GDISP_HARDWARE_STREAM_POS - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - GC->p.cy = GC->p.y1 - GC->p.y + 1; - GC->p.cx = 1; - gdisp_lld_write_start(GC); + g->p.cy = g->p.y1 - g->p.y + 1; + g->p.cx = 1; + gdisp_lld_write_start(g); #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(GC); + gdisp_lld_write_pos(g); #endif - do { gdisp_lld_write_color(GC); } while(GC->p.cy--); - gdisp_lld_write_stop(GC); + do { gdisp_lld_write_color(g); } while(g->p.cy--); + gdisp_lld_write_stop(g); #else // Worst is drawing pixels - for(; GC->p.y <= GC->p.y1; GC->p.y++) - gdisp_lld_draw_pixel(GC); + for(; g->p.y <= g->p.y1; g->p.y++) + gdisp_lld_draw_pixel(g); #endif } // Parameters: x,y and x1,y1 // Alters: x,y x1,y1 cx,cy -static void line_clip(void) { +static void line_clip(GDisplay *g) { int16_t dy, dx; int16_t addx, addy; int16_t P, diff, i; // Is this a horizontal line (or a point) - if (GC->p.y == GC->p.y1) { - hline_clip(); + if (g->p.y == g->p.y1) { + hline_clip(g); return; } // Is this a vertical line (or a point) - if (GC->p.x == GC->p.x1) { - vline_clip(); + if (g->p.x == g->p.x1) { + vline_clip(g); return; } @@ -327,18 +338,18 @@ static void line_clip(void) { // When clipping is needed, all the clipping could also be done up front // instead of on each pixel. - if (GC->p.x1 >= GC->p.x) { - dx = GC->p.x1 - GC->p.x; + if (g->p.x1 >= g->p.x) { + dx = g->p.x1 - g->p.x; addx = 1; } else { - dx = GC->p.x - GC->p.x1; + dx = g->p.x - g->p.x1; addx = -1; } - if (GC->p.y1 >= GC->p.y) { - dy = GC->p.y1 - GC->p.y; + if (g->p.y1 >= g->p.y) { + dy = g->p.y1 - g->p.y; addy = 1; } else { - dy = GC->p.y - GC->p.y1; + dy = g->p.y - g->p.y1; addy = -1; } @@ -348,14 +359,14 @@ static void line_clip(void) { diff = P - dx; for(i=0; i<=dx; ++i) { - drawpixel_clip(); + drawpixel_clip(g); if (P < 0) { P += dy; - GC->p.x += addx; + g->p.x += addx; } else { P += diff; - GC->p.x += addx; - GC->p.y += addy; + g->p.x += addx; + g->p.y += addy; } } } else { @@ -364,90 +375,126 @@ static void line_clip(void) { diff = P - dy; for(i=0; i<=dy; ++i) { - drawpixel_clip(); + drawpixel_clip(g); if (P < 0) { P += dx; - GC->p.y += addy; + g->p.y += addy; } else { P += diff; - GC->p.x += addx; - GC->p.y += addy; + g->p.x += addx; + g->p.y += addy; } } } } +#if GDISP_STARTUP_LOGO_TIMEOUT > 0 + static void StatupLogoDisplay(GDisplay *g) { + gdispGClear(g, Black); + gdispGFillArea(g, g->g.Width/4, g->g.Height/4, g->g.Width/2, g->g.Height/2, Blue); + } +#endif + /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ /* Our module initialiser */ void _gdispInit(void) { - MUTEX_INIT(); + GDisplay *g; + unsigned i; + #if GDISP_TOTAL_CONTROLLERS > 1 + unsigned j; + #endif + /* Initialise driver */ - MUTEX_ENTER(); - GC->flags = 0; - gdisp_lld_init(GC); - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - #if GDISP_HARDWARE_CLIP - GC->p.x = x; - GC->p.y = y; - GC->p.cx = cx; - GC->p.cy = cy; - gdisp_lld_set_clip(GC); - #else - GC->clipx0 = 0; - GC->clipy0 = 0; - GC->clipx1 = GC->g.Width; - GC->clipy1 = GC->g.Height; - #endif + #if GDISP_TOTAL_CONTROLLERS > 1 + for(g = GDisplayArray, j=0; j < GDISP_TOTAL_CONTROLLERS; j++) + for(i = 0; i < DisplayCountList[j]; g++, i++) { + g->vmt = ControllerList[j]; + #else + for(g = GDisplayArray, i = 0; i < GDISP_TOTAL_DISPLAYS; g++, i++) { #endif - MUTEX_EXIT(); + MUTEX_INIT(g); + MUTEX_ENTER(g); + g->flags = 0; + gdisp_lld_init(g, i); + #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + #if GDISP_HARDWARE_CLIP + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + gdisp_lld_set_clip(g); + #else + g->clipx0 = 0; + g->clipy0 = 0; + g->clipx1 = g->g.Width; + g->clipy1 = g->g.Height; + #endif + #endif + MUTEX_EXIT(g); + #if GDISP_STARTUP_LOGO_TIMEOUT > 0 + StatupLogoDisplay(g); + #else + gdispGClear(g, Black); + #endif + } + #if GDISP_STARTUP_LOGO_TIMEOUT > 0 + gfxSleepMilliseconds(GDISP_STARTUP_LOGO_TIMEOUT); + for(g = GDisplayArray, i = 0; i < GDISP_TOTAL_DISPLAYS; g++, i++) + gdispGClear(g, Black); + #endif +} + +void gdispSetDisplay(unsigned display) { + if (display < GDISP_TOTAL_DISPLAYS) + GDISP = &GDisplayArray[display]; } #if GDISP_NEED_STREAMING - void gdispStreamStart(coord_t x, coord_t y, coord_t cx, coord_t cy) { - MUTEX_ENTER(); + void gdispGStreamStart(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy) { + MUTEX_ENTER(g); #if NEED_CLIPPING // Test if the area is valid - if not then exit - if (x < GC->clipx0 || x+cx > GC->clipx1 || y < GC->clipy0 || y+cy > GC->clipy1) { - MUTEX_EXIT(); + if (x < g->clipx0 || x+cx > g->clipx1 || y < g->clipy0 || y+cy > g->clipy1) { + MUTEX_EXIT(g); return; } #endif - GC->flags |= GDISP_FLG_INSTREAM; + g->flags |= GDISP_FLG_INSTREAM; #if GDISP_HARDWARE_STREAM_WRITE // Best is hardware streaming - GC->p.x = x; - GC->p.y = y; - GC->p.cx = cx; - GC->p.cy = cy; - gdisp_lld_write_start(GC); + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + gdisp_lld_write_start(g); #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(GC); + gdisp_lld_write_pos(g); #endif #else // Worst - save the parameters and use pixel drawing // Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position, cx = bufpos - GC->p.x1 = GC->p.x = x; - GC->p.y1 = GC->p.y = y; - GC->p.x2 = x + cx; - GC->p.y2 = y + cy; + g->p.x1 = g->p.x = x; + g->p.y1 = g->p.y = y; + g->p.x2 = x + cx; + g->p.y2 = y + cy; #if (GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS) || GDISP_HARDWARE_FILLS - GC->p.cx = 0; - GC->p.cy = 1; + g->p.cx = 0; + g->p.cy = 1; #endif #endif // Don't release the mutex as gdispStreamEnd() will do that. } - void gdispStreamColor(color_t color) { + void gdispGStreamColor(GDisplay *g, color_t color) { #if !GDISP_HARDWARE_STREAM_WRITE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS coord_t sx1, sy1; #endif @@ -455,224 +502,224 @@ void _gdispInit(void) { // Don't touch the mutex as we should already own it // Ignore this call if we are not streaming - if (!(GC->flags & GDISP_FLG_INSTREAM)) + if (!(g->flags & GDISP_FLG_INSTREAM)) return; #if GDISP_HARDWARE_STREAM_WRITE // Best is hardware streaming - GC->p.color = color; - gdisp_lld_write_color(GC); + g->p.color = color; + gdisp_lld_write_color(g); #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS - GC->linebuf[GC->p.cx++] = color; - if (GC->p.cx >= GDISP_LINEBUF_SIZE) { - sx1 = GC->p.x1; - sy1 = GC->p.y1; - GC->p.x1 = 0; - GC->p.y1 = 0; - GC->p.ptr = (void *)GC->linebuf; - gdisp_lld_blit_area(GC); - GC->p.x1 = sx1; - GC->p.y1 = sy1; - GC->p.x += GC->p.cx; - GC->p.cx = 0; + g->linebuf[g->p.cx++] = color; + if (g->p.cx >= GDISP_LINEBUF_SIZE) { + sx1 = g->p.x1; + sy1 = g->p.y1; + g->p.x1 = 0; + g->p.y1 = 0; + g->p.ptr = (void *)g->linebuf; + gdisp_lld_blit_area(g); + g->p.x1 = sx1; + g->p.y1 = sy1; + g->p.x += g->p.cx; + g->p.cx = 0; } // Just wrap at end-of-line and end-of-buffer - if (GC->p.x+GC->p.cx >= GC->p.x2) { - if (GC->p.cx) { - sx1 = GC->p.x1; - sy1 = GC->p.y1; - GC->p.x1 = 0; - GC->p.y1 = 0; - GC->p.ptr = (void *)GC->linebuf; - gdisp_lld_blit_area(GC); - GC->p.x1 = sx1; - GC->p.y1 = sy1; - GC->p.cx = 0; + if (g->p.x+g->p.cx >= g->p.x2) { + if (g->p.cx) { + sx1 = g->p.x1; + sy1 = g->p.y1; + g->p.x1 = 0; + g->p.y1 = 0; + g->p.ptr = (void *)g->linebuf; + gdisp_lld_blit_area(g); + g->p.x1 = sx1; + g->p.y1 = sy1; + g->p.cx = 0; } - GC->p.x = GC->p.x1; - if (++GC->p.y >= GC->p.y2) - GC->p.y = GC->p.y1; + g->p.x = g->p.x1; + if (++g->p.y >= g->p.y2) + g->p.y = g->p.y1; } #elif GDISP_HARDWARE_FILLS // Only slightly better than drawing pixels is to look for runs and use fill area - if (!GC->p.cx || GC->p.color == color) { - GC->p.cx++; - GC->p.color = color; + if (!g->p.cx || g->p.color == color) { + g->p.cx++; + g->p.color = color; } else { - if (GC->p.cx == 1) - gdisp_lld_draw_pixel(GC); + if (g->p.cx == 1) + gdisp_lld_draw_pixel(g); else - gdisp_lld_fill_area(GC); - GC->p.x += GC->p.cx; - GC->p.color = color; - GC->p.cx = 1; + gdisp_lld_fill_area(g); + g->p.x += g->p.cx; + g->p.color = color; + g->p.cx = 1; } // Just wrap at end-of-line and end-of-buffer - if (GC->p.x+GC->p.cx >= GC->p.x2) { - if (GC->p.cx) { - if (GC->p.cx == 1) - gdisp_lld_draw_pixel(GC); + if (g->p.x+g->p.cx >= g->p.x2) { + if (g->p.cx) { + if (g->p.cx == 1) + gdisp_lld_draw_pixel(g); else - gdisp_lld_fill_area(GC); - GC->p.cx = 0; + gdisp_lld_fill_area(g); + g->p.cx = 0; } - GC->p.x = GC->p.x1; - if (++GC->p.y >= GC->p.y2) - GC->p.y = GC->p.y1; + g->p.x = g->p.x1; + if (++g->p.y >= g->p.y2) + g->p.y = g->p.y1; } #else // Worst is using pixel drawing - GC->p.color = color; - gdisp_lld_draw_pixel(GC); + g->p.color = color; + gdisp_lld_draw_pixel(g); // Just wrap at end-of-line and end-of-buffer - if (++GC->p.x >= GC->p.x2) { - GC->p.x = GC->p.x1; - if (++GC->p.y >= GC->p.y2) - GC->p.y = GC->p.y1; + if (++g->p.x >= g->p.x2) { + g->p.x = g->p.x1; + if (++g->p.y >= g->p.y2) + g->p.y = g->p.y1; } #endif } - void gdispStreamStop(void) { + void gdispGStreamStop(GDisplay *g) { // Only release the mutex and end the stream if we are actually streaming. - if (!(GC->flags & GDISP_FLG_INSTREAM)) + if (!(g->flags & GDISP_FLG_INSTREAM)) return; #if GDISP_HARDWARE_STREAM_WRITE - gdisp_lld_write_stop(GC); + gdisp_lld_write_stop(g); #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS - if (GC->p.cx) { - GC->p.x1 = 0; - GC->p.y1 = 0; - GC->p.ptr = (void *)GC->linebuf; - gdisp_lld_blit_area(GC); + if (g->p.cx) { + g->p.x1 = 0; + g->p.y1 = 0; + g->p.ptr = (void *)g->linebuf; + gdisp_lld_blit_area(g); } #elif GDISP_HARDWARE_FILLS - if (GC->p.cx) { - if (GC->p.cx == 1) - gdisp_lld_draw_pixel(GC); + if (g->p.cx) { + if (g->p.cx == 1) + gdisp_lld_draw_pixel(g); else - gdisp_lld_fill_area(GC); + gdisp_lld_fill_area(g); } #endif - GC->flags &= ~GDISP_FLG_INSTREAM; - MUTEX_EXIT(); + g->flags &= ~GDISP_FLG_INSTREAM; + MUTEX_EXIT(g); } #endif -void gdispDrawPixel(coord_t x, coord_t y, color_t color) { - MUTEX_ENTER(); - GC->p.x = x; - GC->p.y = y; - GC->p.color = color; - drawpixel_clip(); +void gdispGDrawPixel(GDisplay *g, coord_t x, coord_t y, color_t color) { + MUTEX_ENTER(g); + g->p.x = x; + g->p.y = y; + g->p.color = color; + drawpixel_clip(g); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } -void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { - MUTEX_ENTER(); - GC->p.x = x0; - GC->p.y = y0; - GC->p.x1 = x1; - GC->p.y1 = y1; - GC->p.color = color; - line_clip(); +void gdispGDrawLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { + MUTEX_ENTER(g); + g->p.x = x0; + g->p.y = y0; + g->p.x1 = x1; + g->p.y1 = y1; + g->p.color = color; + line_clip(g); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } -void gdispClear(color_t color) { +void gdispGClear(GDisplay *g, color_t color) { // Note - clear() ignores the clipping area. It clears the screen. - MUTEX_ENTER(); + MUTEX_ENTER(g); #if GDISP_HARDWARE_CLEARS // Best is hardware accelerated clear - GC->p.color = color; - gdisp_lld_clear(GC); + g->p.color = color; + gdisp_lld_clear(g); #elif GDISP_HARDWARE_FILLS // Next best is hardware accelerated area fill - GC->p.x = GC->p.y = 0; - GC->p.cx = GC->g.Width; - GC->p.cy = GC->g.Height; - GC->p.color = color; - gdisp_lld_fill_area(GC); + g->p.x = g->p.y = 0; + g->p.cx = g->g.Width; + g->p.cy = g->g.Height; + g->p.color = color; + gdisp_lld_fill_area(g); #elif GDISP_HARDWARE_STREAM_WRITE // Next best is streaming uint32_t area; - GC->p.x = GC->p.y = 0; - GC->p.cx = GC->g.Width; - GC->p.cy = GC->g.Height; - GC->p.color = color; - area = (uint32_t)GC->p.cx * GC->p.cy; + g->p.x = g->p.y = 0; + g->p.cx = g->g.Width; + g->p.cy = g->g.Height; + g->p.color = color; + area = (uint32_t)g->p.cx * g->p.cy; - gdisp_lld_write_start(GC); + gdisp_lld_write_start(g); #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(GC); + gdisp_lld_write_pos(g); #endif for(; area; area--) - gdisp_lld_write_color(GC); - gdisp_lld_write_stop(GC); + gdisp_lld_write_color(g); + gdisp_lld_write_stop(g); #else // Worst is drawing pixels - GC->p.color = color; - for(GC->p.y = 0; GC->p.y < GC->g.Height; GC->p.y++) - for(GC->p.x = 0; GC->p.x < GC->g.Width; GC->p.x++) - gdisp_lld_draw_pixel(GC); + g->p.color = color; + for(g->p.y = 0; g->p.y < g->g.Height; g->p.y++) + for(g->p.x = 0; g->p.x < g->g.Width; g->p.x++) + gdisp_lld_draw_pixel(g); #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } -void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - MUTEX_ENTER(); - TEST_CLIP_AREA(x,y,cx,cy) { - GC->p.x = x; - GC->p.y = y; - GC->p.cx = cx; - GC->p.cy = cy; - GC->p.color = color; - fillarea(); +void gdispGFillArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { + MUTEX_ENTER(g); + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + g->p.color = color; + TEST_CLIP_AREA(g) { + fillarea(g); } - MUTEX_EXIT(); + MUTEX_EXIT(g); } -void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - MUTEX_ENTER(); +void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { + MUTEX_ENTER(g); #if NEED_CLIPPING - // This is a different cliping to fillarea() as it needs to take into account srcx,srcy - if (x < GC->clipx0) { cx -= GC->clipx0 - x; srcx += GC->clipx0 - x; x = GC->clipx0; } - if (y < GC->clipy0) { cy -= GC->clipy0 - y; srcy += GC->clipy0 - x; y = GC->clipy0; } - if (x+cx > GC->clipx1) cx = GC->clipx1 - x; - if (y+cy > GC->clipy1) cy = GC->clipy1 - y; + // This is a different cliping to fillarea(g) as it needs to take into account srcx,srcy + if (x < g->clipx0) { cx -= g->clipx0 - x; srcx += g->clipx0 - x; x = g->clipx0; } + if (y < g->clipy0) { cy -= g->clipy0 - y; srcy += g->clipy0 - x; y = g->clipy0; } + if (x+cx > g->clipx1) cx = g->clipx1 - x; + if (y+cy > g->clipy1) cy = g->clipy1 - y; if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0) { MUTEX_EXIT(); return; } + if (cx <= 0 || cy <= 0) { MUTEX_EXIT(g); return; } #endif #if GDISP_HARDWARE_BITFILLS // Best is hardware bitfills - GC->p.x = x; - GC->p.y = y; - GC->p.cx = cx; - GC->p.cy = cy; - GC->p.x1 = srcx; - GC->p.y1 = srcy; - GC->p.x2 = srccx; - GC->p.ptr = (void *)buffer; - gdisp_lld_blit_area(GC); + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + g->p.x1 = srcx; + g->p.y1 = srcy; + g->p.x2 = srccx; + g->p.ptr = (void *)buffer; + gdisp_lld_blit_area(g); #elif GDISP_HARDWARE_STREAM_WRITE // Next best is hardware streaming @@ -682,21 +729,21 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, srcy = y + cy; srccx -= cx; - GC->p.x = x; - GC->p.y = y; - GC->p.cx = cx; - GC->p.cy = cy; - gdisp_lld_write_start(GC); + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + gdisp_lld_write_start(g); #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(GC); + gdisp_lld_write_pos(g); #endif - for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { - for(GC->p.x = x; GC->p.x < srcx; GC->p.x++) { - GC->p.color = *buffer++; - gdisp_lld_write_color(GC); + for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) { + for(g->p.x = x; g->p.x < srcx; g->p.x++) { + g->p.color = *buffer++; + gdisp_lld_write_color(g); } } - gdisp_lld_write_stop(GC); + gdisp_lld_write_stop(g); #elif GDISP_HARDWARE_FILLS // Only slightly better than drawing pixels is to look for runs and use fill area @@ -706,19 +753,19 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, srcy = y + cy; srccx -= cx; - GC->p.cy = 1; - for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { - for(GC->p.x=x; GC->p.x < srcx; GC->p.x += GC->p.cx) { - GC->p.cx=1; - GC->p.color = *buffer++; - while(GC->p.x+GC->p.cx < srcx && *buffer == GC->p.color) { - GC->p.cx++; + g->p.cy = 1; + for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) { + for(g->p.x=x; g->p.x < srcx; g->p.x += g->p.cx) { + g->p.cx=1; + g->p.color = *buffer++; + while(g->p.x+g->p.cx < srcx && *buffer == g->p.color) { + g->p.cx++; buffer++; } - if (GC->p.cx == 1) { - gdisp_lld_draw_pixel(GC); + if (g->p.cx == 1) { + gdisp_lld_draw_pixel(g); } else { - gdisp_lld_fill_area(GC); + gdisp_lld_fill_area(g); } } } @@ -731,135 +778,135 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, srcy = y + cy; srccx -= cx; - for(GC->p.y = y; GC->p.y < srcy; GC->p.y++, buffer += srccx) { - for(GC->p.x=x; GC->p.x < srcx; GC->p.x++) { - GC->p.color = *buffer++; - gdisp_lld_draw_pixel(GC); + for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) { + for(g->p.x=x; g->p.x < srcx; g->p.x++) { + g->p.color = *buffer++; + gdisp_lld_draw_pixel(g); } } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #if GDISP_NEED_CLIP - void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy) { - MUTEX_ENTER(); + void gdispGSetClip(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy) { + MUTEX_ENTER(g); #if GDISP_HARDWARE_CLIP // Best is using hardware clipping - GC->p.x = x; - GC->p.y = y; - GC->p.cx = cx; - GC->p.cy = cy; - gdisp_lld_set_clip(GC); + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + gdisp_lld_set_clip(g); #else // Worst is using software clipping if (x < 0) { cx += x; x = 0; } if (y < 0) { cy += y; y = 0; } - if (cx <= 0 || cy <= 0 || x >= GC->g.Width || y >= GC->g.Height) { MUTEX_EXIT(); return; } - GC->clipx0 = x; - GC->clipy0 = y; - GC->clipx1 = x+cx; if (GC->clipx1 > GC->g.Width) GC->clipx1 = GC->g.Width; - GC->clipy1 = y+cy; if (GC->clipy1 > GC->g.Height) GC->clipy1 = GC->g.Height; + if (cx <= 0 || cy <= 0 || x >= g->g.Width || y >= g->g.Height) { MUTEX_EXIT(g); return; } + g->clipx0 = x; + g->clipy0 = y; + g->clipx1 = x+cx; if (g->clipx1 > g->g.Width) g->clipx1 = g->g.Width; + g->clipy1 = y+cy; if (g->clipy1 > g->g.Height) g->clipy1 = g->g.Height; #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #endif #if GDISP_NEED_CIRCLE - void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color) { + void gdispGDrawCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color) { coord_t a, b, P; - MUTEX_ENTER(); + MUTEX_ENTER(g); // Calculate intermediates a = 1; b = radius; P = 4 - radius; - GC->p.color = color; + g->p.color = color; // Away we go using Bresenham's circle algorithm // Optimized to prevent double drawing - GC->p.x = x; GC->p.y = y + b; drawpixel_clip(); - GC->p.x = x; GC->p.y = y - b; drawpixel_clip(); - GC->p.x = x + b; GC->p.y = y; drawpixel_clip(); - GC->p.x = x - b; GC->p.y = y; drawpixel_clip(); + g->p.x = x; g->p.y = y + b; drawpixel_clip(g); + g->p.x = x; g->p.y = y - b; drawpixel_clip(g); + g->p.x = x + b; g->p.y = y; drawpixel_clip(g); + g->p.x = x - b; g->p.y = y; drawpixel_clip(g); do { - GC->p.x = x + a; GC->p.y = y + b; drawpixel_clip(); - GC->p.x = x + a; GC->p.y = y - b; drawpixel_clip(); - GC->p.x = x + b; GC->p.y = y + a; drawpixel_clip(); - GC->p.x = x - b; GC->p.y = y + a; drawpixel_clip(); - GC->p.x = x - a; GC->p.y = y + b; drawpixel_clip(); - GC->p.x = x - a; GC->p.y = y - b; drawpixel_clip(); - GC->p.x = x + b; GC->p.y = y - a; drawpixel_clip(); - GC->p.x = x - b; GC->p.y = y - a; drawpixel_clip(); + g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g); + g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g); + g->p.x = x + b; g->p.y = y + a; drawpixel_clip(g); + g->p.x = x - b; g->p.y = y + a; drawpixel_clip(g); + g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g); + g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g); + g->p.x = x + b; g->p.y = y - a; drawpixel_clip(g); + g->p.x = x - b; g->p.y = y - a; drawpixel_clip(g); if (P < 0) P += 3 + 2*a++; else P += 5 + 2*(a++ - b--); } while(a < b); - GC->p.x = x + a; GC->p.y = y + b; drawpixel_clip(); - GC->p.x = x + a; GC->p.y = y - b; drawpixel_clip(); - GC->p.x = x - a; GC->p.y = y + b; drawpixel_clip(); - GC->p.x = x - a; GC->p.y = y - b; drawpixel_clip(); + g->p.x = x + a; g->p.y = y + b; drawpixel_clip(g); + g->p.x = x + a; g->p.y = y - b; drawpixel_clip(g); + g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g); + g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #endif #if GDISP_NEED_CIRCLE - void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color) { + void gdispGFillCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius, color_t color) { coord_t a, b, P; - MUTEX_ENTER(); + MUTEX_ENTER(g); // Calculate intermediates a = 1; b = radius; P = 4 - radius; - GC->p.color = color; + g->p.color = color; // Away we go using Bresenham's circle algorithm // This is optimized to prevent overdrawing by drawing a line only when a variable is about to change value - GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); - GC->p.y = y+b; GC->p.x = x; drawpixel_clip(); - GC->p.y = y-b; GC->p.x = x; drawpixel_clip(); + g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); + g->p.y = y+b; g->p.x = x; drawpixel_clip(g); + g->p.y = y-b; g->p.x = x; drawpixel_clip(g); do { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); if (P < 0) { P += 3 + 2*a++; } else { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); + g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); P += 5 + 2*(a++ - b--); } } while(a < b); - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #endif #if GDISP_NEED_ELLIPSE - void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { + void gdispGDrawEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { coord_t dx, dy; int32_t a2, b2; int32_t err, e2; - MUTEX_ENTER(); + MUTEX_ENTER(g); // Calculate intermediates dx = 0; @@ -867,14 +914,14 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, a2 = a*a; b2 = b*b; err = b2-(2*b-1)*a2; - GC->p.color = color; + g->p.color = color; // Away we go using Bresenham's ellipse algorithm do { - GC->p.x = x + dx; GC->p.y = y + dy; drawpixel_clip(); - GC->p.x = x - dx; GC->p.y = y + dy; drawpixel_clip(); - GC->p.x = x - dx; GC->p.y = y - dy; drawpixel_clip(); - GC->p.x = x + dx; GC->p.y = y - dy; drawpixel_clip(); + g->p.x = x + dx; g->p.y = y + dy; drawpixel_clip(g); + g->p.x = x - dx; g->p.y = y + dy; drawpixel_clip(g); + g->p.x = x - dx; g->p.y = y - dy; drawpixel_clip(g); + g->p.x = x + dx; g->p.y = y - dy; drawpixel_clip(g); e2 = 2*err; if(e2 < (2*dx+1)*b2) { @@ -888,22 +935,22 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, } while(dy >= 0); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #endif #if GDISP_NEED_ELLIPSE - void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { + void gdispGFillEllipse(GDisplay *g, coord_t x, coord_t y, coord_t a, coord_t b, color_t color) { coord_t dx, dy; int32_t a2, b2; int32_t err, e2; - MUTEX_ENTER(); + MUTEX_ENTER(g); // Calculate intermediates dx = 0; @@ -911,7 +958,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, a2 = a*a; b2 = b*b; err = b2-(2*b-1)*a2; - GC->p.color = color; + g->p.color = color; // Away we go using Bresenham's ellipse algorithm // This is optimized to prevent overdrawing by drawing a line only when a y is about to change value @@ -922,20 +969,20 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, err += (2*dx+1)*b2; } if(e2 > -(2*dy-1)*a2) { - GC->p.y = y + dy; GC->p.x = x - dx; GC->p.x1 = x + dx; hline_clip(); - if (y) { GC->p.y = y - dy; GC->p.x = x - dx; GC->p.x1 = x + dx; hline_clip(); } + g->p.y = y + dy; g->p.x = x - dx; g->p.x1 = x + dx; hline_clip(g); + if (y) { g->p.y = y - dy; g->p.x = x - dx; g->p.x1 = x + dx; hline_clip(g); } dy--; err -= (2*dy-1)*a2; } } while(dy >= 0); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #endif @@ -944,7 +991,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, #include #endif - void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { + void gdispGDrawArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { coord_t a, b, P, sedge, eedge; uint8_t full, sbit, ebit, tbit; @@ -970,8 +1017,8 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, for(tbit=sbit<<1; tbit < ebit; tbit<<=1) full |= tbit; } - MUTEX_ENTER(); - GC->p.color = color; + MUTEX_ENTER(g); + g->p.color = color; if (full) { // Draw full sectors @@ -979,33 +1026,33 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, a = 1; b = radius; P = 4 - radius; - if (full & 0x60) { GC->p.y = y+b; GC->p.x = x; drawpixel_clip(); } - if (full & 0x06) { GC->p.y = y-b; GC->p.x = x; drawpixel_clip(); } - if (full & 0x81) { GC->p.y = y; GC->p.x = x+b; drawpixel_clip(); } - if (full & 0x18) { GC->p.y = y; GC->p.x = x-b; drawpixel_clip(); } + if (full & 0x60) { g->p.y = y+b; g->p.x = x; drawpixel_clip(g); } + if (full & 0x06) { g->p.y = y-b; g->p.x = x; drawpixel_clip(g); } + if (full & 0x81) { g->p.y = y; g->p.x = x+b; drawpixel_clip(g); } + if (full & 0x18) { g->p.y = y; g->p.x = x-b; drawpixel_clip(g); } do { - if (full & 0x01) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } - if (full & 0x02) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } - if (full & 0x04) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } - if (full & 0x08) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } - if (full & 0x10) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } - if (full & 0x20) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } - if (full & 0x40) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } - if (full & 0x80) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (full & 0x01) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); } + if (full & 0x02) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); } + if (full & 0x04) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); } + if (full & 0x08) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); } + if (full & 0x10) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); } + if (full & 0x20) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } + if (full & 0x40) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); } + if (full & 0x80) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); } if (P < 0) P += 3 + 2*a++; else P += 5 + 2*(a++ - b--); } while(a < b); - if (full & 0xC0) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } - if (full & 0x0C) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } - if (full & 0x03) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } - if (full & 0x30) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + if (full & 0xC0) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); } + if (full & 0x0C) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); } + if (full & 0x03) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); } + if (full & 0x30) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } if (full == 0xFF) { #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif MUTEX_EXIT; @@ -1032,116 +1079,116 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, a = 1; b = radius; P = 4 - radius; - if ((sbit & 0x20) || (ebit & 0x40)) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); } - if ((sbit & 0x02) || (ebit & 0x04)) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); } - if ((sbit & 0x80) || (ebit & 0x01)) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); } - if ((sbit & 0x08) || (ebit & 0x10)) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); } + if ((sbit & 0x20) || (ebit & 0x40)) { g->p.x = x; g->p.y = y+b; drawpixel_clip(g); } + if ((sbit & 0x02) || (ebit & 0x04)) { g->p.x = x; g->p.y = y-b; drawpixel_clip(g); } + if ((sbit & 0x80) || (ebit & 0x01)) { g->p.x = x+b; g->p.y = y; drawpixel_clip(g); } + if ((sbit & 0x08) || (ebit & 0x10)) { g->p.x = x-b; g->p.y = y; drawpixel_clip(g); } do { - if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } - if (((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } - if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } - if (((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } - if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } - if (((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } - if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } - if (((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge)) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); } + if (((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); } + if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge)) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); } + if (((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); } + if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge)) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); } + if (((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } + if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge)) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); } + if (((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); } if (P < 0) P += 3 + 2*a++; else P += 5 + 2*(a++ - b--); } while(a < b); if (((sbit & 0x40) && a >= sedge) || ((ebit & 0x40) && a <= eedge) || ((sbit & 0x80) && a <= sedge) || ((ebit & 0x80) && a >= eedge)) - { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); } if (((sbit & 0x04) && a >= sedge) || ((ebit & 0x04) && a <= eedge) || ((sbit & 0x08) && a <= sedge) || ((ebit & 0x08) && a >= eedge)) - { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); } if (((sbit & 0x01) && a >= sedge) || ((ebit & 0x01) && a <= eedge) || ((sbit & 0x02) && a <= sedge) || ((ebit & 0x02) && a >= eedge)) - { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); } if (((sbit & 0x10) && a >= sedge) || ((ebit & 0x10) && a <= eedge) || ((sbit & 0x20) && a <= sedge) || ((ebit & 0x20) && a >= eedge)) - { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } } else if (end < start) { // Draw start/end sector where it is a non-internal angle // Optimized to prevent double drawing a = 1; b = radius; P = 4 - radius; - if (sbit & 0x60) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); } - if (sbit & 0x06) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); } - if (sbit & 0x81) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); } - if (sbit & 0x18) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); } + if (sbit & 0x60) { g->p.x = x; g->p.y = y+b; drawpixel_clip(g); } + if (sbit & 0x06) { g->p.x = x; g->p.y = y-b; drawpixel_clip(g); } + if (sbit & 0x81) { g->p.x = x+b; g->p.y = y; drawpixel_clip(g); } + if (sbit & 0x18) { g->p.x = x-b; g->p.y = y; drawpixel_clip(g); } do { - if ((sbit & 0x01) && (a >= sedge || a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } - if ((sbit & 0x02) && (a <= sedge || a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } - if ((sbit & 0x04) && (a >= sedge || a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } - if ((sbit & 0x08) && (a <= sedge || a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } - if ((sbit & 0x10) && (a >= sedge || a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } - if ((sbit & 0x20) && (a <= sedge || a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } - if ((sbit & 0x40) && (a >= sedge || a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } - if ((sbit & 0x80) && (a <= sedge || a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if ((sbit & 0x01) && (a >= sedge || a <= eedge)) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); } + if ((sbit & 0x02) && (a <= sedge || a >= eedge)) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); } + if ((sbit & 0x04) && (a >= sedge || a <= eedge)) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); } + if ((sbit & 0x08) && (a <= sedge || a >= eedge)) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); } + if ((sbit & 0x10) && (a >= sedge || a <= eedge)) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); } + if ((sbit & 0x20) && (a <= sedge || a >= eedge)) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } + if ((sbit & 0x40) && (a >= sedge || a <= eedge)) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); } + if ((sbit & 0x80) && (a <= sedge || a >= eedge)) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); } if (P < 0) P += 3 + 2*a++; else P += 5 + 2*(a++ - b--); } while(a < b); if (((sbit & 0x04) && (a >= sedge || a <= eedge)) || ((sbit & 0x08) && (a <= sedge || a >= eedge))) - { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); } if (((sbit & 0x40) && (a >= sedge || a <= eedge)) || ((sbit & 0x80) && (a <= sedge || a >= eedge))) - { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); } if (((sbit & 0x01) && (a >= sedge || a <= eedge)) || ((sbit & 0x02) && (a <= sedge || a >= eedge))) - { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); } if (((sbit & 0x10) && (a >= sedge || a <= eedge)) || ((sbit & 0x20) && (a <= sedge || a >= eedge))) - { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } } else { // Draw start/end sector where it is a internal angle // Optimized to prevent double drawing a = 1; b = radius; P = 4 - radius; - if (((sbit & 0x20) && !eedge) || ((sbit & 0x40) && !sedge)) { GC->p.x = x; GC->p.y = y+b; drawpixel_clip(); } - if (((sbit & 0x02) && !eedge) || ((sbit & 0x04) && !sedge)) { GC->p.x = x; GC->p.y = y-b; drawpixel_clip(); } - if (((sbit & 0x80) && !eedge) || ((sbit & 0x01) && !sedge)) { GC->p.x = x+b; GC->p.y = y; drawpixel_clip(); } - if (((sbit & 0x08) && !eedge) || ((sbit & 0x10) && !sedge)) { GC->p.x = x-b; GC->p.y = y; drawpixel_clip(); } + if (((sbit & 0x20) && !eedge) || ((sbit & 0x40) && !sedge)) { g->p.x = x; g->p.y = y+b; drawpixel_clip(g); } + if (((sbit & 0x02) && !eedge) || ((sbit & 0x04) && !sedge)) { g->p.x = x; g->p.y = y-b; drawpixel_clip(g); } + if (((sbit & 0x80) && !eedge) || ((sbit & 0x01) && !sedge)) { g->p.x = x+b; g->p.y = y; drawpixel_clip(g); } + if (((sbit & 0x08) && !eedge) || ((sbit & 0x10) && !sedge)) { g->p.x = x-b; g->p.y = y; drawpixel_clip(g); } do { - if (((sbit & 0x01) && a >= sedge && a <= eedge)) { GC->p.x = x+b; GC->p.y = y-a; drawpixel_clip(); } - if (((sbit & 0x02) && a <= sedge && a >= eedge)) { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } - if (((sbit & 0x04) && a >= sedge && a <= eedge)) { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } - if (((sbit & 0x08) && a <= sedge && a >= eedge)) { GC->p.x = x-b; GC->p.y = y-a; drawpixel_clip(); } - if (((sbit & 0x10) && a >= sedge && a <= eedge)) { GC->p.x = x-b; GC->p.y = y+a; drawpixel_clip(); } - if (((sbit & 0x20) && a <= sedge && a >= eedge)) { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } - if (((sbit & 0x40) && a >= sedge && a <= eedge)) { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } - if (((sbit & 0x80) && a <= sedge && a >= eedge)) { GC->p.x = x+b; GC->p.y = y+a; drawpixel_clip(); } + if (((sbit & 0x01) && a >= sedge && a <= eedge)) { g->p.x = x+b; g->p.y = y-a; drawpixel_clip(g); } + if (((sbit & 0x02) && a <= sedge && a >= eedge)) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); } + if (((sbit & 0x04) && a >= sedge && a <= eedge)) { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); } + if (((sbit & 0x08) && a <= sedge && a >= eedge)) { g->p.x = x-b; g->p.y = y-a; drawpixel_clip(g); } + if (((sbit & 0x10) && a >= sedge && a <= eedge)) { g->p.x = x-b; g->p.y = y+a; drawpixel_clip(g); } + if (((sbit & 0x20) && a <= sedge && a >= eedge)) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } + if (((sbit & 0x40) && a >= sedge && a <= eedge)) { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); } + if (((sbit & 0x80) && a <= sedge && a >= eedge)) { g->p.x = x+b; g->p.y = y+a; drawpixel_clip(g); } if (P < 0) P += 3 + 2*a++; else P += 5 + 2*(a++ - b--); } while(a < b); if (((sbit & 0x04) && a >= sedge && a <= eedge) || ((sbit & 0x08) && a <= sedge && a >= eedge)) - { GC->p.x = x-a; GC->p.y = y-b; drawpixel_clip(); } + { g->p.x = x-a; g->p.y = y-b; drawpixel_clip(g); } if (((sbit & 0x40) && a >= sedge && a <= eedge) || ((sbit & 0x80) && a <= sedge && a >= eedge)) - { GC->p.x = x+a; GC->p.y = y+b; drawpixel_clip(); } + { g->p.x = x+a; g->p.y = y+b; drawpixel_clip(g); } if (((sbit & 0x01) && a >= sedge && a <= eedge) || ((sbit & 0x02) && a <= sedge && a >= eedge)) - { GC->p.x = x+a; GC->p.y = y-b; drawpixel_clip(); } + { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); } if (((sbit & 0x10) && a >= sedge && a <= eedge) || ((sbit & 0x20) && a <= sedge && a >= eedge)) - { GC->p.x = x-a; GC->p.y = y+b; drawpixel_clip(); } + { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } } #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #endif #if GDISP_NEED_ARC - void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { + void gdispGFillArc(GDisplay *g, coord_t x, coord_t y, coord_t radius, coord_t start, coord_t end, color_t color) { coord_t a, b, P; coord_t sy, ey; fixed sxa, sxb, sxd, exa, exb, exd; uint8_t qtr; - MUTEX_ENTER(); + MUTEX_ENTER(g); // Do the trig to get the formulas for the start and end lines. sxa = exa = FIXED(x)+FIXED0_5; @@ -1170,7 +1217,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, a = 1; b = radius; P = 4 - radius; - GC->p.color = color; + g->p.color = color; sxb += sxa; exb += exa; @@ -1181,50 +1228,50 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, case 0: // S2E2 sy <= ey case 1: // S1E2 sy <= ey if (ey && sy) { - GC->p.x = x; GC->p.x1 = x; // E2S + g->p.x = x; g->p.x1 = x; // E2S sxa -= sxd; exa -= exd; } else if (sy) { - GC->p.x = x-b; GC->p.x1 = x; // C2S + g->p.x = x-b; g->p.x1 = x; // C2S sxa -= sxd; } else if (ey) { - GC->p.x = x; GC->p.x1 = x+b; // E2C + g->p.x = x; g->p.x1 = x+b; // E2C exa -= exd; } else { - GC->p.x = x-b; GC->p.x1 = x+b; // C2C + g->p.x = x-b; g->p.x1 = x+b; // C2C } - GC->p.y = y; - hline_clip(); + g->p.y = y; + hline_clip(g); do { if (-a >= ey) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g); // E2S sxa -= sxd; exa -= exd; } else if (-a >= sy) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S sxa -= sxd; } else if (qtr & 1) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (P < 0) { P += 3 + 2*a++; } else { if (-b >= ey) { - GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = NONFIXED(sxb); hline_clip(); // E2S + g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = NONFIXED(sxb); hline_clip(g); // E2S sxb += sxd; exb += exd; } else if (-b >= sy) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g); // C2S sxb += sxd; } else if (qtr & 1) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } P += 5 + 2*(a++ - b--); } } while(a < b); if (-a >= ey) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g); // E2S } else if (-a >= sy) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S } else if (qtr & 1) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } break; @@ -1236,92 +1283,92 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, case 19: // S4E2 sy > ey case 22: // S3E1 sy > ey case 23: // S4E1 sy > ey - GC->p.y = y; GC->p.x = x; GC->p.x1 = x+b; hline_clip(); // SE2C + g->p.y = y; g->p.x = x; g->p.x1 = x+b; hline_clip(g); // SE2C sxa += sxd; exa -= exd; do { if (-a >= ey) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C exa -= exd; } else if (!(qtr & 4)) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (a <= sy) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C sxa += sxd; } else if (!(qtr & 1)) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (P < 0) { P += 3 + 2*a++; } else { if (-b >= ey) { - GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g); // E2C exb += exd; } else if (!(qtr & 4)) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } if (b <= sy) { - GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g); // S2C sxb -= sxd; } else if (!(qtr & 1)) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } P += 5 + 2*(a++ - b--); } } while(a < b); if (-a >= ey) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C } else if (!(qtr & 4)) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (a <= sy) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+a; hline_clip(); // S2C + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+a; hline_clip(g); // S2C } else if (!(qtr & 1)) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+a; hline_clip(g); // C2C } break; case 4: // S2E1 sy <= ey case 5: // S1E1 sy <= ey - GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C do { if (-a >= ey) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C sxa -= sxd; exa -= exd; } else if (-a >= sy) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S sxa -= sxd; } else if (qtr & 1) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C if (P < 0) { P += 3 + 2*a++; } else { if (-b >= ey) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S - GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g); // C2S + g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g); // E2C sxb += sxd; exb += exd; } else if (-b >= sy) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g); // C2S sxb += sxd; } else if (qtr & 1) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C P += 5 + 2*(a++ - b--); } } while(a < b); if (-a >= ey) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C } else if (-a >= sy) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S } else if (qtr & 1) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C break; case 8: // S2E3 sy <= ey @@ -1332,261 +1379,261 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, case 25: // S1E3 sy > ey case 28: // S2E3 sy > ey case 29: // S1E3 sy > ey - GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x; hline_clip(); // C2SE + g->p.y = y; g->p.x = x-b; g->p.x1 = x; hline_clip(g); // C2SE sxa -= sxd; exa += exd; do { if (-a >= sy) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S sxa -= sxd; } else if (qtr & 1) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (a <= ey) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E exa += exd; } else if (qtr & 4) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (P < 0) { P += 3 + 2*a++; } else { if (-b >= sy) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S + g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g); // C2S sxb += sxd; } else if (qtr & 1) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } if (b <= ey) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g); // C2E exb -= exd; } else if (qtr & 4) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } P += 5 + 2*(a++ - b--); } } while(a < b); if (-a >= sy) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S } else if (qtr & 1) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (a <= ey) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E } else if (qtr & 4) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+a; hline_clip(g); // C2C } break; case 10: // S3E3 sy <= ey case 14: // S3E4 sy <= ey - GC->p.y = y; GC->p.x = x; drawpixel_clip(); // S2E + g->p.y = y; g->p.x = x; drawpixel_clip(g); // S2E sxa += sxd; exa += exd; do { if (a <= sy) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip(); // S2E + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = NONFIXED(exa); hline_clip(g); // S2E sxa += sxd; exa += exd; } else if (a <= ey) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E exa += exd; } else if (qtr & 4) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (P < 0) { P += 3 + 2*a++; } else { if (b <= sy) { - GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = NONFIXED(exb); hline_clip(); // S2E + g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = NONFIXED(exb); hline_clip(g); // S2E sxb -= sxd; exb -= exd; } else if (b <= ey) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g); // C2E exb -= exd; } else if (qtr & 4) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } P += 5 + 2*(a++ - b--); } } while(a < b); if (a <= sy) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip(); // S2E + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = NONFIXED(exa); hline_clip(g); // S2E } else if (a <= ey) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E } else if (qtr & 4) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } break; case 11: // S4E3 sy <= ey case 15: // S4E4 sy <= ey - GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C do { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C if (a <= sy) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C sxa += sxd; exa += exd; } else if (a <= ey) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E exa += exd; } else if (qtr & 4) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (P < 0) { P += 3 + 2*a++; } else { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C if (b <= sy) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E - GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g); // C2E + g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g); // S2C sxb -= sxd; exb -= exd; } else if (b <= ey) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E + g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g); // C2E exb -= exd; } else if (qtr & 4) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } P += 5 + 2*(a++ - b--); } } while(a < b); - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C if (a <= sy) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C } else if (a <= ey) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E } else if (qtr & 4) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } break; case 16: // S2E2 sy > ey case 20: // S2E1 sy > ey - GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C sxa -= sxd; exa -= exd; do { if (-a >= sy) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C sxa -= sxd; exa -= exd; } else if (-a >= ey) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C exa -= exd; } else if (!(qtr & 4)){ - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C if (P < 0) { P += 3 + 2*a++; } else { if (-b >= sy) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = NONFIXED(sxb); hline_clip(); // C2S - GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = NONFIXED(sxb); hline_clip(g); // C2S + g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g); // E2C sxb += sxd; exb += exd; } else if (-b >= ey) { - GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g); // E2C exb += exd; } else if (!(qtr & 4)){ - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C P += 5 + 2*(a++ - b--); } } while(a < b); if (-a >= sy) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = NONFIXED(sxa); hline_clip(); // C2S - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = NONFIXED(sxa); hline_clip(g); // C2S + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C } else if (-a >= ey) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C } else if (!(qtr & 4)){ - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C break; case 17: // S1E2 sy > ey case 21: // S1E1 sy > ey if (sy) { - GC->p.x = x; GC->p.x1 = x; // E2S + g->p.x = x; g->p.x1 = x; // E2S sxa -= sxd; exa -= exd; } else { - GC->p.x = x; GC->p.x1 = x+b; // E2C + g->p.x = x; g->p.x1 = x+b; // E2C exa -= exd; } - GC->p.y = y; - hline_clip(); + g->p.y = y; + hline_clip(g); do { if (-a >= sy) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g); // E2S sxa -= sxd; exa -= exd; } else if (-a >= ey) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C exa -= exd; } else if (!(qtr & 4)) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (P < 0) { P += 3 + 2*a++; } else { if (-b >= sy) { - GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = NONFIXED(sxb); hline_clip(); // E2S + g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = NONFIXED(sxb); hline_clip(g); // E2S sxb += sxd; exb += exd; } else if (-b >= ey) { - GC->p.y = y-b; GC->p.x = NONFIXED(exb); GC->p.x1 = x+a; hline_clip(); // E2C + g->p.y = y-b; g->p.x = NONFIXED(exb); g->p.x1 = x+a; hline_clip(g); // E2C exb += exd; } else if (!(qtr & 4)) { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } P += 5 + 2*(a++ - b--); } } while(a < b); if (-a >= sy) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = NONFIXED(sxa); hline_clip(); // E2S + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = NONFIXED(sxa); hline_clip(g); // E2S } else if (-a >= ey) { - GC->p.y = y-a; GC->p.x = NONFIXED(exa); GC->p.x1 = x+b; hline_clip(); // E2C + g->p.y = y-a; g->p.x = NONFIXED(exa); g->p.x1 = x+b; hline_clip(g); // E2C } else if (!(qtr & 4)) { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } break; case 26: // S3E3 sy > ey case 27: // S4E3 sy > ey - GC->p.y = y; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C do { - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C if (a <= ey) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C sxa += sxd; exa += exd; } else if (a <= sy) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C sxa += sxd; } else if (!(qtr & 1)) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (P < 0) { P += 3 + 2*a++; } else { - GC->p.y = y-b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y-b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C if (b <= ey) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = NONFIXED(exb); hline_clip(); // C2E - GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = NONFIXED(exb); hline_clip(g); // C2E + g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g); // S2C sxb -= sxd; exb -= exd; } else if (b <= sy) { - GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g); // S2C sxb -= sxd; } else if (!(qtr & 1)) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } P += 5 + 2*(a++ - b--); } } while(a < b); - GC->p.y = y-a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C if (a <= ey) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = NONFIXED(exa); hline_clip(); // C2E - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = NONFIXED(exa); hline_clip(g); // C2E + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C } else if (a <= sy) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C } else if (!(qtr & 4)) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } break; @@ -1594,52 +1641,52 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, case 31: // S4E4 sy > ey do { if (a <= ey) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = NONFIXED(exa); hline_clip(); // S2E + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = NONFIXED(exa); hline_clip(g); // S2E sxa += sxd; exa += exd; } else if (a <= sy) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C sxa += sxd; } else if (!(qtr & 1)) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } if (P < 0) { P += 3 + 2*a++; } else { if (b <= ey) { - GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = NONFIXED(exb); hline_clip(); // S2E + g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = NONFIXED(exb); hline_clip(g); // S2E sxb -= sxd; exb -= exd; } else if (b <= sy) { - GC->p.y = y+b; GC->p.x = NONFIXED(sxb); GC->p.x1 = x+a; hline_clip(); // S2C + g->p.y = y+b; g->p.x = NONFIXED(sxb); g->p.x1 = x+a; hline_clip(g); // S2C sxb -= sxd; } else if (!(qtr & 1)) { - GC->p.y = y+b; GC->p.x = x-a; GC->p.x1 = x+a; hline_clip(); // C2C + g->p.y = y+b; g->p.x = x-a; g->p.x1 = x+a; hline_clip(g); // C2C } P += 5 + 2*(a++ - b--); } } while(a < b); if (a <= ey) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C } else if (a <= sy) { - GC->p.y = y+a; GC->p.x = NONFIXED(sxa); GC->p.x1 = x+b; hline_clip(); // S2C + g->p.y = y+a; g->p.x = NONFIXED(sxa); g->p.x1 = x+b; hline_clip(g); // S2C } else if (!(qtr & 4)) { - GC->p.y = y+a; GC->p.x = x-b; GC->p.x1 = x+b; hline_clip(); // C2C + g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); // C2C } break; } #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #endif #if GDISP_NEED_ARC - void gdispDrawRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { + void gdispGDrawRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { if (2*radius > cx || 2*radius > cy) { gdispDrawBox(x, y, cx, cy, color); return; @@ -1656,7 +1703,7 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, #endif #if GDISP_NEED_ARC - void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { + void gdispGFillRoundedBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) { coord_t radius2; radius2 = radius*2; @@ -1675,49 +1722,49 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, #endif #if GDISP_NEED_PIXELREAD - color_t gdispGetPixelColor(coord_t x, coord_t y) { + color_t gdispGGetPixelColor(GDisplay *g, coord_t x, coord_t y) { color_t c; /* Always synchronous as it must return a value */ - MUTEX_ENTER(); + MUTEX_ENTER(g); #if GDISP_HARDWARE_PIXELREAD // Best is direct pixel read - GC->p.x = x; - GC->p.y = y; - c = gdisp_lld_get_pixel_color(GC); + g->p.x = x; + g->p.y = y; + c = gdisp_lld_get_pixel_color(g); #elif GDISP_HARDWARE_STREAM_READ // Next best is hardware streaming - GC->p.x = x; - GC->p.y = y; - GC->p.cx = 1; - GC->p.cy = 1; - gdisp_lld_read_start(GC); - c = gdisp_lld_read_color(GC); - gdisp_lld_read_stop(GC); + g->p.x = x; + g->p.y = y; + g->p.cx = 1; + g->p.cy = 1; + gdisp_lld_read_start(g); + c = gdisp_lld_read_color(g); + gdisp_lld_read_stop(g); #else // Worst is "not possible" #error "GDISP: GDISP_NEED_PIXELREAD has been set but there is no hardware support for reading the display" #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); return c; } #endif #if GDISP_NEED_SCROLL - void gdispVerticalScroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { + void gdispGVerticalScroll(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { coord_t abslines; #if !GDISP_HARDWARE_SCROLL coord_t fy, dy, ix, fx, i, j; #endif - MUTEX_ENTER(); + MUTEX_ENTER(g); #if NEED_CLIPPING - if (x < GC->clipx0) { cx -= GC->clipx0 - x; x = GC->clipx0; } - if (y < GC->clipy0) { cy -= GC->clipy0 - y; y = GC->clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GC->clipx1 || y >= GC->clipy1) { MUTEX_EXIT(); return; } - if (x+cx > GC->clipx1) cx = GC->clipx1 - x; - if (y+cy > GC->clipy1) cy = GC->clipy1 - y; + if (x < g->clipx0) { cx -= g->clipx0 - x; x = g->clipx0; } + if (y < g->clipy0) { cy -= g->clipy0 - y; y = g->clipy0; } + if (!lines || cx <= 0 || cy <= 0 || x >= g->clipx1 || y >= g->clipy1) { MUTEX_EXIT(g); return; } + if (x+cx > g->clipx1) cx = g->clipx1 - x; + if (y+cy > g->clipy1) cy = g->clipy1 - y; #endif abslines = lines < 0 ? -lines : lines; @@ -1726,13 +1773,13 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, cy = 0; } else { #if GDISP_HARDWARE_SCROLL - GC->p.x = x; - GC->p.y = y; - GC->p.cx = cx; - GC->p.cy = cy; - GC->p.y1 = lines; - GC->p.color = bgcolor; - gdisp_lld_vertical_scroll(GC); + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + g->p.y1 = lines; + g->p.color = bgcolor; + gdisp_lld_vertical_scroll(g); cy -= abslines; #elif GDISP_LINEBUF_SIZE == 0 #error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support and GDISP_LINEBUF_SIZE is zero." @@ -1759,20 +1806,20 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, // Read one line of data from the screen #if GDISP_HARDWARE_STREAM_READ // Best is hardware streaming - GC->p.x = x+ix; - GC->p.y = fy+lines; - GC->p.cx = fx; - GC->p.cy = 1; - gdisp_lld_read_start(GC); + g->p.x = x+ix; + g->p.y = fy+lines; + g->p.cx = fx; + g->p.cy = 1; + gdisp_lld_read_start(g); for(j=0; j < fx; j++) - GC->linebuf[j] = gdisp_lld_read_color(GC); - gdisp_lld_read_stop(GC); + g->linebuf[j] = gdisp_lld_read_color(g); + gdisp_lld_read_stop(g); #elif GDISP_HARDWARE_PIXELREAD // Next best is single pixel reads for(j=0; j < fx; j++) { - GC->p.x = x+ix+j; - GC->p.y = fy+lines; - GC->linebuf[j] = gdisp_lld_get_pixel_color(GC); + g->p.x = x+ix+j; + g->p.y = fy+lines; + g->linebuf[j] = gdisp_lld_get_pixel_color(g); } #else // Worst is "not possible" @@ -1782,36 +1829,36 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, // Write that line to the new location #if GDISP_HARDWARE_BITFILLS // Best is hardware bitfills - GC->p.x = x+ix; - GC->p.y = fy; - GC->p.cx = fx; - GC->p.cy = 1; - GC->p.x1 = 0; - GC->p.y1 = 0; - GC->p.x2 = fx; - GC->p.ptr = (void *)GC->linebuf; - gdisp_lld_blit_area(GC); + g->p.x = x+ix; + g->p.y = fy; + g->p.cx = fx; + g->p.cy = 1; + g->p.x1 = 0; + g->p.y1 = 0; + g->p.x2 = fx; + g->p.ptr = (void *)g->linebuf; + gdisp_lld_blit_area(g); #elif GDISP_HARDWARE_STREAM_WRITE // Next best is hardware streaming - GC->p.x = x+ix; - GC->p.y = fy; - GC->p.cx = fx; - GC->p.cy = 1; - gdisp_lld_write_start(GC); + g->p.x = x+ix; + g->p.y = fy; + g->p.cx = fx; + g->p.cy = 1; + gdisp_lld_write_start(g); #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(GC); + gdisp_lld_write_pos(g); #endif for(j = 0; j < fx; j++) { - GC->p.color = GC->linebuf[j]; - gdisp_lld_write_color(GC); + g->p.color = g->linebuf[j]; + gdisp_lld_write_color(g); } - gdisp_lld_write_stop(GC); + gdisp_lld_write_stop(g); #else // Worst is drawing pixels - GC->p.y = fy; - for(GC->p.x = x+ix, j = 0; j < fx; GC->p.x++, j++) { - GC->p.color = GC->linebuf[j]; - gdisp_lld_draw_pixel(GC); + g->p.y = fy; + for(g->p.x = x+ix, j = 0; j < fx; g->p.x++, j++) { + g->p.color = g->linebuf[j]; + gdisp_lld_draw_pixel(g); } #endif } @@ -1820,45 +1867,45 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, } /* fill the remaining gap */ - GC->p.x = x; - GC->p.y = lines > 0 ? (y+cy) : y; - GC->p.cx = cx; - GC->p.cy = abslines; - GC->p.color = bgcolor; - fillarea(); - MUTEX_EXIT(); + g->p.x = x; + g->p.y = lines > 0 ? (y+cy) : y; + g->p.cx = cx; + g->p.cy = abslines; + g->p.color = bgcolor; + fillarea(g); + MUTEX_EXIT(g); } #endif #if GDISP_NEED_CONTROL #if GDISP_HARDWARE_CONTROL - void gdispControl(unsigned what, void *value) { - MUTEX_ENTER(); - GC->p.x = what; - GC->p.ptr = value; - gdisp_lld_control(GC); + void gdispGControl(GDisplay *g, unsigned what, void *value) { + MUTEX_ENTER(g); + g->p.x = what; + g->p.ptr = value; + gdisp_lld_control(g); #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION if (what == GDISP_CONTROL_ORIENTATION) { #if GDISP_HARDWARE_CLIP // Best is hardware clipping - GC->p.x = 0; - GC->p.y = 0; - GC->p.cx = GC->g.Width; - GC->p.cy = GC->g.Height; - gdisp_lld_set_clip(GC); + g->p.x = 0; + g->p.y = 0; + g->p.cx = g->g.Width; + g->p.cy = g->g.Height; + gdisp_lld_set_clip(g); #else // Worst is software clipping - GC->clipx0 = 0; - GC->clipy0 = 0; - GC->clipx1 = GC->g.Width; - GC->clipy1 = GC->g.Height; + g->clipx0 = 0; + g->clipy0 = 0; + g->clipx1 = g->g.Width; + g->clipy1 = g->g.Height; #endif } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #else - void gdispControl(unsigned what, void *value) { + void gdispGControl(GDisplay *g, unsigned what, void *value) { (void)what; (void)value; /* Ignore everything */ @@ -1868,17 +1915,17 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, #if GDISP_NEED_QUERY #if GDISP_HARDWARE_QUERY - void *gdispQuery(unsigned what) { + void *gdispGQuery(GDisplay *g, unsigned what) { void *res; - MUTEX_ENTER(); - GC->p.x = (coord_t)what; - res = gdisp_lld_query(GC); - MUTEX_EXIT(); + MUTEX_ENTER(g); + g->p.x = (coord_t)what; + res = gdisp_lld_query(g); + MUTEX_EXIT(g); return res; } #else - void *gdispQuery(unsigned what) { + void *gdispGQuery(GDisplay *g, unsigned what) { (void) what; return (void *)-1; } @@ -1889,63 +1936,63 @@ void gdispBlitAreaEx(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, /* High Level Driver Routines. */ /*===========================================================================*/ -void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { +void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { if (cx <= 0 || cy <= 0) return; cx = x+cx-1; cy = y+cy-1; // cx, cy are now the end point. - MUTEX_ENTER(); + MUTEX_ENTER(g); - GC->p.color = color; + g->p.color = color; if (cx - x > 2) { - GC->p.x = x; GC->p.y = y; GC->p.x1 = cx; hline_clip(); + g->p.x = x; g->p.y = y; g->p.x1 = cx; hline_clip(g); if (y != cy) { - GC->p.x = x; GC->p.y = cy; GC->p.x1 = cx; hline_clip(); + g->p.x = x; g->p.y = cy; g->p.x1 = cx; hline_clip(g); if (cy - y > 2) { y++; cy--; - GC->p.x = x; GC->p.y = y; GC->p.y1 = cy; vline_clip(); - GC->p.x = cx; GC->p.y = y; GC->p.y1 = cy; vline_clip(); + g->p.x = x; g->p.y = y; g->p.y1 = cy; vline_clip(g); + g->p.x = cx; g->p.y = y; g->p.y1 = cy; vline_clip(g); } } } else { - GC->p.x = x; GC->p.y = y; GC->p.y1 = cy; vline_clip(); + g->p.x = x; g->p.y = y; g->p.y1 = cy; vline_clip(g); if (x != cx) { - GC->p.x = cx; GC->p.y = y; GC->p.y1 = cy; vline_clip(); + g->p.x = cx; g->p.y = y; g->p.y1 = cy; vline_clip(g); } } #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } #if GDISP_NEED_CONVEX_POLYGON - void gdispDrawPoly(coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) { + void gdispGDrawPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) { const point *epnt, *p; epnt = &pntarray[cnt-1]; - MUTEX_ENTER(); - GC->p.color = color; + MUTEX_ENTER(g); + g->p.color = color; for(p = pntarray; p < epnt; p++) { - GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+p[1].x; GC->p.y1=ty+p[1].y; line_clip(); + g->p.x=tx+p->x; g->p.y=ty+p->y; g->p.x1=tx+p[1].x; g->p.y1=ty+p[1].y; line_clip(g); } - GC->p.x=tx+p->x; GC->p.y=ty+p->y; GC->p.x1=tx+pntarray->x; GC->p.y1=ty+pntarray->y; line_clip(); + g->p.x=tx+p->x; g->p.y=ty+p->y; g->p.x1=tx+pntarray->x; g->p.y1=ty+pntarray->y; line_clip(g); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } - void gdispFillConvexPoly(coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) { + void gdispGFillConvexPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color) { const point *lpnt, *rpnt, *epnts; fixed lx, rx, lk, rk; coord_t y, ymax, lxc, rxc; @@ -1975,8 +2022,8 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { lk = (FIXED(lpnt->x) - lx) / (lpnt->y - y); rk = (FIXED(rpnt->x) - rx) / (rpnt->y - y); - MUTEX_ENTER(); - GC->p.color = color; + MUTEX_ENTER(g); + g->p.color = color; while(1) { /* Determine our boundary */ ymax = rpnt->y < lpnt->y ? rpnt->y : lpnt->y; @@ -1991,9 +2038,9 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { * of pixels. */ if (lxc < rxc) { - GC->p.x=tx+lxc; GC->p.y=ty+y; GC->p.x1=tx+rxc-1; hline_clip(); + g->p.x=tx+lxc; g->p.y=ty+y; g->p.x1=tx+rxc-1; hline_clip(g); } else if (lxc > rxc) { - GC->p.x=tx+rxc; GC->p.y=ty+y; GC->p.x1=tx+lxc-1; hline_clip(); + g->p.x=tx+rxc; g->p.y=ty+y; g->p.x1=tx+lxc-1; hline_clip(g); } lx += lk; @@ -2002,12 +2049,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { if (!cnt) { #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); return; } cnt--; @@ -2017,12 +2064,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { for (lpnt = lpnt <= pntarray ? epnts : lpnt-1; lpnt->y == y; cnt--) { if (!cnt) { #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); return; } lx = FIXED(lpnt->x); @@ -2033,12 +2080,12 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) { if (!cnt) { #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); return; } rx = FIXED(rpnt->x); @@ -2055,27 +2102,27 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { #if GDISP_NEED_ANTIALIAS && GDISP_HARDWARE_PIXELREAD static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { - #define GD ((GDISPDriver *)state) + #define GD ((GDisplay *)state) if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x < GD->t.clipx0 || x+count > GD->t.clipx1) return; if (alpha == 255) { GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color; - hline_clip(); + hline_clip(g); } else { for (; count; count--, x++) { GD->p.x = x; GD->p.y = y; GD->p.color = gdispBlendColor(GD->t.color, gdisp_lld_get_pixel_color(GD), alpha); - drawpixel_clip(); + drawpixel_clip(g); } } #undef GD } #else static void drawcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { - #define GD ((GDISPDriver *)state) + #define GD ((GDisplay *)state) if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x < GD->t.clipx0 || x+count > GD->t.clipx1) return; if (alpha > 0x80) { // A best approximation when using anti-aliased fonts but we can't actually draw them anti-aliased GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color; - hline_clip(); + hline_clip(g); } #undef GD } @@ -2083,7 +2130,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { #if GDISP_NEED_ANTIALIAS static void fillcharline(int16_t x, int16_t y, uint8_t count, uint8_t alpha, void *state) { - #define GD ((GDISPDriver *)state) + #define GD ((GDisplay *)state) if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x < GD->t.clipx0 || x+count > GD->t.clipx1) return; if (alpha == 255) { GD->p.color = GD->t.color; @@ -2091,7 +2138,7 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { GD->p.color = gdispBlendColor(GD->t.color, GD->t.bgcolor, alpha); } GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; - hline_clip(); + hline_clip(g); #undef GD } #else @@ -2100,110 +2147,110 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { /* Callback to render characters. */ static uint8_t drawcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { - return mf_render_character(GC->t.font, x, y, ch, drawcharline, state); + return mf_render_character(g->t.font, x, y, ch, drawcharline, state); } /* Callback to render characters. */ static uint8_t fillcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { - return mf_render_character(GC->t.font, x, y, ch, fillcharline, state); + return mf_render_character(g->t.font, x, y, ch, fillcharline, state); } - void gdispDrawChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color) { - MUTEX_ENTER(); - GC->t.font = font; - GC->t.clipx0 = x; - GC->t.clipy0 = y; - GC->t.clipx1 = x + mf_character_width(font, c) + font->baseline_x; - GC->t.clipy1 = y + font->height; - GC->t.color = color; - mf_render_character(font, x, y, c, drawcharline, GC); + void gdispGDrawChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color) { + MUTEX_ENTER(g); + g->t.font = font; + g->t.clipx0 = x; + g->t.clipy0 = y; + g->t.clipx1 = x + mf_character_width(font, c) + font->baseline_x; + g->t.clipy1 = y + font->height; + g->t.color = color; + mf_render_character(font, x, y, c, drawcharline, g); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } - void gdispFillChar(coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) { - MUTEX_ENTER(); - GC->p.cx = mf_character_width(font, c) + font->baseline_x; - GC->p.cy = font->height; - GC->t.font = font; - GC->t.clipx0 = GC->p.x = x; - GC->t.clipy0 = GC->p.y = y; - GC->t.clipx1 = GC->p.x+GC->p.cx; - GC->t.clipy1 = GC->p.y+GC->p.cy; - GC->t.color = color; - GC->t.bgcolor = GC->p.color = bgcolor; + void gdispGFillChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color, color_t bgcolor) { + MUTEX_ENTER(g); + g->p.cx = mf_character_width(font, c) + font->baseline_x; + g->p.cy = font->height; + g->t.font = font; + g->t.clipx0 = g->p.x = x; + g->t.clipy0 = g->p.y = y; + g->t.clipx1 = g->p.x+g->p.cx; + g->t.clipy1 = g->p.y+g->p.cy; + g->t.color = color; + g->t.bgcolor = g->p.color = bgcolor; - TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { - fillarea(); - mf_render_character(font, x, y, c, fillcharline, GC); + TEST_CLIP_AREA(g) { + fillarea(g); + mf_render_character(font, x, y, c, fillcharline, g); } #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } - void gdispDrawString(coord_t x, coord_t y, const char *str, font_t font, color_t color) { - MUTEX_ENTER(); - GC->t.font = font; - GC->t.clipx0 = x; - GC->t.clipy0 = y; - GC->t.clipx1 = x + mf_get_string_width(font, str, 0, 0); - GC->t.clipy1 = y + font->height; - GC->t.color = color; + void gdispGDrawString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color) { + MUTEX_ENTER(g); + g->t.font = font; + g->t.clipx0 = x; + g->t.clipy0 = y; + g->t.clipx1 = x + mf_get_string_width(font, str, 0, 0); + g->t.clipy1 = y + font->height; + g->t.color = color; - mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, GC); + mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, g); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } - void gdispFillString(coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor) { - MUTEX_ENTER(); - GC->p.cx = mf_get_string_width(font, str, 0, 0); - GC->p.cy = font->height; - GC->t.font = font; - GC->t.clipx0 = GC->p.x = x; - GC->t.clipy0 = GC->p.y = y; - GC->t.clipx1 = GC->p.x+GC->p.cx; - GC->t.clipy1 = GC->p.y+GC->p.cy; - GC->t.color = color; - GC->t.bgcolor = GC->p.color = bgcolor; + void gdispGFillString(GDisplay *g, coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor) { + MUTEX_ENTER(g); + g->p.cx = mf_get_string_width(font, str, 0, 0); + g->p.cy = font->height; + g->t.font = font; + g->t.clipx0 = g->p.x = x; + g->t.clipy0 = g->p.y = y; + g->t.clipx1 = g->p.x+g->p.cx; + g->t.clipy1 = g->p.y+g->p.cy; + g->t.color = color; + g->t.bgcolor = g->p.color = bgcolor; - TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { - fillarea(); - mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, GC); + TEST_CLIP_AREA(g) { + fillarea(g); + mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, g); } #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } - void gdispDrawStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) { - MUTEX_ENTER(); - GC->t.font = font; - GC->t.clipx0 = x; - GC->t.clipy0 = y; - GC->t.clipx1 = x+cx; - GC->t.clipy1 = y+cy; - GC->t.color = color; + void gdispGDrawStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) { + MUTEX_ENTER(g); + g->t.font = font; + g->t.clipx0 = x; + g->t.clipy0 = y; + g->t.clipx1 = x+cx; + g->t.clipy1 = y+cy; + g->t.color = color; /* Select the anchor position */ switch(justify) { @@ -2219,33 +2266,33 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { } y += (cy+1 - font->height)/2; - mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, GC); + mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, g); #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } - void gdispFillStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) { - MUTEX_ENTER(); - GC->p.cx = cx; - GC->p.cy = cy; - GC->t.font = font; - GC->t.clipx0 = GC->p.x = x; - GC->t.clipy0 = GC->p.y = y; - GC->t.clipx1 = x+cx; - GC->t.clipy1 = y+cy; - GC->t.color = color; - GC->t.bgcolor = GC->p.color = bgcolor; + void gdispGFillStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) { + MUTEX_ENTER(g); + g->p.cx = cx; + g->p.cy = cy; + g->t.font = font; + g->t.clipx0 = g->p.x = x; + g->t.clipy0 = g->p.y = y; + g->t.clipx1 = x+cx; + g->t.clipy1 = y+cy; + g->t.color = color; + g->t.bgcolor = g->p.color = bgcolor; - TEST_CLIP_AREA(GC->p.x, GC->p.y, GC->p.cx, GC->p.cy) { + TEST_CLIP_AREA(g) { // background fill - fillarea(); + fillarea(g); /* Select the anchor position */ switch(justify) { @@ -2262,16 +2309,16 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { y += (cy+1 - font->height)/2; /* Render */ - mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, GC); + mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, g); } #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((GC->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(GC); - GC->flags &= ~GDISP_FLG_SCRSTREAM; + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; } #endif - MUTEX_EXIT(); + MUTEX_EXIT(g); } coord_t gdispGetFontMetric(font_t font, fontmetric_t metric) { diff --git a/src/gfx.c b/src/gfx.c index 92533937..09d0798b 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -71,7 +71,6 @@ void gfxInit(void) { #endif #if GFX_USE_GDISP _gdispInit(); - gdispClear(Black); #endif #if GFX_USE_GWIN _gwinInit(); From 75ed6842750ac4c43964604905a8459384dfdb65 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 12 Oct 2013 22:38:12 +1000 Subject: [PATCH 043/160] Multiple display update for X11 driver. Untested. --- drivers/multiple/X/gdisp_lld.c | 170 ++++++++++++++++---------- drivers/multiple/X/gdisp_lld_config.h | 8 -- 2 files changed, 103 insertions(+), 75 deletions(-) diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld.c index c60e2085..9478d22a 100644 --- a/drivers/multiple/X/gdisp_lld.c +++ b/drivers/multiple/X/gdisp_lld.c @@ -14,7 +14,7 @@ #if GFX_USE_GDISP -#define GDISP_LLD_DECLARATIONS +#define GDISP_DRIVER_VMT GDISPVMT_X11 #include "gdisp/lld/gdisp_lld.h" /** @@ -35,6 +35,8 @@ #define GDISP_SCREEN_WIDTH 640 #endif +#define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0) + #if GINPUT_NEED_MOUSE /* Include mouse support code */ #include "ginput/lld/mouse.h" @@ -45,24 +47,37 @@ #include #include -Display *dis; -int scr; -Window win; -Pixmap pix; -XEvent evt; -GC gc; -Colormap cmap; -XVisualInfo vis; -int depth; +static bool_t initdone; +static Display *dis; +static int scr; +static XEvent evt; +static Colormap cmap; +static XVisualInfo vis; +static int depth; +static XContext cxt; #if GINPUT_NEED_MOUSE coord_t mousex, mousey; uint16_t mousebuttons; #endif -static void ProcessEvent(void) { +typedef struct xPriv { + Pixmap pix; + GC gc; + Window win; +} xPriv; + +static void ProcessEvent(GDisplay *g, xPriv *priv) { switch(evt.type) { + case MapNotify: + XSelectInput(dis, evt.xmap.window, StructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask); + g->flags |= GDISP_FLG_READY; + break; + case UnmapNotify: + XCloseDisplay(dis); + exit(0); + break; case Expose: - XCopyArea(dis, pix, win, gc, + XCopyArea(dis, pix, evt.xexpose.window, priv->gc, evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height, evt.xexpose.x, evt.xexpose.y); @@ -108,13 +123,15 @@ static void ProcessEvent(void) { /* this is the X11 thread which keeps track of all events */ static DECLARE_THREAD_STACK(waXThread, 1024); static DECLARE_THREAD_FUNCTION(ThreadX, arg) { + GDisplay *g; (void)arg; while(1) { gfxSleepMilliseconds(100); while(XPending(dis)) { XNextEvent(dis, &evt); - ProcessEvent(); + XFindContext(ev.xany.display, ev.xany.window, cxt, (XPointer*)&g); + ProcessEvent(g, (xPriv *)g->priv); } } return 0; @@ -128,50 +145,76 @@ static int FatalXIOError(Display *d) { exit(0); } -LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { XSizeHints *pSH; XSetWindowAttributes xa; XTextProperty WindowTitle; char * WindowTitleText; - gfxThreadHandle hth; + xPriv *priv; - #if GFX_USE_OS_LINUX || GFX_USE_OS_OSX - XInitThreads(); - #endif + if (!initdone) { + gfxThreadHandle hth; - dis = XOpenDisplay(NULL); - scr = DefaultScreen(dis); + initdone = TRUE; + #if GFX_USE_OS_LINUX || GFX_USE_OS_OSX + XInitThreads(); + #endif - #if GDISP_FORCE_24BIT - if (!XMatchVisualInfo(dis, scr, 24, TrueColor, &vis)) { - fprintf(stderr, "Your display has no TrueColor mode\n"); + dis = XOpenDisplay(NULL); + scr = DefaultScreen(dis); + cxt = XUniqueContext(); + XSetIOErrorHandler(FatalXIOError); + + #if GDISP_FORCE_24BIT + if (!XMatchVisualInfo(dis, scr, 24, TrueColor, &vis)) { + fprintf(stderr, "Your display has no TrueColor mode\n"); + XCloseDisplay(dis); + return FALSE; + } + cmap = XCreateColormap(dis, RootWindow(dis, scr), + vis.visual, AllocNone); + #else + vis.visual = CopyFromParent; + vis.depth = DefaultDepth(dis, scr); + cmap = DefaultColormap(dis, scr); + #endif + fprintf(stderr, "Running GFX Window in %d bit color\n", vis.depth); + + if (!(hth = gfxThreadCreate(waXThread, sizeof(waXThread), HIGH_PRIORITY, ThreadX, 0))) { + fprintf(stderr, "Cannot start X Thread\n"); XCloseDisplay(dis); - return FALSE; + exit(0); } - cmap = XCreateColormap(dis, RootWindow(dis, scr), - vis.visual, AllocNone); - #else - vis.visual = CopyFromParent; - vis.depth = DefaultDepth(dis, scr); - cmap = DefaultColormap(dis, scr); - #endif - fprintf(stderr, "Running GFX Window in %d bit color\n", vis.depth); + #if GFX_USE_OS_LINUX || GFX_USE_OS_OSX + pthread_detach(hth); + #endif + gfxThreadClose(hth); + } + + g->priv = gfxAlloc(sizeof(xPriv)); + priv = (xPriv *)g->priv; xa.colormap = cmap; xa.border_pixel = 0xFFFFFF; xa.background_pixel = 0x000000; - win = XCreateWindow(dis, RootWindow(dis, scr), 16, 16, + priv->win = XCreateWindow(dis, RootWindow(dis, scr), 16, 16, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, 0, vis.depth, InputOutput, vis.visual, CWBackPixel|CWColormap|CWBorderPixel, &xa); XSync(dis, TRUE); - WindowTitleText = "GFX"; - XStringListToTextProperty(&WindowTitleText, 1, &WindowTitle); - XSetWMName(dis, win, &WindowTitle); - XSetWMIconName(dis, win, &WindowTitle); - XSync(dis, TRUE); + XSaveContext(dis, win, cxt, (XPointer)g); + + { + char buf[132]; + sprintf(buf, "uGFX - %u", display+1); + WindowTitleText = buf; + XStringListToTextProperty(&WindowTitleText, 1, &WindowTitle); + XSetWMName(dis, win, &WindowTitle); + XSetWMIconName(dis, win, &WindowTitle); + XSync(dis, TRUE); + } pSH = XAllocSizeHints(); pSH->flags = PSize | PMinSize | PMaxSize; @@ -181,34 +224,22 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { XFree(pSH); XSync(dis, TRUE); - pix = XCreatePixmap(dis, win, + priv->pix = XCreatePixmap(dis, win, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, vis.depth); XSync(dis, TRUE); - gc = XCreateGC(dis, win, 0, 0); + priv->gc = XCreateGC(dis, win, 0, 0); XSetBackground(dis, gc, BlackPixel(dis, scr)); XSync(dis, TRUE); XSelectInput(dis, win, StructureNotifyMask); XMapWindow(dis, win); - do { XNextEvent(dis, &evt); } while (evt.type != MapNotify); - /* start the X11 thread */ - XSetIOErrorHandler(FatalXIOError); - XSelectInput(dis, win, - ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask); + // Wait for the window creation to complete (for safety) + while(!(((volatile GDisplay *)g)->flags & GDISP_FLG_READY)) + gfxSleepMilliseconds(100); - if (!(hth = gfxThreadCreate(waXThread, sizeof(waXThread), HIGH_PRIORITY, ThreadX, 0))) { - fprintf(stderr, "Cannot start X Thread\n"); - XCloseDisplay(dis); - exit(0); - } - #if GFX_USE_OS_LINUX || GFX_USE_OS_OSX - pthread_detach(hth); - #endif - gfxThreadClose(hth); - - /* Initialise the GDISP structure to match */ + /* Initialise the GDISP structure to match */ g->g.Orientation = GDISP_ROTATE_0; g->g.Powermode = powerOn; g->g.Backlight = 100; @@ -220,29 +251,31 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) { + xPriv priv = (xPriv *)g->priv; XColor col; col.red = RED_OF(g->p.color) << 8; col.green = GREEN_OF(g->p.color) << 8; col.blue = BLUE_OF(g->p.color) << 8; XAllocColor(dis, cmap, &col); - XSetForeground(dis, gc, col.pixel); - XDrawPoint(dis, pix, gc, (int)g->p.x, (int)g->p.y ); - XDrawPoint(dis, win, gc, (int)g->p.x, (int)g->p.y ); + XSetForeground(dis, priv->gc, col.pixel); + XDrawPoint(dis, priv->pix, priv->gc, (int)g->p.x, (int)g->p.y ); + XDrawPoint(dis, priv->win, priv->gc, (int)g->p.x, (int)g->p.y ); XFlush(dis); } #if GDISP_HARDWARE_FILLS LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { + xPriv priv = (xPriv *)g->priv; XColor col; col.red = RED_OF(g->p.color) << 8; col.green = GREEN_OF(g->p.color) << 8; col.blue = BLUE_OF(g->p.color) << 8; XAllocColor(dis, cmap, &col); - XSetForeground(dis, gc, col.pixel); - XFillRectangle(dis, pix, gc, g->p.x, g->p.y, g->p.cx, g->p.cy); - XFillRectangle(dis, win, gc, g->p.x, g->p.y, g->p.cx, g->p.cy); + XSetForeground(dis, priv->gc, col.pixel); + XFillRectangle(dis, priv->pix, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy); + XFillRectangle(dis, priv->win, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy); XFlush(dis); } #endif @@ -262,10 +295,11 @@ LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) #if GDISP_HARDWARE_PIXELREAD LLDSPEC color_t gdisp_lld_get_pixel_color(GDISPDriver *g) { + xPriv priv = (xPriv *)g->priv; XColor color; XImage *img; - img = XGetImage (dis, pix, g->p.x, g->p.y, 1, 1, AllPlanes, XYPixmap); + img = XGetImage (dis, priv->pix, g->p.x, g->p.y, 1, 1, AllPlanes, XYPixmap); color.pixel = XGetPixel (img, 0, 0); XFree(img); XQueryColor(dis, cmap, &color); @@ -275,12 +309,14 @@ LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) #if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL LLDSPEC void gdisp_lld_vertical_scroll(GDISPDriver *g) { + xPriv priv = (xPriv *)g->priv; + if (g->p.y1 > 0) { - XCopyArea(dis, pix, pix, gc, g->p.x, g->p.y+g->p.y1, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); - XCopyArea(dis, pix, win, gc, g->p.x, g->p.y, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); + XCopyArea(dis, priv->pix, priv->pix, priv->gc, g->p.x, g->p.y+g->p.y1, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); + XCopyArea(dis, priv->pix, priv->win, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); } else { - XCopyArea(dis, pix, pix, gc, g->p.x, g->p.y, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); - XCopyArea(dis, pix, win, gc, g->p.x, g->p.y-g->p.y1, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); + XCopyArea(dis, priv->pix, priv->pix, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); + XCopyArea(dis, priv->pix, priv->win, priv->gc, g->p.x, g->p.y-g->p.y1, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1); } } #endif diff --git a/drivers/multiple/X/gdisp_lld_config.h b/drivers/multiple/X/gdisp_lld_config.h index 7c04b1b9..b58a3d54 100644 --- a/drivers/multiple/X/gdisp_lld_config.h +++ b/drivers/multiple/X/gdisp_lld_config.h @@ -22,14 +22,6 @@ /* Driver hardware support. */ /*===========================================================================*/ -#ifndef GDISP_DRIVER_COUNT_X11 - #define GDISP_DRIVER_COUNT_X11 1 -#endif -#define GDISP_DRIVER_COUNT GDISP_DRIVER_COUNT_X11 - -#define GDISP_DRIVER_NAME "Linux emulator - X11" -#define GDISP_DRIVER_STRUCT GDISP_X11 - #define GDISP_HARDWARE_DRAWPIXEL TRUE #define GDISP_HARDWARE_FILLS TRUE #define GDISP_HARDWARE_BITFILLS FALSE From 769766aa4ad4d35a8aa94ff5cf2df2b88549d426 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 12 Oct 2013 23:36:27 +1000 Subject: [PATCH 044/160] X11 multiple display now tested --- drivers/multiple/X/gdisp_lld.c | 41 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld.c index 9478d22a..c87308f2 100644 --- a/drivers/multiple/X/gdisp_lld.c +++ b/drivers/multiple/X/gdisp_lld.c @@ -53,7 +53,6 @@ static int scr; static XEvent evt; static Colormap cmap; static XVisualInfo vis; -static int depth; static XContext cxt; #if GINPUT_NEED_MOUSE coord_t mousex, mousey; @@ -77,7 +76,7 @@ static void ProcessEvent(GDisplay *g, xPriv *priv) { exit(0); break; case Expose: - XCopyArea(dis, pix, evt.xexpose.window, priv->gc, + XCopyArea(dis, priv->pix, evt.xexpose.window, priv->gc, evt.xexpose.x, evt.xexpose.y, evt.xexpose.width, evt.xexpose.height, evt.xexpose.x, evt.xexpose.y); @@ -130,7 +129,7 @@ static DECLARE_THREAD_FUNCTION(ThreadX, arg) { gfxSleepMilliseconds(100); while(XPending(dis)) { XNextEvent(dis, &evt); - XFindContext(ev.xany.display, ev.xany.window, cxt, (XPointer*)&g); + XFindContext(evt.xany.display, evt.xany.window, cxt, (XPointer*)&g); ProcessEvent(g, (xPriv *)g->priv); } } @@ -204,15 +203,15 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { CWBackPixel|CWColormap|CWBorderPixel, &xa); XSync(dis, TRUE); - XSaveContext(dis, win, cxt, (XPointer)g); + XSaveContext(dis, priv->win, cxt, (XPointer)g); { char buf[132]; sprintf(buf, "uGFX - %u", display+1); WindowTitleText = buf; XStringListToTextProperty(&WindowTitleText, 1, &WindowTitle); - XSetWMName(dis, win, &WindowTitle); - XSetWMIconName(dis, win, &WindowTitle); + XSetWMName(dis, priv->win, &WindowTitle); + XSetWMIconName(dis, priv->win, &WindowTitle); XSync(dis, TRUE); } @@ -220,20 +219,20 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { pSH->flags = PSize | PMinSize | PMaxSize; pSH->min_width = pSH->max_width = pSH->base_width = GDISP_SCREEN_WIDTH; pSH->min_height = pSH->max_height = pSH->base_height = GDISP_SCREEN_HEIGHT; - XSetWMNormalHints(dis, win, pSH); + XSetWMNormalHints(dis, priv->win, pSH); XFree(pSH); XSync(dis, TRUE); - priv->pix = XCreatePixmap(dis, win, + priv->pix = XCreatePixmap(dis, priv->win, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, vis.depth); XSync(dis, TRUE); - priv->gc = XCreateGC(dis, win, 0, 0); - XSetBackground(dis, gc, BlackPixel(dis, scr)); + priv->gc = XCreateGC(dis, priv->win, 0, 0); + XSetBackground(dis, priv->gc, BlackPixel(dis, scr)); XSync(dis, TRUE); - XSelectInput(dis, win, StructureNotifyMask); - XMapWindow(dis, win); + XSelectInput(dis, priv->win, StructureNotifyMask); + XMapWindow(dis, priv->win); // Wait for the window creation to complete (for safety) while(!(((volatile GDisplay *)g)->flags & GDISP_FLG_READY)) @@ -249,9 +248,9 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { return TRUE; } -LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) +LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { - xPriv priv = (xPriv *)g->priv; + xPriv * priv = (xPriv *)g->priv; XColor col; col.red = RED_OF(g->p.color) << 8; @@ -265,8 +264,8 @@ LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) } #if GDISP_HARDWARE_FILLS - LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { - xPriv priv = (xPriv *)g->priv; + LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { + xPriv * priv = (xPriv *)g->priv; XColor col; col.red = RED_OF(g->p.color) << 8; @@ -281,7 +280,7 @@ LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) #endif #if 0 && GDISP_HARDWARE_BITFILLS - LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g) { + LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { // Start of Bitblit code //XImage bitmap; @@ -294,8 +293,8 @@ LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) #endif #if GDISP_HARDWARE_PIXELREAD - LLDSPEC color_t gdisp_lld_get_pixel_color(GDISPDriver *g) { - xPriv priv = (xPriv *)g->priv; + LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { + xPriv * priv = (xPriv *)g->priv; XColor color; XImage *img; @@ -308,8 +307,8 @@ LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) #endif #if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL - LLDSPEC void gdisp_lld_vertical_scroll(GDISPDriver *g) { - xPriv priv = (xPriv *)g->priv; + LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g) { + xPriv * priv = (xPriv *)g->priv; if (g->p.y1 > 0) { XCopyArea(dis, priv->pix, priv->pix, priv->gc, g->p.x, g->p.y+g->p.y1, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y); From ea4af865f11cd18ac1b3d33fb9951f7527a42ab7 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 14 Oct 2013 08:55:15 +1000 Subject: [PATCH 045/160] Compile time fix to text rendering. Updated gdisp Get/Set Display routines to a more logical API. --- include/gdisp/gdisp.h | 24 ++++++++++++++++++++---- src/gdisp/gdisp.c | 27 ++++++++++++++++++--------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index 7f0f8012..0c8310bb 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -366,16 +366,32 @@ extern "C" { color_t gdispBlendColor(color_t fg, color_t bg, uint8_t alpha); /** - * @brief Set the current default display to the specified display - * @note The default display is used for the gdispXxxx functions. + * @brief Get the specified display + * @return The pointer to the display or NULL if the display doesn't exist + * @note The GDISP variable contains the display used by the gdispXxxx routines + * as opposed to the gdispGXxxx routines which take an explicit display + * parameter. * @note Displays are numbered from 0 to GDISP_TOTAL_DISPLAYS - 1 - * @note If an invalid display number is specified the request is ignored. * * @param[in] display The display number (0..n) * * @api */ -void gdispSetDisplay(unsigned display); +GDisplay *gdispGetDisplay(unsigned display); + +/** + * @brief Set the current default display to the specified display + * @note The default display is used for the gdispXxxx functions. + * @note The default display is contained in the variable GDISP. Using + * this function to set it protects against it being set to a NULL + * value. + * @note If a NULL is passed for the dispay this call is ignored. + * + * @param[in] display The display number (0..n) + * + * @api + */ +void gdispSetDisplay(GDisplay *g); /* Drawing Functions */ diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 41f2f0f9..ca0411e3 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -448,9 +448,14 @@ void _gdispInit(void) { #endif } -void gdispSetDisplay(unsigned display) { - if (display < GDISP_TOTAL_DISPLAYS) - GDISP = &GDisplayArray[display]; +GDisplay *gdispGetDisplay(unsigned display) { + if (display >= GDISP_TOTAL_DISPLAYS) + return 0; + return &GDisplayArray[display]; +} + +void gdispSetDisplay(GDisplay *g) { + if (g) GDISP = g; } #if GDISP_NEED_STREAMING @@ -2106,12 +2111,12 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x < GD->t.clipx0 || x+count > GD->t.clipx1) return; if (alpha == 255) { GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color; - hline_clip(g); + hline_clip(GD); } else { for (; count; count--, x++) { GD->p.x = x; GD->p.y = y; GD->p.color = gdispBlendColor(GD->t.color, gdisp_lld_get_pixel_color(GD), alpha); - drawpixel_clip(g); + drawpixel_clip(GD); } } #undef GD @@ -2122,7 +2127,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co if (y < GD->t.clipy0 || y >= GD->t.clipy1 || x < GD->t.clipx0 || x+count > GD->t.clipx1) return; if (alpha > 0x80) { // A best approximation when using anti-aliased fonts but we can't actually draw them anti-aliased GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; GD->p.color = GD->t.color; - hline_clip(g); + hline_clip(GD); } #undef GD } @@ -2138,7 +2143,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co GD->p.color = gdispBlendColor(GD->t.color, GD->t.bgcolor, alpha); } GD->p.x = x; GD->p.y = y; GD->p.x1 = x+count-1; - hline_clip(g); + hline_clip(GD); #undef GD } #else @@ -2147,12 +2152,16 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co /* Callback to render characters. */ static uint8_t drawcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { - return mf_render_character(g->t.font, x, y, ch, drawcharline, state); + #define GD ((GDisplay *)state) + return mf_render_character(GD->t.font, x, y, ch, drawcharline, state); + #undef GD } /* Callback to render characters. */ static uint8_t fillcharglyph(int16_t x, int16_t y, mf_char ch, void *state) { - return mf_render_character(g->t.font, x, y, ch, fillcharline, state); + #define GD ((GDisplay *)state) + return mf_render_character(GD->t.font, x, y, ch, fillcharline, state); + #undef GD } void gdispGDrawChar(GDisplay *g, coord_t x, coord_t y, uint16_t c, font_t font, color_t color) { From 3b8c57255247a8774fa03ce259b9f8640488a1f9 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 14 Oct 2013 08:55:44 +1000 Subject: [PATCH 046/160] New demo for multiple display support. --- .../gdisp/gdisp_multiple_displays/gfxconf.h | 75 +++++++++++ .../gdisp/gdisp_multiple_displays/main.c | 122 ++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h create mode 100644 demos/modules/gdisp/gdisp_multiple_displays/main.c diff --git a/demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h b/demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h new file mode 100644 index 00000000..04ff1970 --- /dev/null +++ b/demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + +/* The operating system to use - one of these must be defined */ +//#define GFX_USE_OS_CHIBIOS TRUE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_POSIX FALSE + +/* GFX sub-systems to turn on */ +#define GFX_USE_GDISP TRUE + +/* Features for the GDISP sub-system. */ +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_TEXT TRUE +#define GDISP_NEED_CIRCLE FALSE +#define GDISP_NEED_ELLIPSE FALSE +#define GDISP_NEED_ARC FALSE +#define GDISP_NEED_SCROLL FALSE +#define GDISP_NEED_PIXELREAD FALSE +#define GDISP_NEED_CONTROL FALSE +#define GDISP_NEED_MULTITHREAD FALSE +#define GDISP_NEED_ASYNC FALSE +#define GDISP_NEED_MSGAPI FALSE + +#define GDISP_INCLUDE_FONT_UI2 TRUE + +#define GDISP_TOTAL_DISPLAYS 2 + +/* Uncomment the following lines and alter the definitions to match your + * hardware if you want to try multiple displays on different controllers. + * Remember that GDISP_TOTAL_DISPLAYS above must match the **Total** + * number of displays in your system across all controllers. + */ +//#define GDISP_TOTAL_CONTROLLERS 2 +//#define GDISP_CONTROLLER_LIST GDISPVMT_Win32, GDISPVMT_Win32 +//#define GDISP_CONTROLLER_DISPLAYS 1, 1 +//#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 +//#define GDISP_HARDWARE_DRAWPIXEL TRUE +//#define GDISP_HARDWARE_FILLS TRUE +//#define GDISP_HARDWARE_PIXELREAD TRUE +//#define GDISP_HARDWARE_CONTROL TRUE +//#define GDISP_HARDWARE_BITFILLS TRUE +//#define GDISP_HARDWARE_SCROLL TRUE + +#endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/gdisp_multiple_displays/main.c b/demos/modules/gdisp/gdisp_multiple_displays/main.c new file mode 100644 index 00000000..443bee27 --- /dev/null +++ b/demos/modules/gdisp/gdisp_multiple_displays/main.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gfx.h" + +#include + +/* + * This demo demonstrates two ways to talk to multiple displays. + * + * Method 1 is the preferred way however Method 1 would be useful + * when quickly converting existing single display applications. + * + * Note you can combine the methods using method 2 for the first display + * and method 1 for any extra displays. + */ + +#define USE_METHOD_1 FALSE + +#if USE_METHOD_1 + int main(void) { + coord_t width, height; + coord_t display, i, j; + font_t f; + GDisplay *g; + char buf[16]; + + /* Initialize and clear the display */ + gfxInit(); + + /* Get a font to write with */ + f = gdispOpenFont("*"); + + /* Cycle through each display */ + for(display = 0; display < GDISP_TOTAL_DISPLAYS; display++) { + + // Get the specified display + g = gdispGetDisplay(display); + + // Get the screen size + width = gdispGGetWidth(g); + height = gdispGGetHeight(g); + + /* Draw draw draw */ + gdispGDrawBox(g, 10, 10, width/2, height/2, Yellow); + sprintf(buf, "Display %u", display); + gdispGFillStringBox(g, width/2, height/2, width/2-10, height/2-10, buf, f, White, Blue, justifyCenter); + gdispGDrawLine(g, 5, 30, width-50, height-40, Red); + + for(i = 5, j = 0; i < width && j < height; i += 7, j += i/20) + gdispGDrawPixel(g, i, j, White); + } + + while(TRUE) { + gfxSleepMilliseconds(500); + } + } +#else + int main(void) { + coord_t width, height; + coord_t display, i, j; + font_t f; + char buf[16]; + + /* Initialize and clear the display */ + gfxInit(); + + /* Get a font to write with */ + f = gdispOpenFont("*"); + + /* Cycle through each display */ + for(display = 0; display < GDISP_TOTAL_DISPLAYS; display++) { + + // Set the default display to the specified display + gdispSetDisplay(gdispGetDisplay(display)); + + // Get the screen size + width = gdispGetWidth(); + height = gdispGetHeight(); + + /* Draw draw draw */ + gdispDrawBox(10, 10, width/2, height/2, Yellow); + sprintf(buf, "Display %u", display); + gdispFillStringBox(width/2, height/2, width/2-10, height/2-10, buf, f, White, Blue, justifyCenter); + gdispDrawLine(5, 30, width-50, height-40, Red); + + for(i = 5, j = 0; i < width && j < height; i += 7, j += i/20) + gdispDrawPixel(i, j, White); + } + + while(TRUE) { + gfxSleepMilliseconds(500); + } + } +#endif + From 86a57349128197f58cf3f103e9adf9c2c348d418 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 16 Oct 2013 01:39:56 +1000 Subject: [PATCH 047/160] Multiple controller support can now auto-detect hardware capabilities at run-time. Specific hardware support can still be turned off or on via macros in gfxconf.h to improve efficiency. Multiple Display demo updated to match. --- .../gdisp/gdisp_multiple_displays/gfxconf.h | 39 +- drivers/multiple/Win32/gdisp_lld.c | 1 + drivers/multiple/X/gdisp_lld.c | 1 + include/gdisp/lld/gdisp_lld.h | 88 +- src/gdisp/gdisp.c | 1412 +++++++++++------ 5 files changed, 988 insertions(+), 553 deletions(-) diff --git a/demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h b/demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h index 04ff1970..71c16864 100644 --- a/demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h +++ b/demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h @@ -52,24 +52,37 @@ #define GDISP_NEED_ASYNC FALSE #define GDISP_NEED_MSGAPI FALSE -#define GDISP_INCLUDE_FONT_UI2 TRUE +#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_TOTAL_DISPLAYS 2 +#define GDISP_TOTAL_DISPLAYS 2 -/* Uncomment the following lines and alter the definitions to match your - * hardware if you want to try multiple displays on different controllers. +/* Uncomment the following lines if you want to use multiple displays on + * different controllers. + * + * Change the definitions to suit your hardware. + * Currently all controllers must use the same pixel format. + * * Remember that GDISP_TOTAL_DISPLAYS above must match the **Total** * number of displays in your system across all controllers. + * + * Optionally, you can also specify hardware characteristics that are common to + * all your controllers. This significantly improves code and speed efficiency + * as the program doesn't have to detect the hardware method to use on each call. + * + * Hardware definitions can be set to: + * - TRUE - all controllers support this routine + * - FALSE - no controllers support this routine + * - if not specified then the code auto-detects the hardware. + * + * e.g + * #define GDISP_HARDWARE_STREAM_WRITE FALSE + * #define GDISP_HARDWARE_STREAM_READ FALSE + * #define GDISP_HARDWARE_DRAWPIXEL TRUE + * #define GDISP_HARDWARE_FILLS TRUE */ //#define GDISP_TOTAL_CONTROLLERS 2 -//#define GDISP_CONTROLLER_LIST GDISPVMT_Win32, GDISPVMT_Win32 -//#define GDISP_CONTROLLER_DISPLAYS 1, 1 -//#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 -//#define GDISP_HARDWARE_DRAWPIXEL TRUE -//#define GDISP_HARDWARE_FILLS TRUE -//#define GDISP_HARDWARE_PIXELREAD TRUE -//#define GDISP_HARDWARE_CONTROL TRUE -//#define GDISP_HARDWARE_BITFILLS TRUE -//#define GDISP_HARDWARE_SCROLL TRUE +//#define GDISP_CONTROLLER_LIST GDISPVMT_Win32, GDISPVMT_Win32 +//#define GDISP_CONTROLLER_DISPLAYS 1, 1 +//#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 #endif /* _GFXCONF_H */ diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 65627e1c..dae92821 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -14,6 +14,7 @@ #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_Win32 +#include "../drivers/multiple/Win32/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" #include diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld.c index c87308f2..fc573c87 100644 --- a/drivers/multiple/X/gdisp_lld.c +++ b/drivers/multiple/X/gdisp_lld.c @@ -15,6 +15,7 @@ #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_X11 +#include "../drivers/multiple/X/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" /** diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 2a6f90b7..b1e89f09 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -22,107 +22,140 @@ /* Error checks. */ /*===========================================================================*/ +#if GDISP_TOTAL_CONTROLLERS > 1 && !defined(GDISP_DRIVER_VMT) + #define HARDWARE_AUTODETECT 2 + #define HARDWARE_DEFAULT HARDWARE_AUTODETECT +#else + #define HARDWARE_AUTODETECT 2 + #define HARDWARE_DEFAULT FALSE +#endif + /** * @name GDISP hardware accelerated support * @{ */ /** * @brief Hardware streaming writing is supported. - * @details If set to @p FALSE software emulation is used. - * @note Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 + * @note Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by each driver */ #ifndef GDISP_HARDWARE_STREAM_WRITE - #define GDISP_HARDWARE_STREAM_WRITE FALSE + #define GDISP_HARDWARE_STREAM_WRITE HARDWARE_DEFAULT #endif /** * @brief Hardware streaming reading of the display surface is supported. - * @details If set to @p FALSE this routine is not available. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 + * */ #ifndef GDISP_HARDWARE_STREAM_READ - #define GDISP_HARDWARE_STREAM_READ FALSE + #define GDISP_HARDWARE_STREAM_READ HARDWARE_DEFAULT #endif /** * @brief Hardware supports setting the cursor position within the stream window. - * @details If set to @p FALSE this routine is not available. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 * @note This is used to optimise setting of individual pixels within a stream window. * It should therefore not be implemented unless it is cheaper than just setting * a new window. */ #ifndef GDISP_HARDWARE_STREAM_POS - #define GDISP_HARDWARE_STREAM_POS FALSE + #define GDISP_HARDWARE_STREAM_POS HARDWARE_DEFAULT #endif /** * @brief Hardware accelerated draw pixel. - * @details If set to @p FALSE software emulation is used. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 * @note Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver */ #ifndef GDISP_HARDWARE_DRAWPIXEL - #define GDISP_HARDWARE_DRAWPIXEL FALSE + #define GDISP_HARDWARE_DRAWPIXEL HARDWARE_DEFAULT #endif /** * @brief Hardware accelerated screen clears. - * @details If set to @p FALSE software emulation is used. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 * @note This clears the entire display surface regardless of the clipping area currently set */ #ifndef GDISP_HARDWARE_CLEARS - #define GDISP_HARDWARE_CLEARS FALSE + #define GDISP_HARDWARE_CLEARS HARDWARE_DEFAULT #endif /** * @brief Hardware accelerated rectangular fills. - * @details If set to @p FALSE software emulation is used. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 */ #ifndef GDISP_HARDWARE_FILLS - #define GDISP_HARDWARE_FILLS FALSE + #define GDISP_HARDWARE_FILLS HARDWARE_DEFAULT #endif /** * @brief Hardware accelerated fills from an image. - * @details If set to @p FALSE software emulation is used. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 */ #ifndef GDISP_HARDWARE_BITFILLS - #define GDISP_HARDWARE_BITFILLS FALSE + #define GDISP_HARDWARE_BITFILLS HARDWARE_DEFAULT #endif /** * @brief Hardware accelerated scrolling. - * @details If set to @p FALSE there is no support for scrolling. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 */ #ifndef GDISP_HARDWARE_SCROLL - #define GDISP_HARDWARE_SCROLL FALSE + #define GDISP_HARDWARE_SCROLL HARDWARE_DEFAULT #endif /** * @brief Reading back of pixel values. - * @details If set to @p FALSE there is no support for pixel read-back. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 */ #ifndef GDISP_HARDWARE_PIXELREAD - #define GDISP_HARDWARE_PIXELREAD FALSE + #define GDISP_HARDWARE_PIXELREAD HARDWARE_DEFAULT #endif /** * @brief The driver supports one or more control commands. - * @details If set to @p FALSE there is no support for control commands. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 */ #ifndef GDISP_HARDWARE_CONTROL - #define GDISP_HARDWARE_CONTROL FALSE + #define GDISP_HARDWARE_CONTROL HARDWARE_DEFAULT #endif /** * @brief The driver supports a non-standard query. - * @details If set to @p FALSE there is no support for non-standard queries. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 */ #ifndef GDISP_HARDWARE_QUERY - #define GDISP_HARDWARE_QUERY FALSE + #define GDISP_HARDWARE_QUERY HARDWARE_DEFAULT #endif /** * @brief The driver supports a clipping in hardware. - * @details If set to @p FALSE there is no support for non-standard queries. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 * @note If this is defined the driver must perform its own clipping on all calls to * the driver and respond appropriately if a parameter is outside the display area. * @note If this is not defined then the software ensures that all calls to the @@ -130,7 +163,7 @@ * has been set). */ #ifndef GDISP_HARDWARE_CLIP - #define GDISP_HARDWARE_CLIP FALSE + #define GDISP_HARDWARE_CLIP HARDWARE_DEFAULT #endif /** @} */ @@ -159,7 +192,7 @@ typedef struct GDisplay { #endif // Software clipping - #if !GDISP_HARDWARE_CLIP && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) + #if GDISP_HARDWARE_CLIP != TRUE && (GDISP_NEED_CLIP || GDISP_NEED_VALIDATION) coord_t clipx0, clipy0; coord_t clipx1, clipy1; /* not inclusive */ #endif @@ -464,6 +497,9 @@ typedef struct GDisplay { } GDISPVMT; #if defined(GDISP_DRIVER_VMT) + #if !GDISP_HARDWARE_STREAM_WRITE && !GDISP_HARDWARE_DRAWPIXEL + #error "GDISP Driver: Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be TRUE" + #endif const GDISPVMT const GDISP_DRIVER_VMT[1] = {{ gdisp_lld_init, #if GDISP_HARDWARE_STREAM_WRITE diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index ca0411e3..ef388df5 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -19,10 +19,6 @@ /* Include the low level driver information */ #include "gdisp/lld/gdisp_lld.h" -#if !GDISP_HARDWARE_STREAM_WRITE && !GDISP_HARDWARE_DRAWPIXEL - #error "GDISP Driver: Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be defined" -#endif - #if 1 #undef INLINE #define INLINE inline @@ -34,6 +30,9 @@ // Number of milliseconds for the startup logo - 0 means disabled. #define GDISP_STARTUP_LOGO_TIMEOUT 1000 +// The color to clear the display on startup +#define GDISP_STARTUP_COLOR Black + /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ @@ -58,8 +57,27 @@ GDisplay *GDISP = GDisplayArray; #define MUTEX_EXIT(g) #endif -#define NEED_CLIPPING (!GDISP_HARDWARE_CLIP && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP)) +#define NEED_CLIPPING (GDISP_HARDWARE_CLIP != TRUE && (GDISP_NEED_VALIDATION || GDISP_NEED_CLIP)) +#if !NEED_CLIPPING + #define TEST_CLIP_AREA(g) +#elif GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + #define TEST_CLIP_AREA(g) \ + if (!g->vmt->setclip) { \ + if ((g)->p.x < (g)->clipx0) { (g)->p.cx -= (g)->clipx0 - (g)->p.x; (g)->p.x = (g)->clipx0; } \ + if ((g)->p.y < (g)->clipy0) { (g)->p.cy -= (g)->clipy0 - (g)->p.y; (g)->p.y = (g)->clipy0; } \ + if ((g)->p.x + (g)->p.cx > (g)->clipx1) (g)->p.cx = (g)->clipx1 - (g)->p.x; \ + if ((g)->p.y + (g)->p.cy > (g)->clipy1) (g)->p.cy = (g)->clipy1 - (g)->p.y; \ + } \ + if ((g)->p.cx > 0 && (g)->p.cy > 0) +#else + #define TEST_CLIP_AREA(g) \ + if ((g)->p.x < (g)->clipx0) { (g)->p.cx -= (g)->clipx0 - (g)->p.x; (g)->p.x = (g)->clipx0; } \ + if ((g)->p.y < (g)->clipy0) { (g)->p.cy -= (g)->clipy0 - (g)->p.y; (g)->p.y = (g)->clipy0; } \ + if ((g)->p.x + (g)->p.cx > (g)->clipx1) (g)->p.cx = (g)->clipx1 - (g)->p.x; \ + if ((g)->p.y + (g)->p.cy > (g)->clipy1) (g)->p.cy = (g)->clipy1 - (g)->p.y; \ + if ((g)->p.cx > 0 && (g)->p.cy > 0) +#endif /*==========================================================================*/ /* Internal functions. */ @@ -76,103 +94,140 @@ GDisplay *GDISP = GDisplayArray; } #endif +// drawpixel(g) +// Parameters: x,y +// Alters: cx, cy (if using streaming) +// Does not clip +static INLINE void drawpixel(GDisplay *g) { + + // Best is hardware accelerated pixel draw + #if GDISP_HARDWARE_DRAWPIXEL + #if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT + if (g->vmt->pixel) + #endif + { + gdisp_lld_draw_pixel(g); + return; + } + #endif + + // Next best is cursor based streaming + #if GDISP_HARDWARE_DRAWPIXEL != TRUE && GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + #if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT + if (g->vmt->writepos) + #endif + { + if (!(g->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(g); + gdisp_lld_write_pos(g); + gdisp_lld_write_color(g); + return; + } + #endif + + // Worst is general streaming + #if GDISP_HARDWARE_DRAWPIXEL != TRUE && GDISP_HARDWARE_STREAM_POS != TRUE && GDISP_HARDWARE_STREAM_WRITE + // The following test is unneeded because we are guaranteed to have streaming if we don't have drawpixel + //#if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + // if (g->vmt->writestart) + //#endif + { + g->p.cx = g->p.cy = 1; + gdisp_lld_write_start(g); + gdisp_lld_write_color(g); + gdisp_lld_write_stop(g); + return; + } + #endif +} + // drawpixel_clip(g) // Parameters: x,y // Alters: cx, cy (if using streaming) -#if GDISP_HARDWARE_DRAWPIXEL - // Best is hardware accelerated pixel draw - #if NEED_CLIPPING - static INLINE void drawpixel_clip(GDisplay *g) { - if (g->p.x >= g->clipx0 && g->p.x < g->clipx1 && g->p.y >= g->clipy0 && g->p.y < g->clipy1) - gdisp_lld_draw_pixel(g); - } - #else - #define drawpixel_clip(g) gdisp_lld_draw_pixel(g) - #endif -#elif GDISP_HARDWARE_STREAM_POS - // Next best is cursor based streaming +#if NEED_CLIPPING static INLINE void drawpixel_clip(GDisplay *g) { - #if NEED_CLIPPING + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + if (!g->vmt->setclip) + #endif + { if (g->p.x < g->clipx0 || g->p.x >= g->clipx1 || g->p.y < g->clipy0 || g->p.y >= g->clipy1) return; - #endif - if (!(g->flags & GDISP_FLG_SCRSTREAM)) - setglobalwindow(g); - gdisp_lld_write_pos(g); - gdisp_lld_write_color(g); + } + drawpixel(g); } #else - // Worst is streaming - static INLINE void drawpixel_clip(GDisplay *g) { - #if NEED_CLIPPING - if (g->p.x < g->clipx0 || g->p.x >= g->clipx1 || g->p.y < g->clipy0 || g->p.y >= g->clipy1) - return; - #endif - - g->p.cx = g->p.cy = 1; - gdisp_lld_write_start(g); - gdisp_lld_write_color(g); - gdisp_lld_write_stop(g); - } + #define drawpixel_clip(g) drawpixel(g) #endif // fillarea(g) // Parameters: x,y cx,cy and color // Alters: nothing // Note: This is not clipped -// Resets the streaming area -// if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set. -#if GDISP_HARDWARE_FILLS +// Resets the streaming area if GDISP_HARDWARE_STREAM_WRITE and GDISP_HARDWARE_STREAM_POS is set. +static INLINE void fillarea(GDisplay *g) { + // Best is hardware accelerated area fill - #define fillarea(g) gdisp_lld_fill_area(g) -#elif GDISP_HARDWARE_STREAM_WRITE + #if GDISP_HARDWARE_FILLS + #if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT + if (g->vmt->fill) + #endif + { + gdisp_lld_fill_area(g); + return; + } + #endif + // Next best is hardware streaming - static INLINE void fillarea(GDisplay *g) { - uint32_t area; - - area = (uint32_t)g->p.cx * g->p.cy; - - #if GDISP_HARDWARE_STREAM_POS - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } + #if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + if (g->vmt->writestart) #endif + { + uint32_t area; - gdisp_lld_write_start(g); - #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(g); - #endif - for(; area; area--) - gdisp_lld_write_color(g); - gdisp_lld_write_stop(g); - } -#else - // Worst is drawing pixels - static INLINE void fillarea(GDisplay *g) { - coord_t x0, y0, x1, y1; + #if GDISP_HARDWARE_STREAM_POS + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif - x0 = g->p.x; - y0 = g->p.y; - x1 = g->p.x + g->p.cx; - y1 = g->p.y + g->p.cy; - for(; g->p.y < y1; g->p.y++, g->p.x = x0) - for(; g->p.x < x1; g->p.x++) - gdisp_lld_draw_pixel(g); - g->p.y = y0; - } -#endif + area = (uint32_t)g->p.cx * g->p.cy; + gdisp_lld_write_start(g); + #if GDISP_HARDWARE_STREAM_POS + #if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT + if (g->vmt->writepos) + #endif + gdisp_lld_write_pos(g); + #endif + for(; area; area--) + gdisp_lld_write_color(g); + gdisp_lld_write_stop(g); + return; + } + #endif -#if NEED_CLIPPING - #define TEST_CLIP_AREA(g) \ - if ((g)->p.x < (g)->clipx0) { (g)->p.cx -= (g)->clipx0 - (g)->p.x; (g)->p.x = (g)->clipx0; } \ - if ((g)->p.y < (g)->clipy0) { (g)->p.cy -= (g)->clipy0 - (g)->p.y; (g)->p.y = (g)->clipy0; } \ - if ((g)->p.x + (g)->p.cx > (g)->clipx1) (g)->p.cx = (g)->clipx1 - (g)->p.x; \ - if ((g)->p.y + (g)->p.cy > (g)->clipy1) (g)->p.cy = (g)->clipy1 - (g)->p.y; \ - if ((g)->p.cx > 0 && (g)->p.cy > 0) -#else - #define TEST_CLIP_AREA(g) -#endif + // Worst is pixel drawing + #if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL + // The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming + //#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT + // if (g->vmt->pixel) + //#endif + { + coord_t x0, y0, x1, y1; + + x0 = g->p.x; + y0 = g->p.y; + x1 = g->p.x + g->p.cx; + y1 = g->p.y + g->p.cy; + for(; g->p.y < y1; g->p.y++, g->p.x = x0) + for(; g->p.x < x1; g->p.x++) + gdisp_lld_draw_pixel(g); + g->p.y = y0; + return; + } + #endif +} // Parameters: x,y and x1 // Alters: x,y x1,y1 cx,cy @@ -186,10 +241,15 @@ static void hline_clip(GDisplay *g) { // Clipping #if NEED_CLIPPING - if (g->p.y < g->clipy0 || g->p.y >= g->clipy1) return; - if (g->p.x < g->clipx0) g->p.x = g->clipx0; - if (g->p.x1 >= g->clipx1) g->p.x1 = g->clipx1 - 1; - if (g->p.x1 < g->p.x) return; + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + if (!g->vmt->setclip) + #endif + { + if (g->p.y < g->clipy0 || g->p.y >= g->clipy1) return; + if (g->p.x < g->clipx0) g->p.x = g->clipx0; + if (g->p.x1 >= g->clipx1) g->p.x1 = g->clipx1 - 1; + if (g->p.x1 < g->p.x) return; + } #endif // This is an optimization for the point case. It is only worthwhile however if we @@ -197,48 +257,64 @@ static void hline_clip(GDisplay *g) { #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) // Is this a point if (g->p.x == g->p.x1) { - #if GDISP_HARDWARE_DRAWPIXEL - // Best is hardware accelerated pixel draw - gdisp_lld_draw_pixel(g); - #elif GDISP_HARDWARE_STREAM_POS - // Next best is cursor based streaming - if (!(g->flags & GDISP_FLG_SCRSTREAM)) - setglobalwindow(g); - gdisp_lld_write_pos(g); - gdisp_lld_write_color(g); - #else - // Worst is streaming - g->p.cx = g->p.cy = 1; - gdisp_lld_write_start(g); - gdisp_lld_write_color(g); - gdisp_lld_write_stop(g); - #endif + drawpixel(g); return; } #endif + // Best is hardware accelerated area fill #if GDISP_HARDWARE_FILLS - // Best is hardware accelerated area fill - g->p.cx = g->p.x1 - g->p.x + 1; - g->p.cy = 1; - gdisp_lld_fill_area(g); - #elif GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - // Next best is cursor based streaming - if (!(g->flags & GDISP_FLG_SCRSTREAM)) - setglobalwindow(g); - gdisp_lld_write_pos(g); - do { gdisp_lld_write_color(g); } while(g->p.cx--); - #elif GDISP_HARDWARE_STREAM_WRITE - // Next best is streaming - g->p.cx = g->p.x1 - g->p.x + 1; - g->p.cy = 1; - gdisp_lld_write_start(g); - do { gdisp_lld_write_color(g); } while(g->p.cx--); - gdisp_lld_write_stop(g); - #else - // Worst is drawing pixels - for(; g->p.x <= g->p.x1; g->p.x++) - gdisp_lld_draw_pixel(g); + #if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT + if (g->vmt->fill) + #endif + { + g->p.cx = g->p.x1 - g->p.x + 1; + g->p.cy = 1; + gdisp_lld_fill_area(g); + return; + } + #endif + + // Next best is cursor based streaming + #if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + #if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT + if (g->vmt->writepos) + #endif + { + if (!(g->flags & GDISP_FLG_SCRSTREAM)) + setglobalwindow(g); + gdisp_lld_write_pos(g); + do { gdisp_lld_write_color(g); } while(g->p.cx--); + return; + } + #endif + + // Next best is streaming + #if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_POS != TRUE && GDISP_HARDWARE_STREAM_WRITE + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + if (g->vmt->writestart) + #endif + { + g->p.cx = g->p.x1 - g->p.x + 1; + g->p.cy = 1; + gdisp_lld_write_start(g); + do { gdisp_lld_write_color(g); } while(g->p.cx--); + gdisp_lld_write_stop(g); + return; + } + #endif + + // Worst is drawing pixels + #if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL + // The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming + //#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT + // if (g->vmt->pixel) + //#endif + { + for(; g->p.x <= g->p.x1; g->p.x++) + gdisp_lld_draw_pixel(g); + return; + } #endif } @@ -252,10 +328,15 @@ static void vline_clip(GDisplay *g) { // Clipping #if NEED_CLIPPING - if (g->p.x < g->clipx0 || g->p.x >= g->clipx1) return; - if (g->p.y < g->clipy0) g->p.y = g->clipy0; - if (g->p.y1 >= g->clipy1) g->p.y1 = g->clipy1 - 1; - if (g->p.y1 < g->p.y) return; + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + if (!g->vmt->setclip) + #endif + { + if (g->p.x < g->clipx0 || g->p.x >= g->clipx1) return; + if (g->p.y < g->clipy0) g->p.y = g->clipy0; + if (g->p.y1 >= g->clipy1) g->p.y1 = g->clipy1 - 1; + if (g->p.y1 < g->p.y) return; + } #endif // This is an optimization for the point case. It is only worthwhile however if we @@ -263,51 +344,62 @@ static void vline_clip(GDisplay *g) { #if GDISP_HARDWARE_FILLS || (GDISP_HARDWARE_DRAWPIXEL && GDISP_HARDWARE_STREAM_WRITE) || (GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE) // Is this a point if (g->p.y == g->p.y1) { - #if GDISP_HARDWARE_DRAWPIXEL - // Best is hardware accelerated pixel draw - gdisp_lld_draw_pixel(g); - #elif GDISP_HARDWARE_STREAM_POS - // Next best is cursor based streaming - if (!(g->flags & GDISP_FLG_SCRSTREAM)) - setglobalwindow(g); - gdisp_lld_write_pos(g); - gdisp_lld_write_color(g); - #else - // Worst is streaming - g->p.cx = g->p.cy = 1; - gdisp_lld_write_start(g); - gdisp_lld_write_color(g); - gdisp_lld_write_stop(g); - #endif + drawpixel(g); return; } #endif + // Best is hardware accelerated area fill #if GDISP_HARDWARE_FILLS - // Best is hardware accelerated area fill - g->p.cy = g->p.y1 - g->p.y + 1; - g->p.cx = 1; - gdisp_lld_fill_area(g); - #elif GDISP_HARDWARE_STREAM_WRITE - // Next best is streaming - #if GDISP_HARDWARE_STREAM_POS - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } + #if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT + if (g->vmt->fill) #endif - g->p.cy = g->p.y1 - g->p.y + 1; - g->p.cx = 1; - gdisp_lld_write_start(g); - #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(g); + { + g->p.cy = g->p.y1 - g->p.y + 1; + g->p.cx = 1; + gdisp_lld_fill_area(g); + return; + } + #endif + + // Next best is streaming + #if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + if (g->vmt->writestart) #endif - do { gdisp_lld_write_color(g); } while(g->p.cy--); - gdisp_lld_write_stop(g); - #else - // Worst is drawing pixels - for(; g->p.y <= g->p.y1; g->p.y++) - gdisp_lld_draw_pixel(g); + { + #if GDISP_HARDWARE_STREAM_POS + if ((g->flags & GDISP_FLG_SCRSTREAM)) { + gdisp_lld_write_stop(g); + g->flags &= ~GDISP_FLG_SCRSTREAM; + } + #endif + g->p.cy = g->p.y1 - g->p.y + 1; + g->p.cx = 1; + gdisp_lld_write_start(g); + #if GDISP_HARDWARE_STREAM_POS + #if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT + if (g->vmt->writepos) + #endif + gdisp_lld_write_pos(g); + #endif + do { gdisp_lld_write_color(g); } while(g->p.cy--); + gdisp_lld_write_stop(g); + return; + } + #endif + + // Worst is drawing pixels + #if GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL + // The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming + //#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT + // if (g->vmt->pixel) + //#endif + { + for(; g->p.y <= g->p.y1; g->p.y++) + gdisp_lld_draw_pixel(g); + return; + } #endif } @@ -390,7 +482,6 @@ static void line_clip(GDisplay *g) { #if GDISP_STARTUP_LOGO_TIMEOUT > 0 static void StatupLogoDisplay(GDisplay *g) { - gdispGClear(g, Black); gdispGFillArea(g, g->g.Width/4, g->g.Height/4, g->g.Width/2, g->g.Height/2, Blue); } #endif @@ -420,31 +511,47 @@ void _gdispInit(void) { MUTEX_ENTER(g); g->flags = 0; gdisp_lld_init(g, i); + + // Set the initial clipping region #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP + + // Best is hardware clipping #if GDISP_HARDWARE_CLIP - g->p.x = x; - g->p.y = y; - g->p.cx = cx; - g->p.cy = cy; - gdisp_lld_set_clip(g); - #else - g->clipx0 = 0; - g->clipy0 = 0; - g->clipx1 = g->g.Width; - g->clipy1 = g->g.Height; + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + if (g->vmt->setclip) + #endif + { + g->p.x = 0; + g->p.y = 0; + g->p.cx = g->g.Width; + g->p.cy = g->g.Height; + gdisp_lld_set_clip(g); + } + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + else + #endif + #endif + + // Worst is software clipping + #if GDISP_HARDWARE_CLIP != TRUE + { + g->clipx0 = 0; + g->clipy0 = 0; + g->clipx1 = g->g.Width; + g->clipy1 = g->g.Height; + } #endif #endif MUTEX_EXIT(g); + gdispGClear(g, GDISP_STARTUP_COLOR); #if GDISP_STARTUP_LOGO_TIMEOUT > 0 StatupLogoDisplay(g); - #else - gdispGClear(g, Black); #endif } #if GDISP_STARTUP_LOGO_TIMEOUT > 0 gfxSleepMilliseconds(GDISP_STARTUP_LOGO_TIMEOUT); for(g = GDisplayArray, i = 0; i < GDISP_TOTAL_DISPLAYS; g++, i++) - gdispGClear(g, Black); + gdispGClear(g, GDISP_STARTUP_COLOR); #endif } @@ -463,6 +570,9 @@ void gdispSetDisplay(GDisplay *g) { MUTEX_ENTER(g); #if NEED_CLIPPING + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + if (!g->vmt->setclip) + #endif // Test if the area is valid - if not then exit if (x < g->clipx0 || x+cx > g->clipx1 || y < g->clipy0 || y+cy > g->clipy1) { MUTEX_EXIT(g); @@ -472,28 +582,45 @@ void gdispSetDisplay(GDisplay *g) { g->flags |= GDISP_FLG_INSTREAM; + // Best is hardware streaming #if GDISP_HARDWARE_STREAM_WRITE - // Best is hardware streaming - g->p.x = x; - g->p.y = y; - g->p.cx = cx; - g->p.cy = cy; - gdisp_lld_write_start(g); - #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(g); + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + if (g->vmt->writestart) #endif - #else - // Worst - save the parameters and use pixel drawing + { + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + gdisp_lld_write_start(g); + #if GDISP_HARDWARE_STREAM_POS + #if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT + if (g->vmt->writepos) + #endif + gdisp_lld_write_pos(g); + #endif + return; + } + #endif - // Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position, cx = bufpos - g->p.x1 = g->p.x = x; - g->p.y1 = g->p.y = y; - g->p.x2 = x + cx; - g->p.y2 = y + cy; - #if (GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS) || GDISP_HARDWARE_FILLS - g->p.cx = 0; - g->p.cy = 1; - #endif + // Worst - save the parameters and use pixel drawing and/or area fills + #if GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL + // The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming + //#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT + // if (g->vmt->pixel) + //#endif + { + // Use x,y as the current position, x1,y1 as the save position and x2,y2 as the end position, cx = bufpos + g->p.x1 = g->p.x = x; + g->p.y1 = g->p.y = y; + g->p.x2 = x + cx; + g->p.y2 = y + cy; + #if (GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS) || GDISP_HARDWARE_FILLS + g->p.cx = 0; + g->p.cy = 1; + #endif + return; + } #endif // Don't release the mutex as gdispStreamEnd() will do that. @@ -510,28 +637,26 @@ void gdispSetDisplay(GDisplay *g) { if (!(g->flags & GDISP_FLG_INSTREAM)) return; + // Best is hardware streaming #if GDISP_HARDWARE_STREAM_WRITE - // Best is hardware streaming - g->p.color = color; - gdisp_lld_write_color(g); - #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS - g->linebuf[g->p.cx++] = color; - if (g->p.cx >= GDISP_LINEBUF_SIZE) { - sx1 = g->p.x1; - sy1 = g->p.y1; - g->p.x1 = 0; - g->p.y1 = 0; - g->p.ptr = (void *)g->linebuf; - gdisp_lld_blit_area(g); - g->p.x1 = sx1; - g->p.y1 = sy1; - g->p.x += g->p.cx; - g->p.cx = 0; + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + if (g->vmt->writestart) + #endif + { + g->p.color = color; + gdisp_lld_write_color(g); + return; } + #endif - // Just wrap at end-of-line and end-of-buffer - if (g->p.x+g->p.cx >= g->p.x2) { - if (g->p.cx) { + // Next best is to use bitfills with our line buffer + #if GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS + #if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT + if (g->vmt->blit) + #endif + { + g->linebuf[g->p.cx++] = color; + if (g->p.cx >= GDISP_LINEBUF_SIZE) { sx1 = g->p.x1; sy1 = g->p.y1; g->p.x1 = 0; @@ -540,49 +665,83 @@ void gdispSetDisplay(GDisplay *g) { gdisp_lld_blit_area(g); g->p.x1 = sx1; g->p.y1 = sy1; + g->p.x += g->p.cx; g->p.cx = 0; } - g->p.x = g->p.x1; - if (++g->p.y >= g->p.y2) - g->p.y = g->p.y1; + + // Just wrap at end-of-line and end-of-buffer + if (g->p.x+g->p.cx >= g->p.x2) { + if (g->p.cx) { + sx1 = g->p.x1; + sy1 = g->p.y1; + g->p.x1 = 0; + g->p.y1 = 0; + g->p.ptr = (void *)g->linebuf; + gdisp_lld_blit_area(g); + g->p.x1 = sx1; + g->p.y1 = sy1; + g->p.cx = 0; + } + g->p.x = g->p.x1; + if (++g->p.y >= g->p.y2) + g->p.y = g->p.y1; + } } - #elif GDISP_HARDWARE_FILLS - // Only slightly better than drawing pixels is to look for runs and use fill area - if (!g->p.cx || g->p.color == color) { - g->p.cx++; - g->p.color = color; - } else { - if (g->p.cx == 1) - gdisp_lld_draw_pixel(g); - else - gdisp_lld_fill_area(g); - g->p.x += g->p.cx; - g->p.color = color; - g->p.cx = 1; - } - // Just wrap at end-of-line and end-of-buffer - if (g->p.x+g->p.cx >= g->p.x2) { - if (g->p.cx) { + #endif + + // Only slightly better than drawing pixels is to look for runs and use fillarea + #if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS + // We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming. + #if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT + if (g->vmt->fill) + #endif + { + if (!g->p.cx || g->p.color == color) { + g->p.cx++; + g->p.color = color; + } else { if (g->p.cx == 1) gdisp_lld_draw_pixel(g); else gdisp_lld_fill_area(g); - g->p.cx = 0; + g->p.x += g->p.cx; + g->p.color = color; + g->p.cx = 1; } - g->p.x = g->p.x1; - if (++g->p.y >= g->p.y2) - g->p.y = g->p.y1; + // Just wrap at end-of-line and end-of-buffer + if (g->p.x+g->p.cx >= g->p.x2) { + if (g->p.cx) { + if (g->p.cx == 1) + gdisp_lld_draw_pixel(g); + else + gdisp_lld_fill_area(g); + g->p.cx = 0; + } + g->p.x = g->p.x1; + if (++g->p.y >= g->p.y2) + g->p.y = g->p.y1; + } + return; } - #else - // Worst is using pixel drawing - g->p.color = color; - gdisp_lld_draw_pixel(g); + #endif - // Just wrap at end-of-line and end-of-buffer - if (++g->p.x >= g->p.x2) { - g->p.x = g->p.x1; - if (++g->p.y >= g->p.y2) - g->p.y = g->p.y1; + // Worst is using pixel drawing + #if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_DRAWPIXEL + // The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming + //#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT + // if (g->vmt->pixel) + //#endif + { + g->p.color = color; + gdisp_lld_draw_pixel(g); + + // Just wrap at end-of-line and end-of-buffer + if (++g->p.x >= g->p.x2) { + g->p.x = g->p.x1; + if (++g->p.y >= g->p.y2) + g->p.y = g->p.y1; + } + return; } #endif } @@ -592,25 +751,54 @@ void gdispSetDisplay(GDisplay *g) { if (!(g->flags & GDISP_FLG_INSTREAM)) return; + // Clear the flag + g->flags &= ~GDISP_FLG_INSTREAM; + + // The cleanup below must match the streaming code above. + #if GDISP_HARDWARE_STREAM_WRITE - gdisp_lld_write_stop(g); - #elif GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS - if (g->p.cx) { - g->p.x1 = 0; - g->p.y1 = 0; - g->p.ptr = (void *)g->linebuf; - gdisp_lld_blit_area(g); - } - #elif GDISP_HARDWARE_FILLS - if (g->p.cx) { - if (g->p.cx == 1) - gdisp_lld_draw_pixel(g); - else - gdisp_lld_fill_area(g); + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + if (g->vmt->writestart) + #endif + { + gdisp_lld_write_stop(g); + MUTEX_EXIT(g); + return; + } + #endif + + #if GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_LINEBUF_SIZE != 0 && GDISP_HARDWARE_BITFILLS + #if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT + if (g->vmt->blit) + #endif + { + if (g->p.cx) { + g->p.x1 = 0; + g->p.y1 = 0; + g->p.ptr = (void *)g->linebuf; + gdisp_lld_blit_area(g); + } + MUTEX_EXIT(g); + return; + } + #endif + + #if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS + // We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming. + #if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT + if (g->vmt->fill) + #endif + { + if (g->p.cx) { + if (g->p.cx == 1) + gdisp_lld_draw_pixel(g); + else + gdisp_lld_fill_area(g); + } + MUTEX_EXIT(g); + return; } #endif - g->flags &= ~GDISP_FLG_INSTREAM; - MUTEX_EXIT(g); } #endif @@ -650,42 +838,79 @@ void gdispGClear(GDisplay *g, color_t color) { // Note - clear() ignores the clipping area. It clears the screen. MUTEX_ENTER(g); + // Best is hardware accelerated clear #if GDISP_HARDWARE_CLEARS - // Best is hardware accelerated clear - g->p.color = color; - gdisp_lld_clear(g); - #elif GDISP_HARDWARE_FILLS - // Next best is hardware accelerated area fill - g->p.x = g->p.y = 0; - g->p.cx = g->g.Width; - g->p.cy = g->g.Height; - g->p.color = color; - gdisp_lld_fill_area(g); - #elif GDISP_HARDWARE_STREAM_WRITE - // Next best is streaming - uint32_t area; - - g->p.x = g->p.y = 0; - g->p.cx = g->g.Width; - g->p.cy = g->g.Height; - g->p.color = color; - area = (uint32_t)g->p.cx * g->p.cy; - - gdisp_lld_write_start(g); - #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(g); + #if GDISP_HARDWARE_CLEARS == HARDWARE_AUTODETECT + if (g->vmt->clear) #endif - for(; area; area--) - gdisp_lld_write_color(g); - gdisp_lld_write_stop(g); - #else - // Worst is drawing pixels - g->p.color = color; - for(g->p.y = 0; g->p.y < g->g.Height; g->p.y++) - for(g->p.x = 0; g->p.x < g->g.Width; g->p.x++) - gdisp_lld_draw_pixel(g); + { + g->p.color = color; + gdisp_lld_clear(g); + MUTEX_EXIT(g); + return; + } + #endif + + // Next best is hardware accelerated area fill + #if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS + #if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT + if (g->vmt->fill) + #endif + { + g->p.x = g->p.y = 0; + g->p.cx = g->g.Width; + g->p.cy = g->g.Height; + g->p.color = color; + gdisp_lld_fill_area(g); + MUTEX_EXIT(g); + return; + } + #endif + + // Next best is streaming + #if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + if (g->vmt->writestart) + #endif + { + uint32_t area; + + g->p.x = g->p.y = 0; + g->p.cx = g->g.Width; + g->p.cy = g->g.Height; + g->p.color = color; + area = (uint32_t)g->p.cx * g->p.cy; + + gdisp_lld_write_start(g); + #if GDISP_HARDWARE_STREAM_POS + #if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT + if (g->vmt->writepos) + #endif + gdisp_lld_write_pos(g); + #endif + for(; area; area--) + gdisp_lld_write_color(g); + gdisp_lld_write_stop(g); + MUTEX_EXIT(g); + return; + } + #endif + + // Worst is drawing pixels + #if GDISP_HARDWARE_CLEARS != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL + // The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming + //#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT + // if (g->vmt->pixel) + //#endif + { + g->p.color = color; + for(g->p.y = 0; g->p.y < g->g.Height; g->p.y++) + for(g->p.x = 0; g->p.x < g->g.Width; g->p.x++) + gdisp_lld_draw_pixel(g); + MUTEX_EXIT(g); + return; + } #endif - MUTEX_EXIT(g); } void gdispGFillArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { @@ -705,113 +930,166 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c MUTEX_ENTER(g); #if NEED_CLIPPING - // This is a different cliping to fillarea(g) as it needs to take into account srcx,srcy - if (x < g->clipx0) { cx -= g->clipx0 - x; srcx += g->clipx0 - x; x = g->clipx0; } - if (y < g->clipy0) { cy -= g->clipy0 - y; srcy += g->clipy0 - x; y = g->clipy0; } - if (x+cx > g->clipx1) cx = g->clipx1 - x; - if (y+cy > g->clipy1) cy = g->clipy1 - y; - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0) { MUTEX_EXIT(g); return; } - #endif - - #if GDISP_HARDWARE_BITFILLS - // Best is hardware bitfills - g->p.x = x; - g->p.y = y; - g->p.cx = cx; - g->p.cy = cy; - g->p.x1 = srcx; - g->p.y1 = srcy; - g->p.x2 = srccx; - g->p.ptr = (void *)buffer; - gdisp_lld_blit_area(g); - #elif GDISP_HARDWARE_STREAM_WRITE - // Next best is hardware streaming - - // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap - buffer += srcy*srccx+srcx; - srcx = x + cx; - srcy = y + cy; - srccx -= cx; - - g->p.x = x; - g->p.y = y; - g->p.cx = cx; - g->p.cy = cy; - gdisp_lld_write_start(g); - #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(g); + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + if (!g->vmt->setclip) #endif - for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) { - for(g->p.x = x; g->p.x < srcx; g->p.x++) { - g->p.color = *buffer++; - gdisp_lld_write_color(g); - } - } - gdisp_lld_write_stop(g); - #elif GDISP_HARDWARE_FILLS - // Only slightly better than drawing pixels is to look for runs and use fill area - - // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap - buffer += srcy*srccx+srcx; - srcx = x + cx; - srcy = y + cy; - srccx -= cx; - - g->p.cy = 1; - for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) { - for(g->p.x=x; g->p.x < srcx; g->p.x += g->p.cx) { - g->p.cx=1; - g->p.color = *buffer++; - while(g->p.x+g->p.cx < srcx && *buffer == g->p.color) { - g->p.cx++; - buffer++; - } - if (g->p.cx == 1) { - gdisp_lld_draw_pixel(g); - } else { - gdisp_lld_fill_area(g); - } - } - } - #else - // Worst is drawing pixels - - // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap - buffer += srcy*srccx+srcx; - srcx = x + cx; - srcy = y + cy; - srccx -= cx; - - for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) { - for(g->p.x=x; g->p.x < srcx; g->p.x++) { - g->p.color = *buffer++; - gdisp_lld_draw_pixel(g); - } + { + // This is a different cliping to fillarea(g) as it needs to take into account srcx,srcy + if (x < g->clipx0) { cx -= g->clipx0 - x; srcx += g->clipx0 - x; x = g->clipx0; } + if (y < g->clipy0) { cy -= g->clipy0 - y; srcy += g->clipy0 - x; y = g->clipy0; } + if (x+cx > g->clipx1) cx = g->clipx1 - x; + if (y+cy > g->clipy1) cy = g->clipy1 - y; + if (srcx+cx > srccx) cx = srccx - srcx; + if (cx <= 0 || cy <= 0) { MUTEX_EXIT(g); return; } + } + #endif + + // Best is hardware bitfills + #if GDISP_HARDWARE_BITFILLS + #if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT + if (g->vmt->blit) + #endif + { + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + g->p.x1 = srcx; + g->p.y1 = srcy; + g->p.x2 = srccx; + g->p.ptr = (void *)buffer; + gdisp_lld_blit_area(g); + MUTEX_EXIT(g); + return; + } + #endif + + // Next best is hardware streaming + #if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + if (g->vmt->writestart) + #endif + { + // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap + buffer += srcy*srccx+srcx; + srcx = x + cx; + srcy = y + cy; + srccx -= cx; + + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + gdisp_lld_write_start(g); + #if GDISP_HARDWARE_STREAM_POS + #if GDISP_HARDWARE_STREAM_POS == HARDWARE_AUTODETECT + if (g->vmt->writepos) + #endif + gdisp_lld_write_pos(g); + #endif + for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) { + for(g->p.x = x; g->p.x < srcx; g->p.x++) { + g->p.color = *buffer++; + gdisp_lld_write_color(g); + } + } + gdisp_lld_write_stop(g); + MUTEX_EXIT(g); + return; + } + #endif + + // Only slightly better than drawing pixels is to look for runs and use fill area + #if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS + // We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming. + #if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT + if (g->vmt->fill) + #endif + { + // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap + buffer += srcy*srccx+srcx; + srcx = x + cx; + srcy = y + cy; + srccx -= cx; + + g->p.cy = 1; + for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) { + for(g->p.x=x; g->p.x < srcx; g->p.x += g->p.cx) { + g->p.cx=1; + g->p.color = *buffer++; + while(g->p.x+g->p.cx < srcx && *buffer == g->p.color) { + g->p.cx++; + buffer++; + } + if (g->p.cx == 1) { + gdisp_lld_draw_pixel(g); + } else { + gdisp_lld_fill_area(g); + } + } + } + MUTEX_EXIT(g); + return; + } + #endif + + // Worst is drawing pixels + #if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_DRAWPIXEL + // The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming + //#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT + // if (g->vmt->pixel) + //#endif + { + // Translate buffer to the real image data, use srcx,srcy as the end point, srccx as the buffer line gap + buffer += srcy*srccx+srcx; + srcx = x + cx; + srcy = y + cy; + srccx -= cx; + + for(g->p.y = y; g->p.y < srcy; g->p.y++, buffer += srccx) { + for(g->p.x=x; g->p.x < srcx; g->p.x++) { + g->p.color = *buffer++; + gdisp_lld_draw_pixel(g); + } + } + MUTEX_EXIT(g); + return; } #endif - MUTEX_EXIT(g); } #if GDISP_NEED_CLIP void gdispGSetClip(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy) { MUTEX_ENTER(g); + + // Best is using hardware clipping #if GDISP_HARDWARE_CLIP - // Best is using hardware clipping - g->p.x = x; - g->p.y = y; - g->p.cx = cx; - g->p.cy = cy; - gdisp_lld_set_clip(g); - #else - // Worst is using software clipping - if (x < 0) { cx += x; x = 0; } - if (y < 0) { cy += y; y = 0; } - if (cx <= 0 || cy <= 0 || x >= g->g.Width || y >= g->g.Height) { MUTEX_EXIT(g); return; } - g->clipx0 = x; - g->clipy0 = y; - g->clipx1 = x+cx; if (g->clipx1 > g->g.Width) g->clipx1 = g->g.Width; - g->clipy1 = y+cy; if (g->clipy1 > g->g.Height) g->clipy1 = g->g.Height; + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + if (g->vmt->setclip) + #endif + { + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + gdisp_lld_set_clip(g); + } + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + else + #endif + #endif + + // Worst is using software clipping + #if GDISP_HARDWARE_CLIP != TRUE + { + if (x < 0) { cx += x; x = 0; } + if (y < 0) { cy += y; y = 0; } + if (cx <= 0 || cy <= 0 || x >= g->g.Width || y >= g->g.Height) { MUTEX_EXIT(g); return; } + g->clipx0 = x; + g->clipy0 = y; + g->clipx1 = x+cx; if (g->clipx1 > g->g.Width) g->clipx1 = g->g.Width; + g->clipy1 = y+cy; if (g->clipy1 > g->g.Height) g->clipy1 = g->g.Height; + } #endif MUTEX_EXIT(g); } @@ -1733,26 +2011,43 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c /* Always synchronous as it must return a value */ MUTEX_ENTER(g); #if GDISP_HARDWARE_PIXELREAD - // Best is direct pixel read - g->p.x = x; - g->p.y = y; - c = gdisp_lld_get_pixel_color(g); - #elif GDISP_HARDWARE_STREAM_READ - // Next best is hardware streaming - g->p.x = x; - g->p.y = y; - g->p.cx = 1; - g->p.cy = 1; - gdisp_lld_read_start(g); - c = gdisp_lld_read_color(g); - gdisp_lld_read_stop(g); - #else - // Worst is "not possible" - #error "GDISP: GDISP_NEED_PIXELREAD has been set but there is no hardware support for reading the display" + #if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT + if (g->vmt->get) + #endif + { + // Best is direct pixel read + g->p.x = x; + g->p.y = y; + c = gdisp_lld_get_pixel_color(g); + MUTEX_EXIT(g); + return c; + } + #endif + #if GDISP_HARDWARE_PIXELREAD != TRUE && GDISP_HARDWARE_STREAM_READ + #if GDISP_HARDWARE_STREAM_READ == HARDWARE_AUTODETECT + if (g->vmt->readcolor) + #endif + { + // Next best is hardware streaming + g->p.x = x; + g->p.y = y; + g->p.cx = 1; + g->p.cy = 1; + gdisp_lld_read_start(g); + c = gdisp_lld_read_color(g); + gdisp_lld_read_stop(g); + MUTEX_EXIT(g); + return c; + } + #endif + #if GDISP_HARDWARE_PIXELREAD != TRUE && GDISP_HARDWARE_STREAM_READ != TRUE + #if !GDISP_HARDWARE_PIXELREAD && !GDISP_HARDWARE_STREAM_READ + // Worst is "not possible" + #error "GDISP: GDISP_NEED_PIXELREAD has been set but there is no hardware support for reading the display" + #endif + MUTEX_EXIT(g); + return 0; #endif - MUTEX_EXIT(g); - - return c; } #endif @@ -1765,11 +2060,16 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c MUTEX_ENTER(g); #if NEED_CLIPPING - if (x < g->clipx0) { cx -= g->clipx0 - x; x = g->clipx0; } - if (y < g->clipy0) { cy -= g->clipy0 - y; y = g->clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= g->clipx1 || y >= g->clipy1) { MUTEX_EXIT(g); return; } - if (x+cx > g->clipx1) cx = g->clipx1 - x; - if (y+cy > g->clipy1) cy = g->clipy1 - y; + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + if (!g->vmt->setclip) + #endif + { + if (x < g->clipx0) { cx -= g->clipx0 - x; x = g->clipx0; } + if (y < g->clipy0) { cy -= g->clipy0 - y; y = g->clipy0; } + if (!lines || cx <= 0 || cy <= 0 || x >= g->clipx1 || y >= g->clipy1) { MUTEX_EXIT(g); return; } + if (x+cx > g->clipx1) cx = g->clipx1 - x; + if (y+cy > g->clipy1) cy = g->clipy1 - y; + } #endif abslines = lines < 0 ? -lines : lines; @@ -1777,95 +2077,159 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c abslines = cy; cy = 0; } else { + // Best is hardware scroll #if GDISP_HARDWARE_SCROLL - g->p.x = x; - g->p.y = y; - g->p.cx = cx; - g->p.cy = cy; - g->p.y1 = lines; - g->p.color = bgcolor; - gdisp_lld_vertical_scroll(g); - cy -= abslines; + #if GDISP_HARDWARE_SCROLL == HARDWARE_AUTODETECT + if (g->vmt->vscroll) + #endif + { + g->p.x = x; + g->p.y = y; + g->p.cx = cx; + g->p.cy = cy; + g->p.y1 = lines; + g->p.color = bgcolor; + gdisp_lld_vertical_scroll(g); + cy -= abslines; + } + #if GDISP_HARDWARE_SCROLL == HARDWARE_AUTODETECT + else + #endif #elif GDISP_LINEBUF_SIZE == 0 #error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support and GDISP_LINEBUF_SIZE is zero." - #else - cy -= abslines; - if (lines < 0) { - fy = y+cy-1; - dy = -1; - } else { - fy = y; - dy = 1; - } - // Move the screen - one line at a time - for(i = 0; i < cy; i++, fy += dy) { + #endif - // Handle where the buffer is smaller than a line - for(ix=0; ix < cx; ix += GDISP_LINEBUF_SIZE) { + // Scroll Emulation + #if GDISP_HARDWARE_SCROLL != TRUE + { + cy -= abslines; + if (lines < 0) { + fy = y+cy-1; + dy = -1; + } else { + fy = y; + dy = 1; + } + // Move the screen - one line at a time + for(i = 0; i < cy; i++, fy += dy) { - // Calculate the data we can move in one operation - fx = cx - ix; - if (fx > GDISP_LINEBUF_SIZE) - fx = GDISP_LINEBUF_SIZE; + // Handle where the buffer is smaller than a line + for(ix=0; ix < cx; ix += GDISP_LINEBUF_SIZE) { - // Read one line of data from the screen - #if GDISP_HARDWARE_STREAM_READ - // Best is hardware streaming - g->p.x = x+ix; - g->p.y = fy+lines; - g->p.cx = fx; - g->p.cy = 1; - gdisp_lld_read_start(g); - for(j=0; j < fx; j++) - g->linebuf[j] = gdisp_lld_read_color(g); - gdisp_lld_read_stop(g); - #elif GDISP_HARDWARE_PIXELREAD - // Next best is single pixel reads - for(j=0; j < fx; j++) { - g->p.x = x+ix+j; - g->p.y = fy+lines; - g->linebuf[j] = gdisp_lld_get_pixel_color(g); - } - #else - // Worst is "not possible" - #error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support for scrolling or reading pixels." - #endif + // Calculate the data we can move in one operation + fx = cx - ix; + if (fx > GDISP_LINEBUF_SIZE) + fx = GDISP_LINEBUF_SIZE; - // Write that line to the new location - #if GDISP_HARDWARE_BITFILLS - // Best is hardware bitfills - g->p.x = x+ix; - g->p.y = fy; - g->p.cx = fx; - g->p.cy = 1; - g->p.x1 = 0; - g->p.y1 = 0; - g->p.x2 = fx; - g->p.ptr = (void *)g->linebuf; - gdisp_lld_blit_area(g); - #elif GDISP_HARDWARE_STREAM_WRITE - // Next best is hardware streaming - g->p.x = x+ix; - g->p.y = fy; - g->p.cx = fx; - g->p.cy = 1; - gdisp_lld_write_start(g); - #if GDISP_HARDWARE_STREAM_POS - gdisp_lld_write_pos(g); + // Read one line of data from the screen + + // Best line read is hardware streaming + #if GDISP_HARDWARE_STREAM_READ + #if GDISP_HARDWARE_STREAM_READ == HARDWARE_AUTODETECT + if (g->vmt->readstart) + #endif + { + g->p.x = x+ix; + g->p.y = fy+lines; + g->p.cx = fx; + g->p.cy = 1; + gdisp_lld_read_start(g); + for(j=0; j < fx; j++) + g->linebuf[j] = gdisp_lld_read_color(g); + gdisp_lld_read_stop(g); + } + #if GDISP_HARDWARE_STREAM_READ == HARDWARE_AUTODETECT + else + #endif #endif - for(j = 0; j < fx; j++) { - g->p.color = g->linebuf[j]; - gdisp_lld_write_color(g); - } - gdisp_lld_write_stop(g); - #else - // Worst is drawing pixels - g->p.y = fy; - for(g->p.x = x+ix, j = 0; j < fx; g->p.x++, j++) { - g->p.color = g->linebuf[j]; - gdisp_lld_draw_pixel(g); - } - #endif + + // Next best line read is single pixel reads + #if GDISP_HARDWARE_STREAM_READ != TRUE && GDISP_HARDWARE_PIXELREAD + #if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT + if (g->vmt->get) + #endif + { + for(j=0; j < fx; j++) { + g->p.x = x+ix+j; + g->p.y = fy+lines; + g->linebuf[j] = gdisp_lld_get_pixel_color(g); + } + } + #if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT + else + // Worst is "not possible" + return; + #endif + #endif + + // Worst is "not possible" + #if !GDISP_HARDWARE_STREAM_READ && !GDISP_HARDWARE_PIXELREAD + #error "GDISP: GDISP_NEED_SCROLL is set but there is no hardware support for scrolling or reading pixels." + #endif + + // Write that line to the new location + + // Best line write is hardware bitfills + #if GDISP_HARDWARE_BITFILLS + #if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT + if (g->vmt->blit) + #endif + { + g->p.x = x+ix; + g->p.y = fy; + g->p.cx = fx; + g->p.cy = 1; + g->p.x1 = 0; + g->p.y1 = 0; + g->p.x2 = fx; + g->p.ptr = (void *)g->linebuf; + gdisp_lld_blit_area(g); + } + #if GDISP_HARDWARE_BITFILLS == HARDWARE_AUTODETECT + else + #endif + #endif + + // Next best line write is hardware streaming + #if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + if (g->vmt->writestart) + #endif + { + g->p.x = x+ix; + g->p.y = fy; + g->p.cx = fx; + g->p.cy = 1; + gdisp_lld_write_start(g); + #if GDISP_HARDWARE_STREAM_POS + gdisp_lld_write_pos(g); + #endif + for(j = 0; j < fx; j++) { + g->p.color = g->linebuf[j]; + gdisp_lld_write_color(g); + } + gdisp_lld_write_stop(g); + } + #if GDISP_HARDWARE_STREAM_WRITE == HARDWARE_AUTODETECT + else + #endif + #endif + + // Worst line write is drawing pixels + #if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL + // The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming + //#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT + // if (g->vmt->pixel) + //#endif + { + g->p.y = fy; + for(g->p.x = x+ix, j = 0; j < fx; g->p.x++, j++) { + g->p.color = g->linebuf[j]; + gdisp_lld_draw_pixel(g); + } + } + #endif + } } } #endif @@ -1885,25 +2249,41 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c #if GDISP_NEED_CONTROL #if GDISP_HARDWARE_CONTROL void gdispGControl(GDisplay *g, unsigned what, void *value) { + #if GDISP_HARDWARE_CONTROL == HARDWARE_AUTODETECT + if (!g->vmt->control) + return; + #endif MUTEX_ENTER(g); g->p.x = what; g->p.ptr = value; gdisp_lld_control(g); #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION if (what == GDISP_CONTROL_ORIENTATION) { + // Best is hardware clipping #if GDISP_HARDWARE_CLIP - // Best is hardware clipping - g->p.x = 0; - g->p.y = 0; - g->p.cx = g->g.Width; - g->p.cy = g->g.Height; - gdisp_lld_set_clip(g); - #else - // Worst is software clipping - g->clipx0 = 0; - g->clipy0 = 0; - g->clipx1 = g->g.Width; - g->clipy1 = g->g.Height; + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + if (g->vmt->setclip) + #endif + { + g->p.x = 0; + g->p.y = 0; + g->p.cx = g->g.Width; + g->p.cy = g->g.Height; + gdisp_lld_set_clip(g); + } + #if GDISP_HARDWARE_CLIP == HARDWARE_AUTODETECT + else + #endif + #endif + + // Worst is software clipping + #if GDISP_HARDWARE_CLIP != TRUE + { + g->clipx0 = 0; + g->clipy0 = 0; + g->clipx1 = g->g.Width; + g->clipy1 = g->g.Height; + } #endif } #endif @@ -1923,6 +2303,10 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c void *gdispGQuery(GDisplay *g, unsigned what) { void *res; + #if GDISP_HARDWARE_QUERY == HARDWARE_AUTODETECT + if (!g->vmt->query) + return -1; + #endif MUTEX_ENTER(g); g->p.x = (coord_t)what; res = gdisp_lld_query(g); From 86c6fdf77bfd096aafec6ac4baadbfba4a537ed3 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Wed, 16 Oct 2013 20:33:23 +0200 Subject: [PATCH 048/160] added label define to gfxconf.h --- gfxconf.example.h | 1 + 1 file changed, 1 insertion(+) diff --git a/gfxconf.example.h b/gfxconf.example.h index f3a1e165..f48008aa 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -102,6 +102,7 @@ #define GWIN_NEED_CONSOLE FALSE #define GWIN_NEED_GRAPH FALSE #define GWIN_NEED_WIDGET FALSE +#define GWIN_NEED_LABEL FALSE #define GWIN_NEED_BUTTON FALSE #define GWIN_NEED_SLIDER FALSE #define GWIN_NEED_CHECKBOX FALSE From 2996e701ad223f70c2bf63a5eddf8fd0de9854bb Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 17 Oct 2013 12:33:35 +1000 Subject: [PATCH 049/160] Change gfxconf.h to match updated multi-controller support --- gfxconf.example.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gfxconf.example.h b/gfxconf.example.h index f48008aa..8414dbe0 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -147,10 +147,12 @@ #define GDISP_TOTAL_DISPLAYS 1 #define GDISP_TOTAL_CONTROLLERS 1 - // Extra stuff needed for when GDISP_TOTAL_CONTROLLERS > 1 + // Extra stuff required when GDISP_TOTAL_CONTROLLERS > 1 #define GDISP_CONTROLLER_LIST GDISPVMT_Win32, GDISPVMT_Win32 #define GDISP_CONTROLLER_DISPLAYS 1, 1 #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 + + // Optional extra stuff when GDISP_TOTAL_CONTROLLERS > 1 #define GDISP_HARDWARE_STREAM_WRITE FALSE #define GDISP_HARDWARE_STREAM_READ FALSE #define GDISP_HARDWARE_STREAM_POS FALSE From bc79e65ffa90162111675f8e7d3dbd302011a23c Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 17 Oct 2013 14:55:10 +1000 Subject: [PATCH 050/160] Tiday up driver makefiles --- drivers/multiple/Win32/gdisp_lld.mk | 5 +---- drivers/multiple/Win32/readme.txt | 13 +++++++------ drivers/multiple/X/gdisp_lld.mk | 5 +---- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/multiple/Win32/gdisp_lld.mk b/drivers/multiple/Win32/gdisp_lld.mk index b116088b..081d8dda 100644 --- a/drivers/multiple/Win32/gdisp_lld.mk +++ b/drivers/multiple/Win32/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/multiple/Win32/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/multiple/Win32 +GFXSRC += $(GFXLIB)/drivers/multiple/Win32/gdisp_lld.c diff --git a/drivers/multiple/Win32/readme.txt b/drivers/multiple/Win32/readme.txt index 7ff8546c..353f5a5b 100644 --- a/drivers/multiple/Win32/readme.txt +++ b/drivers/multiple/Win32/readme.txt @@ -1,14 +1,15 @@ To use this driver: -This driver is special in that it implements both the gdisp low level driver -and a touchscreen driver. +This driver is special in that it implements both the gdisp low level driver, +optionally a touchscreen driver, and optionally a toggle driver. 1. Add in your gfxconf.h: a) #define GFX_USE_GDISP TRUE - b) #define GFX_USE_GINPUT TRUE - #define GINPUT_USE_MOUSE TRUE + b) Optionally #define GFX_USE_GINPUT TRUE + #define GINPUT_USE_MOUSE TRUE + #define GINPUT_USE_TOGGLE TRUE c) Any optional high level driver defines (see gdisp.h) eg: GDISP_NEED_MULTITHREAD - d) All of the following (with appropriate values): + d) Optionally the following (with appropriate values): #define GDISP_SCREEN_WIDTH 640 #define GDISP_SCREEN_HEIGHT 480 @@ -17,5 +18,5 @@ and a touchscreen driver. include $(GFXLIB)/gfx.mk include $(GFXLIB)/drivers/multiple/Win32/gdisp_lld.mk -3. Modify your makefile to add -lgdi32 to the DLIBS line. i.e. +3. Modify your makefile to add -lws2_32 and -lgdi32 to the DLIBS line. i.e. DLIBS = -lws2_32 -lgdi32 diff --git a/drivers/multiple/X/gdisp_lld.mk b/drivers/multiple/X/gdisp_lld.mk index 1a4fc4d7..e7b9daef 100644 --- a/drivers/multiple/X/gdisp_lld.mk +++ b/drivers/multiple/X/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/multiple/X/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/multiple/X +GFXSRC += $(GFXLIB)/drivers/multiple/X/gdisp_lld.c From 4c29822a756168779436a5c0b3af0c85ecb7d66d Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 17 Oct 2013 14:56:11 +1000 Subject: [PATCH 051/160] Bugfix to remove compile error that only affects GCC ARM compiler --- include/gdisp/lld/gdisp_lld.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index b1e89f09..1a08b330 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -171,7 +171,7 @@ /* External declarations. */ /*===========================================================================*/ -typedef struct GDisplay { +struct GDisplay { GDISPControl g; // The public GDISP stuff - must be the first element #if GDISP_TOTAL_CONTROLLERS > 1 @@ -224,7 +224,7 @@ typedef struct GDisplay { color_t linebuf[GDISP_LINEBUF_SIZE]; #endif -} GDisplay; +}; #if GDISP_TOTAL_CONTROLLERS == 1 || defined(GDISP_DRIVER_VMT) || defined(__DOXYGEN__) #if GDISP_TOTAL_CONTROLLERS > 1 From e1744e59ab70ced14a76ff133c50504f8e2a68af Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 17 Oct 2013 14:57:47 +1000 Subject: [PATCH 052/160] SSD1289 driver updated for multiple display support --- .../SSD1289/board_SSD1289_firebullstm32f103.h | 107 +++++++ .../SSD1289/board_SSD1289_stm32f4discovery.h | 169 +++++++++++ .../gdisp/SSD1289/board_SSD1289_template.h | 172 +++++++++++ drivers/gdisp/SSD1289/gdisp_lld.c | 266 +++++++++--------- drivers/gdisp/SSD1289/gdisp_lld.mk | 5 +- .../gdisp_lld_board_firebullstm32f103.h | 156 ---------- .../gdisp_lld_board_st_stm32f4_discovery.h | 215 -------------- .../gdisp/SSD1289/gdisp_lld_board_template.h | 141 ---------- drivers/gdisp/SSD1289/gdisp_lld_config.h | 3 - 9 files changed, 584 insertions(+), 650 deletions(-) create mode 100644 drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h create mode 100644 drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h create mode 100644 drivers/gdisp/SSD1289/board_SSD1289_template.h delete mode 100644 drivers/gdisp/SSD1289/gdisp_lld_board_firebullstm32f103.h delete mode 100644 drivers/gdisp/SSD1289/gdisp_lld_board_st_stm32f4_discovery.h delete mode 100644 drivers/gdisp/SSD1289/gdisp_lld_board_template.h diff --git a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h new file mode 100644 index 00000000..fb541df5 --- /dev/null +++ b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h @@ -0,0 +1,107 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1289 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. +#define SET_CS palSetPad(GPIOD, 12); +#define CLR_CS palClearPad(GPIOD, 12); +#define SET_RS palSetPad(GPIOD, 13); +#define CLR_RS palClearPad(GPIOD, 13); +#define SET_WR palSetPad(GPIOD, 14); +#define CLR_WR palClearPad(GPIOD, 14); +#define SET_RD palSetPad(GPIOD, 15); +#define CLR_RD palClearPad(GPIOD, 15); + +static inline void init_board(GDisplay *g, unsigned display) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + if (display == 0) { + + /** + * Set up for Display 0 + */ + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, 12, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, 13, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, 14, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, 15, PAL_MODE_OUTPUT_PUSHPULL); + + // Configure the pins to a well know state + SET_RS; + SET_RD; + SET_WR; + CLR_CS; + } +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; + /* Nothing to do here - reset pin tied to Vcc */ +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; + /* Nothing to do here - Backlight always on */ +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + palWritePort(GPIOE, index); + CLR_RS; CLR_WR; SET_WR; SET_RS; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + palWritePort(GPIOE, data); + CLR_WR; SET_WR; +} + +static inline void setreadmode(GDisplay *g) { + (void) g; + // change pin mode to digital input + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); + CLR_RD; +} + +static inline void setwritemode(GDisplay *g) { + (void) g; + // change pin mode back to digital output + SET_RD; + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); +} + +static inline uint16_t read_data(GDisplay *g) { + return palReadPort(GPIOE); +} +#endif + +#if defined(GDISP_USE_DMA) + #error "GDISP - SSD1289: The GPIO interface does not support DMA" +#endif + +#endif /* _GDISP_LLD_BOARD_H */ + diff --git a/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h new file mode 100644 index 00000000..5a44e631 --- /dev/null +++ b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h @@ -0,0 +1,169 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1289 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. +#define GDISP_REG ((volatile uint16_t *) 0x60000000)[0] /* RS = 0 */ +#define GDISP_RAM ((volatile uint16_t *) 0x60020000)[0] /* RS = 1 */ +#define GDISP_DMA_STREAM STM32_DMA2_STREAM6 +#define FSMC_BANK 0 + +/* PWM configuration structure. We use timer 3 channel 3 */ +static const PWMConfig pwmcfg = { + 100000, /* 100 kHz PWM clock frequency. */ + 100, /* PWM period is 100 cycles. */ + NULL, + { + {PWM_OUTPUT_DISABLED, NULL}, + {PWM_OUTPUT_DISABLED, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_DISABLED, NULL} + }, + 0 +}; + +static inline void init_board(GDisplay *g, unsigned display) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + if (display == 0) { + + /** + * Set up for Display 0 + * + * Performs the following functions: + * 1. initialise the io port used by the display + * 2. initialise the reset pin (initial state not-in-reset) + * 3. initialise the chip select pin (initial state not-active) + * 4. initialise the backlight pin (initial state back-light off) + */ + + #if defined(STM32F1XX) || defined(STM32F3XX) + /* FSMC setup for F1/F3 */ + rccEnableAHB(RCC_AHBENR_FSMCEN, 0); + + #if defined(GDISP_USE_DMA) + #error "GDISP: SSD1289 - DMA not implemented for F1/F3 Devices" + #endif + #elif defined(STM32F4XX) || defined(STM32F2XX) + /* STM32F2-F4 FSMC init */ + rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); + + #if defined(GDISP_USE_DMA) + if (dmaStreamAllocate(GDISP_DMA_STREAM, 0, NULL, NULL)) gfxExit(); + dmaStreamSetMemory0(GDISP_DMA_STREAM, &GDISP_RAM); + dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); + #else + #warning "GDISP: SSD1289 - DMA is supported for F2/F4 Devices. Define GDISP_USE_DMA in your gfxconf.h to turn this on for better performance." + #endif + #else + #error "GDISP: SSD1289 - FSMC not implemented for this device" + #endif + + /* set pins to FSMC mode */ + IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8) | + (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; + + IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | + (1 << 13) | (1 << 14) | (1 << 15), 0}; + + palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); + palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); + + /* FSMC timing */ + FSMC_Bank1->BTCR[FSMC_BANK+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ; + + /* Bank1 NOR/SRAM control register configuration + * This is actually not needed as already set by default after reset */ + FSMC_Bank1->BTCR[FSMC_BANK] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + + /* Display backlight control */ + /* TIM3 is an alternate function 2 (AF2) */ + pwmStart(&PWMD3, &pwmcfg); + palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATE(2)); + pwmEnableChannel(&PWMD3, 2, 100); + } +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + pwmEnableChannel(&PWMD3, 2, percent); +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + GDISP_REG = index; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + GDISP_RAM = data; +} + +static inline void setreadmode(GDisplay *g) { + (void) g; + FSMC_Bank1->BTCR[FSMC_BANK+1] = FSMC_BTR1_ADDSET_3 | FSMC_BTR1_DATAST_3 | FSMC_BTR1_BUSTURN_0; /* FSMC timing */ +} + +static inline void setwritemode(GDisplay *g) { + (void) g; + FSMC_Bank1->BTCR[FSMC_BANK+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0; /* FSMC timing */ +} + +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return GDISP_RAM; +} + +#if defined(GDISP_USE_DMA) || defined(__DOXYGEN__) + static inline void dma_with_noinc(GDisplay *g, color_t *buffer, int area) { + (void) g; + dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); + dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); + for (; area > 0; area -= 65535) { + dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area > 65535 ? 65535 : area); + dmaStreamEnable(GDISP_DMA_STREAM); + dmaWaitCompletion(GDISP_DMA_STREAM); + } + } + + static inline void dma_with_inc(GDisplay *g, color_t *buffer, int area) { + (void) g; + dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); + dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PINC | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); + for (; area > 0; area -= 65535) { + dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area > 65535 ? 65535 : area); + dmaStreamEnable(GDISP_DMA_STREAM); + dmaWaitCompletion(GDISP_DMA_STREAM); + } + } +#endif + +#endif /* _GDISP_LLD_BOARD_H */ + diff --git a/drivers/gdisp/SSD1289/board_SSD1289_template.h b/drivers/gdisp/SSD1289/board_SSD1289_template.h new file mode 100644 index 00000000..552c93a0 --- /dev/null +++ b/drivers/gdisp/SSD1289/board_SSD1289_template.h @@ -0,0 +1,172 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1289/board_SSD1289_template.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1289 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * @param[in] display The display number on this controller (0..n) + * + * @note Set the g->priv member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g, unsigned display) { +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + +} + +/** + * @brief Set the lcd back-light level. + * + * @param[in] g The GDisplay structure + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + +} + +/** + * @brief Set the bus in read mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setreadmode(GDisplay *g) { + +} + +/** + * @brief Set the bus back into write mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setwritemode(GDisplay *g) { + +} + +/** + * @brief Read data from the lcd. + * @return The data from the lcd + * + * @param[in] g The GDisplay structure + * + * @note The chip select may need to be asserted/de-asserted + * around the actual spi read + * + * @notapi + */ +static inline uint16_t read_data(GDisplay *g) { + +} + +/** + * The below section you can replace with #error if your interface doesn't support DMA + */ +#if defined(GDISP_USE_DMA) || defined(__DOXYGEN__) + //#error "GDISP - SSD1289: This interface does not support DMA" + + /** + * @brief Transfer data using DMA but don't increment the source address + * + * @param[in] g The GDisplay structure + * @param[in] buffer The source buffer location + * @param[in] area The number of pixels to transfer + * + * @notapi + */ + static inline void dma_with_noinc(GDisplay *g, color_t *buffer, int area) { + } + + /** + * @brief Transfer data using DMA incrementing the source address + * + * @param[in] g The GDisplay structure + * @param[in] buffer The source buffer location + * @param[in] area The number of pixels to transfer + * + * @notapi + */ + static inline void dma_with_inc(GDisplay *g, color_t *buffer, int area) { + } +#endif + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 09122d2f..3779578d 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -14,9 +14,11 @@ #if GFX_USE_GDISP -#define GDISP_LLD_DECLARATIONS +#define GDISP_DRIVER_VMT GDISPVMT_SSD1289 +#include "../drivers/gdisp/SSD1289/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" -#include "gdisp_lld_board.h" + +#include "board_SSD1289.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -40,32 +42,37 @@ /*===========================================================================*/ // Some common routines and macros -#define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } -#define write_reg(reg, data) { write_index(reg); write_data(data); } +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } -static void set_cursor(GDISPDriver *g) { +static void set_cursor(GDisplay *g) { + /* + * Reg 0x004E is an 8 bit value - start x position + * Reg 0x004F is 9 bit - start y position + * Use a bit mask to make sure they are not set too high + */ switch(g->g.Orientation) { case GDISP_ROTATE_0: - write_reg(0x004e, g->p.x & 0x00FF); - write_reg(0x004f, g->p.y & 0x01FF); + write_reg(g, 0x4e, g->p.x & 0x00FF); + write_reg(g, 0x4f, g->p.y & 0x01FF); break; case GDISP_ROTATE_90: - write_reg(0x004e, g->p.y & 0x00FF); - write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); + write_reg(g, 0x4e, g->p.y & 0x00FF); + write_reg(g, 0x4f, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); break; case GDISP_ROTATE_180: - write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF); - write_reg(0x004f, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); + write_reg(g, 0x4e, (GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF); + write_reg(g, 0x4f, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); break; case GDISP_ROTATE_270: - write_reg(0x004e, (GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF); - write_reg(0x004f, g->p.x & 0x01FF); + write_reg(g, 0x4e, (GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF); + write_reg(g, 0x4f, g->p.x & 0x01FF); break; } - write_index(0x0022); + write_index(g, 0x22); } -static void set_viewport(GDISPDriver* g) { +static void set_viewport(GDisplay* g) { /* Reg 0x44 - Horizontal RAM address position * Upper Byte - HEA * Lower Byte - HSA @@ -73,31 +80,28 @@ static void set_viewport(GDISPDriver* g) { * Reg 0x45,0x46 - Vertical RAM address position * Lower 9 bits gives 0-511 range in each value * 0 <= Reg(0x45) <= Reg(0x46) <= 0x13F - * Reg 0x004E is an 8 bit value - start x position - * Reg 0x004F is 9 bit - start y position * Use a bit mask to make sure they are not set too high */ switch(g->g.Orientation) { case GDISP_ROTATE_0: - write_reg(0x44, (((g->p.x+g->p.cx-1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); - write_reg(0x45, g->p.y & 0x01FF); - write_reg(0x46, (g->p.y+g->p.cy-1) & 0x01FF); + write_reg(g, 0x44, (((g->p.x+g->p.cx-1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); + write_reg(g, 0x45, g->p.y & 0x01FF); + write_reg(g, 0x46, (g->p.y+g->p.cy-1) & 0x01FF); break; case GDISP_ROTATE_90: - write_reg(0x44, (((g->p.y+g->p.cy-1) << 8) & 0xFF00 ) | (g->p.y & 0x00FF)); - write_reg(0x45, (GDISP_SCREEN_HEIGHT-(g->p.x+g->p.cx)) & 0x01FF); - write_reg(0x46, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); + write_reg(g, 0x44, (((g->p.y+g->p.cy-1) << 8) & 0xFF00 ) | (g->p.y & 0x00FF)); + write_reg(g, 0x45, (GDISP_SCREEN_HEIGHT-(g->p.x+g->p.cx)) & 0x01FF); + write_reg(g, 0x46, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); break; case GDISP_ROTATE_180: - write_reg(0x44, (((GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (g->p.x+g->p.cx)) & 0x00FF)); - write_reg(0x45, (GDISP_SCREEN_HEIGHT-(g->p.y+g->p.cy)) & 0x01FF); - write_reg(0x46, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); + write_reg(g, 0x44, (((GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (g->p.x+g->p.cx)) & 0x00FF)); + write_reg(g, 0x45, (GDISP_SCREEN_HEIGHT-(g->p.y+g->p.cy)) & 0x01FF); + write_reg(g, 0x46, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); break; case GDISP_ROTATE_270: - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1); - write_reg(0x44, (((GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH-(g->p.y+g->p.cy)) & 0x00FF)); - write_reg(0x45, g->p.x & 0x01FF); - write_reg(0x46, (g->p.x+g->p.cx-1) & 0x01FF); + write_reg(g, 0x44, (((GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH-(g->p.y+g->p.cy)) & 0x00FF)); + write_reg(g, 0x45, g->p.x & 0x01FF); + write_reg(g, 0x46, (g->p.x+g->p.cx-1) & 0x01FF); break; } } @@ -110,66 +114,66 @@ static void set_viewport(GDISPDriver* g) { /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { /* Initialise your display */ - init_board(); + init_board(g, display); // Hardware reset - setpin_reset(TRUE); + setpin_reset(g, TRUE); gfxSleepMilliseconds(20); - setpin_reset(FALSE); + setpin_reset(g, FALSE); gfxSleepMilliseconds(20); // Get the bus for the following initialisation commands - acquire_bus(); + acquire_bus(g); - write_reg(0x0000,0x0001); gfxSleepMicroseconds(5); - write_reg(0x0003,0xA8A4); gfxSleepMicroseconds(5); - write_reg(0x000C,0x0000); gfxSleepMicroseconds(5); - write_reg(0x000D,0x080C); gfxSleepMicroseconds(5); - write_reg(0x000E,0x2B00); gfxSleepMicroseconds(5); - write_reg(0x001E,0x00B0); gfxSleepMicroseconds(5); - write_reg(0x0001,0x2B3F); gfxSleepMicroseconds(5); - write_reg(0x0002,0x0600); gfxSleepMicroseconds(5); - write_reg(0x0010,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0011,0x6070); gfxSleepMicroseconds(5); - write_reg(0x0005,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0006,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0016,0xEF1C); gfxSleepMicroseconds(5); - write_reg(0x0017,0x0003); gfxSleepMicroseconds(5); - write_reg(0x0007,0x0133); gfxSleepMicroseconds(5); - write_reg(0x000B,0x0000); gfxSleepMicroseconds(5); - write_reg(0x000F,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0041,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0042,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0048,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0049,0x013F); gfxSleepMicroseconds(5); - write_reg(0x004A,0x0000); gfxSleepMicroseconds(5); - write_reg(0x004B,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0044,0xEF00); gfxSleepMicroseconds(5); - write_reg(0x0045,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0046,0x013F); gfxSleepMicroseconds(5); - write_reg(0x0030,0x0707); gfxSleepMicroseconds(5); - write_reg(0x0031,0x0204); gfxSleepMicroseconds(5); - write_reg(0x0032,0x0204); gfxSleepMicroseconds(5); - write_reg(0x0033,0x0502); gfxSleepMicroseconds(5); - write_reg(0x0034,0x0507); gfxSleepMicroseconds(5); - write_reg(0x0035,0x0204); gfxSleepMicroseconds(5); - write_reg(0x0036,0x0204); gfxSleepMicroseconds(5); - write_reg(0x0037,0x0502); gfxSleepMicroseconds(5); - write_reg(0x003A,0x0302); gfxSleepMicroseconds(5); - write_reg(0x003B,0x0302); gfxSleepMicroseconds(5); - write_reg(0x0023,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0024,0x0000); gfxSleepMicroseconds(5); - write_reg(0x0025,0x8000); gfxSleepMicroseconds(5); - write_reg(0x004f,0x0000); gfxSleepMicroseconds(5); - write_reg(0x004e,0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x00, 0x0001); gfxSleepMicroseconds(5); + write_reg(g, 0x03, 0xA8A4); gfxSleepMicroseconds(5); + write_reg(g, 0x0C, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x0D, 0x080C); gfxSleepMicroseconds(5); + write_reg(g, 0x0E, 0x2B00); gfxSleepMicroseconds(5); + write_reg(g, 0x1E, 0x00B0); gfxSleepMicroseconds(5); + write_reg(g, 0x01, 0x2B3F); gfxSleepMicroseconds(5); + write_reg(g, 0x02, 0x0600); gfxSleepMicroseconds(5); + write_reg(g, 0x10, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x11, 0x6070); gfxSleepMicroseconds(5); + write_reg(g, 0x05, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x06, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x16, 0xEF1C); gfxSleepMicroseconds(5); + write_reg(g, 0x17, 0x0003); gfxSleepMicroseconds(5); + write_reg(g, 0x07, 0x0133); gfxSleepMicroseconds(5); + write_reg(g, 0x0B, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x0F, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x41, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x42, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x48, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x49, 0x013F); gfxSleepMicroseconds(5); + write_reg(g, 0x4A, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x4B, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x44, 0xEF00); gfxSleepMicroseconds(5); + write_reg(g, 0x45, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x46, 0x013F); gfxSleepMicroseconds(5); + write_reg(g, 0x30, 0x0707); gfxSleepMicroseconds(5); + write_reg(g, 0x31, 0x0204); gfxSleepMicroseconds(5); + write_reg(g, 0x32, 0x0204); gfxSleepMicroseconds(5); + write_reg(g, 0x33, 0x0502); gfxSleepMicroseconds(5); + write_reg(g, 0x34, 0x0507); gfxSleepMicroseconds(5); + write_reg(g, 0x35, 0x0204); gfxSleepMicroseconds(5); + write_reg(g, 0x36, 0x0204); gfxSleepMicroseconds(5); + write_reg(g, 0x37, 0x0502); gfxSleepMicroseconds(5); + write_reg(g, 0x3A, 0x0302); gfxSleepMicroseconds(5); + write_reg(g, 0x3B, 0x0302); gfxSleepMicroseconds(5); + write_reg(g, 0x23, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x24, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x25, 0x8000); gfxSleepMicroseconds(5); + write_reg(g, 0x4f, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x4e, 0x0000); gfxSleepMicroseconds(5); // Release the bus - release_bus(); + release_bus(g); /* Turn on the back-light */ - set_backlight(GDISP_INITIAL_BACKLIGHT); + set_backlight(g, GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ g->g.Width = GDISP_SCREEN_WIDTH; @@ -182,94 +186,94 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } #if GDISP_HARDWARE_STREAM_WRITE - LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); set_viewport(g); } - LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { - write_data(g->p.color); + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, g->p.color); } - LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { - release_bus(); + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); } - LLDSPEC void gdisp_lld_stream_pos(GDISPDriver *g) { + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { set_cursor(g); } #endif #if GDISP_HARDWARE_STREAM_READ - LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_read_start(GDisplay *g) { + acquire_bus(g); set_viewport(g); set_cursor(g); - setreadmode(); - dummy_read(); + setreadmode(g); + dummy_read(g); } - LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g) { - return read_data(); + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { + return read_data(g); } - LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g) { - setwritemode(); - release_bus(); + LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { + setwritemode(g); + release_bus(g); } #endif #if GDISP_HARDWARE_FILLS && defined(GDISP_USE_DMA) - LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { + acquire_bus(g); set_viewport(g); set_cursor(g); - dma_with_noinc(&color, g->p.cx*g->p.cy) - release_bus(); + dma_with_noinc(g, &color, g->p.cx*g->p.cy) + release_bus(g); } #endif #if GDISP_HARDWARE_BITFILLS && defined(GDISP_USE_DMA) - LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g) { + LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { pixel_t *buffer; coord_t ycnt; buffer = (pixel_t *)g->p.ptr + g->p.x1 + g->p.y1 * g->p.x2; - acquire_bus(); + acquire_bus(g); set_viewport(g); set_cursor(g); if (g->p.x2 == g->p.cx) { - dma_with_inc(buffer, g->p.cx*g->p.cy); + dma_with_inc(g, buffer, g->p.cx*g->p.cy); } else { for (ycnt = g->p.cy; ycnt; ycnt--, buffer += g->p.x2) - dma_with_inc(buffer, g->p.cy); + dma_with_inc(g, buffer, g->p.cy); } - release_bus(); + release_bus(g); } #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + LLDSPEC void gdisp_lld_control(GDisplay *g) { switch(g->p.x) { case GDISP_CONTROL_POWER: if (g->g.Powermode == (powermode_t)g->p.ptr) return; switch((powermode_t)g->p.ptr) { case powerOff: - acquire_bus(); - write_reg(0x0010, 0x0000); // leave sleep mode - write_reg(0x0007, 0x0000); // halt operation - write_reg(0x0000, 0x0000); // turn off oscillator - write_reg(0x0010, 0x0001); // enter sleep mode - release_bus(); + acquire_bus(g); + write_reg(g, 0x10, 0x0000); // leave sleep mode + write_reg(g, 0x07, 0x0000); // halt operation + write_reg(g, 0x00, 0x0000); // turn off oscillator + write_reg(g, 0x10, 0x0001); // enter sleep mode + release_bus(g); break; case powerOn: - acquire_bus(); - write_reg(0x0010, 0x0000); // leave sleep mode - release_bus(); - if (g->g.Powermode != powerSleep) - gdisp_lld_init(); + acquire_bus(g); + write_reg(g, 0x10, 0x0000); // leave sleep mode + write_reg(g, 0x00, 0x0001); // turn on oscillator + gfxSleepMicroseconds(5); + release_bus(g); break; case powerSleep: - acquire_bus(); - write_reg(0x0010, 0x0001); // enter sleep mode - release_bus(); + acquire_bus(g); + write_reg(g, 0x10, 0x0001); // enter sleep mode + release_bus(g); break; default: return; @@ -282,34 +286,34 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return; switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: - acquire_bus(); + acquire_bus(g); /* ID = 11 AM = 0 */ - write_reg(0x0011, 0x6070); - release_bus(); + write_reg(g, 0x11, 0x6070); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: - acquire_bus(); + acquire_bus(g); /* ID = 01 AM = 1 */ - write_reg(0x0011, 0x6058); - release_bus(); + write_reg(0x11, 0x6058); + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: - acquire_bus(); + acquire_bus(g); /* ID = 00 AM = 0 */ - write_reg(0x0011, 0x6040); - release_bus(); + write_reg(0x11, 0x6040); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: - acquire_bus(); + acquire_bus(g); /* ID = 10 AM = 1 */ - write_reg(0x0011, 0x6068); - release_bus(); + write_reg(g, 0x11, 0x6068); + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; @@ -322,7 +326,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; - set_backlight((unsigned)g->p.ptr); + set_backlight(g, (unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; diff --git a/drivers/gdisp/SSD1289/gdisp_lld.mk b/drivers/gdisp/SSD1289/gdisp_lld.mk index e340a7dc..564610eb 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.mk +++ b/drivers/gdisp/SSD1289/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1289/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/SSD1289 +GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1289/gdisp_lld.c diff --git a/drivers/gdisp/SSD1289/gdisp_lld_board_firebullstm32f103.h b/drivers/gdisp/SSD1289/gdisp_lld_board_firebullstm32f103.h deleted file mode 100644 index e55e7cd1..00000000 --- a/drivers/gdisp/SSD1289/gdisp_lld_board_firebullstm32f103.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD1289/gdisp_lld_board_firebullstm32f103.h - * @brief GDISP Graphic Driver subsystem board interface for the SSD1289 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -#define SET_CS palSetPad(GPIOD, 12); -#define CLR_CS palClearPad(GPIOD, 12); -#define SET_RS palSetPad(GPIOD, 13); -#define CLR_RS palClearPad(GPIOD, 13); -#define SET_WR palSetPad(GPIOD, 14); -#define CLR_WR palClearPad(GPIOD, 14); -#define SET_RD palSetPad(GPIOD, 15); -#define CLR_RD palClearPad(GPIOD, 15); - -/** - * @brief Initialise the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins - * - * @notapi - */ -static inline void init_board(void) { - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, 12, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, 13, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, 14, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, 15, PAL_MODE_OUTPUT_PUSHPULL); - - // Configure the pins to a well know state - SET_RS; - SET_RD; - SET_WR; - CLR_CS; -} - - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - (void) state; - /* Nothing to do here - reset pin tied to Vcc */ -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - (void) percent; - /* Nothing to do here - Backlight always on */ -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - palWritePort(GPIOE, index); - CLR_RS; CLR_WR; SET_WR; SET_RS; -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - palWritePort(GPIOE, data); - CLR_WR; SET_WR; -} - -/** - * @brief Set the bus in read mode - * - * @notapi - */ -static inline void setreadmode(void) { - // change pin mode to digital input - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); - CLR_RD; -} - -/** - * @brief Set the bus back into write mode - * - * @notapi - */ -static inline void setwritemode(void) { - // change pin mode back to digital output - SET_RD; - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); -} - -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - return palReadPort(GPIOE); -} -#endif - -#if defined(GDISP_USE_DMA) - #error "GDISP - SSD1289: The GPIO interface does not support DMA" -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/SSD1289/gdisp_lld_board_st_stm32f4_discovery.h b/drivers/gdisp/SSD1289/gdisp_lld_board_st_stm32f4_discovery.h deleted file mode 100644 index 7097347b..00000000 --- a/drivers/gdisp/SSD1289/gdisp_lld_board_st_stm32f4_discovery.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD1289/gdisp_lld_board_st_stm32f4_discovery.h - * @brief GDISP Graphic Driver subsystem board interface for the SSD1289 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -#define GDISP_REG ((volatile uint16_t *) 0x60000000)[0] /* RS = 0 */ -#define GDISP_RAM ((volatile uint16_t *) 0x60020000)[0] /* RS = 1 */ -#define GDISP_DMA_STREAM STM32_DMA2_STREAM6 - -const unsigned char FSMC_Bank = 0; - -/* PWM configuration structure. We use timer 3 channel 3 */ -static const PWMConfig pwmcfg = { - 100000, /* 100 kHz PWM clock frequency. */ - 100, /* PWM period is 100 cycles. */ - NULL, - { - {PWM_OUTPUT_DISABLED, NULL}, - {PWM_OUTPUT_DISABLED, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_DISABLED, NULL} - }, - 0 -}; - -/** - * @brief Initialise the board for the display. - * @notes Performs the following functions: - * 1. initialise the io port used by your display - * 2. initialise the reset pin (initial state not-in-reset) - * 3. initialise the chip select pin (initial state not-active) - * 4. initialise the backlight pin (initial state back-light off) - * - * @notapi - */ -static inline void init_board(void) { - - #if defined(STM32F1XX) || defined(STM32F3XX) - /* FSMC setup for F1/F3 */ - rccEnableAHB(RCC_AHBENR_FSMCEN, 0); - - #if defined(GDISP_USE_DMA) - #error "GDISP: SSD1289 - DMA not implemented for F1/F3 Devices" - #endif - #elif defined(STM32F4XX) || defined(STM32F2XX) - /* STM32F2-F4 FSMC init */ - rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); - - #if defined(GDISP_USE_DMA) - if (dmaStreamAllocate(GDISP_DMA_STREAM, 0, NULL, NULL)) gfxExit(); - dmaStreamSetMemory0(GDISP_DMA_STREAM, &GDISP_RAM); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - #else - #warning "GDISP: SSD1289 - DMA is supported for F2/F4 Devices. Define GDISP_USE_DMA in your gfxconf.h to turn this on for better performance." - #endif - #else - #error "GDISP: SSD1289 - FSMC not implemented for this device" - #endif - - /* set pins to FSMC mode */ - IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8) | - (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; - - IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | - (1 << 13) | (1 << 14) | (1 << 15), 0}; - - palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); - palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); - - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ; - - /* Bank1 NOR/SRAM control register configuration - * This is actually not needed as already set by default after reset */ - FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; - - /* Display backlight control */ - /* TIM3 is an alternate function 2 (AF2) */ - pwmStart(&PWMD3, &pwmcfg); - palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATE(2)); - pwmEnableChannel(&PWMD3, 2, 100); - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - (void) state; - /* Nothing to do here */ -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - pwmEnableChannel(&PWMD3, 2, percent); -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do here */ -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - /* Nothing to do here */ -} - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { GDISP_REG = index; } - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { GDISP_RAM = data; } - -/** - * @brief Set the bus in read mode - * - * @notapi - */ -static inline void setreadmode(void) { - FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_3 | FSMC_BTR1_DATAST_3 | FSMC_BTR1_BUSTURN_0; /* FSMC timing */ -} - -/** - * @brief Set the bus back into write mode - * - * @notapi - */ -static inline void setwritemode(void) { - FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0; /* FSMC timing */ -} - -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { return GDISP_RAM; } - -#if defined(GDISP_USE_DMA) || defined(__DOXYGEN__) - /** - * @brief Transfer data using DMA but don't increment the source address - */ - static inline dma_with_noinc(color_t *buffer, int area) { - dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (; area > 0; area -= 65535) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area > 65535 ? 65535 : area); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - } - - /** - * @brief Transfer data using DMA incrementing the source address - */ - static inline dma_with_inc(color_t *buffer, int area) { - dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PINC | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (; area > 0; area -= 65535) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area > 65535 ? 65535 : area); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - } -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/SSD1289/gdisp_lld_board_template.h b/drivers/gdisp/SSD1289/gdisp_lld_board_template.h deleted file mode 100644 index 8b55bed3..00000000 --- a/drivers/gdisp/SSD1289/gdisp_lld_board_template.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD1289/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board interface for the SSD1289 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief Initialise the board for the display. - * - * @notapi - */ -static inline void init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - -} - -/** - * @brief Set the bus in read mode - * - * @notapi - */ -static inline void setreadmode(void) { - -} - -/** - * @brief Set the bus back into write mode - * - * @notapi - */ -static inline void setwritemode(void) { - -} - -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} - -/** - * The below section you can replace with #error if your interface doesn't support DMA - */ -#if defined(GDISP_USE_DMA) || defined(__DOXYGEN__) - //#error "GDISP - SSD1289: This interface does not support DMA" - - /** - * @brief Transfer data using DMA but don't increment the source address - */ - static inline dma_with_noinc(color_t *buffer, int area) { - } - - /** - * @brief Transfer data using DMA incrementing the source address - */ - static inline dma_with_inc(color_t *buffer, int area) { - } -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/SSD1289/gdisp_lld_config.h b/drivers/gdisp/SSD1289/gdisp_lld_config.h index fc04a798..84e518d2 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_config.h @@ -22,9 +22,6 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "SSD1289" -#define GDISP_DRIVER_STRUCT GDISP_SSD1289 - #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE #define GDISP_HARDWARE_STREAM_POS TRUE From 8fb676f73b8f53da4464cf8780dea337c22220f6 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 17 Oct 2013 17:33:04 +1000 Subject: [PATCH 053/160] Added a post_init_board() routine to SSD1289 to allow bus timings to be changed after controller initialisation is complete. --- .../gdisp/SSD1289/board_SSD1289_firebullstm32f103.h | 4 ++++ drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h | 4 ++++ drivers/gdisp/SSD1289/board_SSD1289_template.h | 10 ++++++++++ drivers/gdisp/SSD1289/gdisp_lld.c | 3 +++ 4 files changed, 21 insertions(+) diff --git a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h index fb541df5..df7594f8 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h @@ -48,6 +48,10 @@ static inline void init_board(GDisplay *g, unsigned display) { } } +static inline void post_init_board(GDisplay *g) { + (void) g; +} + static inline void setpin_reset(GDisplay *g, bool_t state) { (void) g; (void) state; diff --git a/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h index 5a44e631..84082089 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h @@ -98,6 +98,10 @@ static inline void init_board(GDisplay *g, unsigned display) { } } +static inline void post_init_board(GDisplay *g) { + (void) g; +} + static inline void setpin_reset(GDisplay *g, bool_t state) { (void) g; (void) state; diff --git a/drivers/gdisp/SSD1289/board_SSD1289_template.h b/drivers/gdisp/SSD1289/board_SSD1289_template.h index 552c93a0..941950b3 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_template.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_template.h @@ -30,6 +30,16 @@ static inline void init_board(GDisplay *g, unsigned display) { } +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { +} + /** * @brief Set or clear the lcd reset pin. * diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 3779578d..dca11d5d 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -169,6 +169,9 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { write_reg(g, 0x4f, 0x0000); gfxSleepMicroseconds(5); write_reg(g, 0x4e, 0x0000); gfxSleepMicroseconds(5); + // Finish Init + post_init_board(g); + // Release the bus release_bus(g); From 8210418402dba694026de4c1945e824a9841fc66 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 17 Oct 2013 17:33:56 +1000 Subject: [PATCH 054/160] Driver RA8875 converted to new driver format. --- drivers/gdisp/RA8875/board_RA8875_marlin.h | 102 +++ drivers/gdisp/RA8875/board_RA8875_template.h | 140 ++++ drivers/gdisp/RA8875/gdisp_lld.c | 606 +++++++----------- drivers/gdisp/RA8875/gdisp_lld.mk | 6 +- drivers/gdisp/RA8875/gdisp_lld_board_marlin.h | 193 ------ .../gdisp/RA8875/gdisp_lld_board_template.h | 119 ---- drivers/gdisp/RA8875/gdisp_lld_config.h | 11 +- 7 files changed, 466 insertions(+), 711 deletions(-) create mode 100644 drivers/gdisp/RA8875/board_RA8875_marlin.h create mode 100644 drivers/gdisp/RA8875/board_RA8875_template.h delete mode 100644 drivers/gdisp/RA8875/gdisp_lld_board_marlin.h delete mode 100644 drivers/gdisp/RA8875/gdisp_lld_board_template.h diff --git a/drivers/gdisp/RA8875/board_RA8875_marlin.h b/drivers/gdisp/RA8875/board_RA8875_marlin.h new file mode 100644 index 00000000..0d675833 --- /dev/null +++ b/drivers/gdisp/RA8875/board_RA8875_marlin.h @@ -0,0 +1,102 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/RA8875/gdisp_lld_board_marlin.h + * @brief GDISP Graphic Driver subsystem board interface for the RA8875 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. +#define GDISP_RAM (*((volatile uint16_t *) 0x68000000)) /* RS = 0 */ +#define GDISP_REG (*((volatile uint16_t *) 0x68020000)) /* RS = 1 */ +#define FSMC_BANK 4 + + +static inline void init_board(GDisplay *g, unsigned display) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + if (display == 0) { + + /** + * Set up for Display 0 + */ + + /* set pins to FSMC mode */ + IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 8) | + (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; + + IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | + (1 << 13) | (1 << 14) | (1 << 15), 0}; + + IOBus busG = {GPIOG, (1 << 10), 0}; + + palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); + palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); + palSetBusMode(&busG, PAL_MODE_ALTERNATE(12)); + + /* FSMC timing */ + FSMC_Bank1->BTCR[FSMC_BANK+1] = (FSMC_BTR1_ADDSET_1 | FSMC_BTR1_ADDSET_3) \ + | (FSMC_BTR1_DATAST_1 | FSMC_BTR1_DATAST_3) \ + | (FSMC_BTR1_BUSTURN_1 | FSMC_BTR1_BUSTURN_3) ; + + /* Bank1 NOR/SRAM control register configuration + * This is actually not needed as already set by default after reset */ + FSMC_Bank1->BTCR[FSMC_BANK] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; + + /* FSMC delay reduced as the controller now runs at full speed */ + FSMC_Bank1->BTCR[2+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ; + FSMC_Bank1->BTCR[2] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + GDISP_REG = index; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + GDISP_RAM = data; +} + +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return GDISP_RAM; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/RA8875/board_RA8875_template.h b/drivers/gdisp/RA8875/board_RA8875_template.h new file mode 100644 index 00000000..f60067f2 --- /dev/null +++ b/drivers/gdisp/RA8875/board_RA8875_template.h @@ -0,0 +1,140 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1963/gdisp_lld_board_template.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1963 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * @param[in] display The display number on this controller (0..n) + * + * @note Set the g->priv member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g, unsigned display) { +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + +} + +/** + * @brief Set the bus in read mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setreadmode(GDisplay *g) { + +} + +/** + * @brief Set the bus back into write mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setwritemode(GDisplay *g) { + +} + +/** + * @brief Read data from the lcd. + * @return The data from the lcd + * + * @param[in] g The GDisplay structure + * + * @note The chip select may need to be asserted/de-asserted + * around the actual spi read + * + * @notapi + */ +static inline uint16_t read_data(GDisplay *g) { + +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ + diff --git a/drivers/gdisp/RA8875/gdisp_lld.c b/drivers/gdisp/RA8875/gdisp_lld.c index 397c933a..b8072f51 100644 --- a/drivers/gdisp/RA8875/gdisp_lld.c +++ b/drivers/gdisp/RA8875/gdisp_lld.c @@ -8,22 +8,98 @@ /** * @file drivers/gdisp/RA8875/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source. - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" +#define GDISP_DRIVER_VMT GDISPVMT_RA8875 +#include "../drivers/gdisp/RA8875/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" -#include "ra8875.h" +/* include the users board interface */ +#include "board_ra8875.h" -/* include the board abstraction */ -#include "gdisp_lld_board.h" +/* include our hardware definitions */ +#include "../drivers/gdisp/RA8875/ra8875.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 272 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 480 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 74 +#endif + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +// Some common routines and macros +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg8(g, reg, data) { write_index(g, reg); write_data(g, data); } +#define write_reg16(g, reg, data) { write_index(g, reg); write_data(g, data); write_index(g, reg+1); write_data(g, (data)>>8); } +#define write_reg8x2(g, reg, d1, d2) { write_index(g, reg); write_data(g, d1); write_data(g, d2); } + +static inline void set_cursor(GDisplay *g) { + write_reg16(g, 0x46, g->p.x); + write_reg16(g, 0x48, g->p.y); + write_index(g, RA8875_WRITE_MEMORY_START); +} + +static inline void set_viewport(GDisplay* g) { + write_reg16(g, 0x30, g->p.x); //HSAW0 & HSAW1 + write_reg16(g, 0x34, g->p.x+g->p.cx-1); //HEAW0 & HEAW1 + write_reg16(g, 0x32, g->p.y); //VSAW0 & VSAW1 + write_reg16(g, 0x36, g->p.y+g->p.cy-1); //VEAW0 & VEAW1 +} + +// On this controller the back-light is controlled by the controllers internal PWM +// which is why it is in this file rather than the board file. +static inline void set_backlight(GDisplay* g, uint8_t percent) { + uint8_t temp; + + //Work in progress: the RA8875 has a built-in PWM, its output can + //be used by a Dynamic Background Control or by a host (user) + + // Enable PWM1 + write_index(g, 0x8a); //MCLR + setreadmode(g); + temp = read_data(g); + setwritemode(g); + temp |= 1<<7 ; + write_data(g, temp); + + // PWM1 function select + write_index(g, 0x8a); //MCLR + setreadmode(g); + temp = read_data(g); + setwritemode(g); + temp &= ~(1<<4); + write_data(g, temp); + + // PWM1 Clock ratio + write_index(g, 0x8a); //MCLR + setreadmode(g); + temp = read_data(g); + setwritemode(g); + temp &= 0xf0; + temp |= 0x0b & 0x0f; + write_data(g, temp); + + // PWM1 Write duty cycle + write_reg8(g, 0x8b, 54+percent); // PTNO: Also change percent to range from 0x00 to 0xFF +} /*===========================================================================*/ /* Driver interrupt handlers. */ @@ -33,417 +109,175 @@ /* Driver exported functions. */ /*===========================================================================*/ +LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { + /* Initialise your display */ + init_board(g, display); -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(20); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(20); -/** - * @brief Low level GDISP driver initialisation. - * @return TRUE if successful, FALSE on error. - * - * @notapi - */ -bool_t gdisp_lld_init(void) { - /* Initialise the display */ - init_board(); + // Get the bus for the following initialisation commands + acquire_bus(g); - /* soft reset */ - write_index(0x01); - write_data(0x01); - write_data(0x00); - gfxSleepMilliseconds(1); + // Soft reset + write_reg8x2(g, 0x01, 0x01, 0x00); gfxSleepMilliseconds(1); - /* Driver PLL config 480x272*/ - write_index(0x88); - write_data(0x08); - gfxSleepMilliseconds(1); - write_index(0x89); - write_data(0x02); - gfxSleepMilliseconds(1); + // PLL config + write_reg8(g, 0x88, 0x08); gfxSleepMilliseconds(1); + write_reg8(g, 0x89, 0x02); gfxSleepMilliseconds(1); - write_index(0x10); //SYSR bit[4:3]=00 256 color bit[2:1]= 00 8bit MPU interface - write_data(0x0F); // if 16bit MCU interface and 65k color display + write_reg8(g, 0x10, 0x0F); //SYSR bit[4:3]=00 256 color bit[2:1]= 00 8bit MPU interface + // 0x0F = 16bit MCU interface and 65k color display - write_index(0x04); //set PCLK invers - write_data(0x82); - gfxSleepMilliseconds(1); + write_reg8(g, 0x04, 0x82); gfxSleepMilliseconds(1); //set PCLK inverse - //Horizontal set - write_index(0x14); //HDWR//Horizontal Display Width Setting Bit[6:0] - write_data(0x3B);//Horizontal display width(pixels) = (HDWR + 1)*8 - write_index(0x15); //Horizontal Non-Display Period Fine Tuning Option Register (HNDFTR) - write_data(0x00);//Horizontal Non-Display Period Fine Tuning(HNDFT) [3:0] - write_index(0x16); //HNDR//Horizontal Non-Display Period Bit[4:0] - write_data(0x01);//Horizontal Non-Display Period (pixels) = (HNDR + 1)*8 - write_index(0x17); //HSTR//HSYNC Start Position[4:0] - write_data(0x00);//HSYNC Start Position(PCLK) = (HSTR + 1)*8 - write_index(0x18); //HPWR//HSYNC Polarity ,The period width of HSYNC. - write_data(0x05);//HSYNC Width [4:0] HSYNC Pulse width(PCLK) = (HPWR + 1)*8 + // Horizontal set + write_reg8(g, 0x14, GDISP_SCREEN_WIDTH/8-1); //HDWR: Horizontal Display Width Setting Bit[6:0] - pixels = (HDWR + 1)*8 + write_reg8(g, 0x15, 0x00); //Horizontal Non-Display Period Fine Tuning Option Register (HNDFTR) - HNDFT = [3:0] + write_reg8(g, 0x16, 0x01); //HNDR: Horizontal Non-Display Period Bit[4:0] - pixels = (HNDR + 1)*8 + write_reg8(g, 0x17, 0x00); //HSTR: HSYNC Start Position[4:0] - Position(PCLK) = (HSTR + 1)*8 + write_reg8(g, 0x18, 0x05); //HPWR: HSYNC Polarity, The period width of HSYNC. Width [4:0] width(PCLK) = (HPWR + 1)*8 - //Vertical set - write_index(0x19); //VDHR0 //Vertical Display Height Bit [7:0] - write_data(0x0f); //Vertical pixels = VDHR + 1 - write_index(0x1a); //VDHR1 //Vertical Display Height Bit [8] - write_data(0x01); //Vertical pixels = VDHR + 1 - write_index(0x1b); //VNDR0 //Vertical Non-Display Period Bit [7:0] - write_data(0x02); //VSYNC Start Position(PCLK) = (VSTR + 1) - write_index(0x1c); //VNDR1 //Vertical Non-Display Period Bit [8] - write_data(0x00); //Vertical Non-Display area = (VNDR + 1) - write_index(0x1d); //VSTR0 //VSYNC Start Position[7:0] - write_data(0x07);//VSYNC Start Position(PCLK) = (VSTR + 1) - write_index(0x1e); //VSTR1 //VSYNC Start Position[8] - write_data(0x00);//VSYNC Start Position(PCLK) = (VSTR + 1) - write_index(0x1f); //VPWR //VSYNC Polarity ,VSYNC Pulse Width[6:0] - write_data(0x09); //VSYNC Pulse Width(PCLK) = (VPWR + 1) + // Vertical set + write_reg16(g, 0x19, GDISP_SCREEN_HEIGHT-1); //VDHR0,1: Vertical Display Height = VDHR + 1 + write_reg16(g, 0x1b, 0x0002); //VNDR0,1: Vertical Non-Display Period Bit = (VSTR + 1) + write_reg16(g, 0x1d, 0x0007); //VSTR0,1: VSYNC Start Position = (VSTR + 1) + write_reg8(g, 0x1f, 0x09); //VPWR: VSYNC Polarity, VSYNC Pulse Width[6:0] - Width(PCLK) = (VPWR + 1) - //Active window set - //setting active window X - write_index(0x30); //Horizontal Start Point 0 of Active Window (HSAW0) - write_data(0x00); //Horizontal Start Point of Active Window [7:0] - write_index(0x31); //Horizontal Start Point 1 of Active Window (HSAW1) - write_data(0x00); //Horizontal Start Point of Active Window [9:8] - write_index(0x34); //Horizontal End Point 0 of Active Window (HEAW0) - write_data(0xDF); //Horizontal End Point of Active Window [7:0] - write_index(0x35); //Horizontal End Point 1 of Active Window (HEAW1) - write_data(0x01); //Horizontal End Point of Active Window [9:8] - - //setting active window Y - write_index(0x32); //Vertical Start Point 0 of Active Window (VSAW0) - write_data(0x00); //Vertical Start Point of Active Window [7:0] - write_index(0x33); //Vertical Start Point 1 of Active Window (VSAW1) - write_data(0x00); //Vertical Start Point of Active Window [8] - write_index(0x36); //Vertical End Point of Active Window 0 (VEAW0) - write_data(0x0F); //Vertical End Point of Active Window [7:0] - write_index(0x37); //Vertical End Point of Active Window 1 (VEAW1) - write_data(0x01); //Vertical End Point of Active Window [8] + // Active window set + write_reg16(g, 0x30, 0); //HSAW0 & HSAW1 + write_reg16(g, 0x34, GDISP_SCREEN_WIDTH-1); //HEAW0 & HEAW1 + write_reg16(g, 0x32, 0); //VSAW0 & VSAW1 + write_reg16(g, 0x36, GDISP_SCREEN_HEIGHT-1); //VEAW0 & VEAW1 // Display ON - write_index(0x01); //PWRR - write_data(0x80); + write_reg8(g, 0x01, 0x80); //PWRR // GPO0 DISP high - write_index(0x13); //GPO - write_data(0x01); + write_reg8(g, 0x13, 0x01); //GPO - set_backlight(0x80); //set to 90% brightness + // Set initial back-light + set_backlight(g, GDISP_INITIAL_BACKLIGHT); - post_init_board(); + // Change timings for faster access + post_init_board(g); - /* Initialise the GDISP structure to match */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = 100; - GDISP.Contrast = 50; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + // Release the bus + release_bus(g); + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -void gdisp_lld_setwindow(coord_t x0, coord_t y0, coord_t x1, coord_t y1) { - /* We don't need to validate here as the LLD routines will validate first. - * - * #if GDISP_NEED_VALIDATION - * if (x0 >= GDISP.Width || y0 >= GDISP.Height || x0 < 0 || y0 < 0) return; - * else if (x1 >= GDISP.Width || y1 >= GDISP.Height || y1 < 0 || y2 < 0) return; - * #endif - */ - - //setting active window X - write_index(0x30); //HSAW0 - write_data(x0); - write_index(0x31); //HSAW1 - write_data(x0>>8); - - write_index(0x34); //HEAW0 - write_data(x1); - write_index(0x35); //HEAW1 - write_data(x1>>8); - - //setting active window Y - write_index(0x32); //VSAW0 - write_data(y0); - write_index(0x33); //VSAW1 - write_data(y0>>8); - - write_index(0x36); //VEAW0 - write_data(y1); - write_index(0x37); //VEAW1 - write_data(y1>>8); - - write_index(0x46); - write_data(x0); - write_index(0x47); - write_data(x0>>8); - - write_index(0x48); - write_data(y0); - write_index(0x49); - write_data(y0>>8); -} - -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - gdisp_lld_setwindow(x, y, x, y); - write_index(RA8875_WRITE_MEMORY_START); - write_data(color); -} - -/* ---- Optional Routines ---- */ - -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - uint32_t area; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - area = cx*cy; - - gdisp_lld_setwindow(x, y, x+cx-1, y+cy-1); - write_index(RA8875_WRITE_MEMORY_START); - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, &color); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area/65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - uint32_t index; - for(index = 0; index < area; index++) - write_data(color); - #endif //#ifdef GDISP_USE_DMA -} -#endif - -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a bitmap. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - gdisp_lld_setwindow(x, y, x+cx-1, y+cy-1); - write_index(RA8875_WRITE_MEMORY_START); - - buffer += srcx + srcy * srccx; - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint32_t area = cx*cy; - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PINC | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area/65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - coord_t endx, endy; - uint32_t lg; - endx = srcx + cx; - endy = y + cy; - lg = srccx - cx; - for(; y < endy; y++, buffer += lg) - for(x=srcx; x < endx; x++) - write_data(*buffer++); - #endif //#ifdef GDISP_USE_DMA +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + } + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, g->p.color); + } + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); + } + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { + set_cursor(g); } #endif -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @note Optional. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - /* NOT IMPLEMENTED YET */ - - /* - uint16_t size = x1 - x0 ; - - write_index(SSD1963_SET_SCROLL_AREA); - write_data((x0 >> 8) & 0xFF); - write_data((x0 >> 0) & 0xFF); - write_data((size >> 8) & 0xFF); - write_data((size >> 0) & 0xFF); - write_data(((lcd_height-x1) >> 8) & 0xFF); - write_data(((lcd_height-x1) >> 0) & 0xFF); - - write_index(SSD1963_SET_SCROLL_START); - write_data((lines >> 8) & 0xFF); - write_data((lines >> 0) & 0xFF); - */ - } - -#endif - -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. - * GDISP_CONTROL_LLD - Low level driver control constants start at - * this value. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { - /* NOT IMPLEMENTED YET */ - switch(what) { +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + #if 0 case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + acquire_bus(g); + // TODO + release_bus(g); + break; + case powerOn: + acquire_bus(g); + // TODO + release_bus(g); + break; + case powerSleep: + acquire_bus(g); + // TODO + release_bus(g); + break; + default: return; - switch((gdisp_powermode_t)value) { - case powerOff: - /* ToDo */ - break; - case powerOn: - /* ToDo */ - break; - case powerSleep: - /* ToDo */ - break; - default: - return; } - GDISP.Powermode = (gdisp_powermode_t)value; + g->g.Powermode = (powermode_t)g->p.ptr; return; + #endif + + #if 0 case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(g); + // TODO + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + acquire_bus(g); + // TODO + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + acquire_bus(g); + // TODO + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + acquire_bus(g); + // TODO + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: return; - switch((gdisp_orientation_t)value) { - case GDISP_ROTATE_0: - /* Code here */ - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_90: - /* Code here */ - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - case GDISP_ROTATE_180: - /* Code here */ - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_270: - /* Code here */ - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - default: - return; } - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; + g->g.Orientation = (orientation_t)value; return; - case GDISP_CONTROL_BACKLIGHT: - set_backlight((uint8_t )value); - //gdisp_lld_bg_dimmer(54 + ((uint8_t)value) << 1);//turn 0..100% in 54..255 - return; -/* - case GDISP_CONTROL_CONTRAST: -*/ + #endif + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + acquire_bus(g); + set_backlight(g, (unsigned)g->p.ptr); + release_bus(g); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + //case GDISP_CONTROL_CONTRAST: + default: + return; } } #endif #endif /* GFX_USE_GDISP */ -/** @} */ - diff --git a/drivers/gdisp/RA8875/gdisp_lld.mk b/drivers/gdisp/RA8875/gdisp_lld.mk index 471b7e83..7ac03624 100644 --- a/drivers/gdisp/RA8875/gdisp_lld.mk +++ b/drivers/gdisp/RA8875/gdisp_lld.mk @@ -1,6 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/RA8875/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/RA8875 - +GFXSRC += $(GFXLIB)/drivers/gdisp/RA8875/gdisp_lld.c diff --git a/drivers/gdisp/RA8875/gdisp_lld_board_marlin.h b/drivers/gdisp/RA8875/gdisp_lld_board_marlin.h deleted file mode 100644 index 072ba32e..00000000 --- a/drivers/gdisp/RA8875/gdisp_lld_board_marlin.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/RA8875/gdisp_lld_board_marlin.h - * @brief GDISP Graphic Driver subsystem board interface for the RA8875 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/* Using FSMC A16 as RS */ -#define GDISP_RAM (*((volatile uint16_t *) 0x68000000)) /* RS = 0 */ -#define GDISP_REG (*((volatile uint16_t *) 0x68020000)) /* RS = 1 */ - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - GDISP_REG = index; -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - GDISP_RAM = data; -} - -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - return GDISP_RAM; -} - -/** - * @brief Initialise the board for the display. - * @notes Performs the following functions: - * 1. initialise the io port used by your display - * 2. initialise the reset pin (initial state not-in-reset) - * 3. initialise the chip select pin (initial state not-active) - * 4. initialise the backlight pin (initial state back-light off) - * - * @notapi - */ -static inline void init_board(void) { - const unsigned char FSMC_Bank = 4; - - #if defined(STM32F1XX) || defined(STM32F3XX) - /* FSMC setup for F1/F3 */ - rccEnableAHB(RCC_AHBENR_FSMCEN, 0); - - #if defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - #error "DMA not implemented for F1/F3 Devices" - #endif - #elif defined(STM32F4XX) || defined(STM32F2XX) - /* STM32F2-F4 FSMC init */ - rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); - - #if defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - if (dmaStreamAllocate(GDISP_DMA_STREAM, 0, NULL, NULL)) chSysHalt(); - dmaStreamSetMemory0(GDISP_DMA_STREAM, &GDISP_RAM); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - #endif - #else - #error "FSMC not implemented for this device" - #endif - - /* set pins to FSMC mode */ - IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 8) | - (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; - - IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | - (1 << 13) | (1 << 14) | (1 << 15), 0}; - - IOBus busG = {GPIOG, (1 << 10), 0}; - - palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); - palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); - palSetBusMode(&busG, PAL_MODE_ALTERNATE(12)); - - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = (FSMC_BTR1_ADDSET_1 | FSMC_BTR1_ADDSET_3) \ - | (FSMC_BTR1_DATAST_1 | FSMC_BTR1_DATAST_3) \ - | (FSMC_BTR1_BUSTURN_1 | FSMC_BTR1_BUSTURN_3) ; - - /* Bank1 NOR/SRAM control register configuration - * This is actually not needed as already set by default after reset */ - FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; -} - -static inline void post_init_board(void) { - const unsigned char FSMC_Bank = 2; - /* FSMC delay reduced as the controller now runs at full speed */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ; - FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - (void) state; - /* Nothing to do here */ -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - - //duty_cycle is 00..FF - //Work in progress: the RA8875 has a built-in PWM, its output can - //be used by a Dynamic Background Control or by a host (user) - - uint8_t temp, temp1; - // Enable PWM1 - write_index(0x8a);//MCLR - temp = read_data(); - temp |= 1<<7 ; - write_data(temp); - - // PWM1 function select - write_index(0x8a);//MCLR - temp = read_data(); - temp &= ~(1<<4); - write_data(temp); - - // PWM1 Clock ratio - temp1= 0x0b&0x0f; - write_index(0x8a);//MCLR - temp = read_data(); - temp &= 0xf0; - temp |= temp1 ; - write_data(temp); - - // Write duty cycle - write_index(0x8b);//PTNO - write_data(percent); - // PWM1 duty cycle -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do here */ -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - /* Nothing to do here */ -} - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/RA8875/gdisp_lld_board_template.h b/drivers/gdisp/RA8875/gdisp_lld_board_template.h deleted file mode 100644 index a11c11ab..00000000 --- a/drivers/gdisp/RA8875/gdisp_lld_board_template.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD1963/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board interface for the SSD1963 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - -} - -/** - * @brief Initialise the board for the display. - * - * @notapi - */ -static inline void init_board(void) { - -} - -static inline void post_init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - -} - -__inline void write_stream(uint16_t *buffer, uint16_t size) { - -} - -__inline void read_stream(uint16_t *buffer, size_t size) { - -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/RA8875/gdisp_lld_config.h b/drivers/gdisp/RA8875/gdisp_lld_config.h index f49c3e03..ae290245 100644 --- a/drivers/gdisp/RA8875/gdisp_lld_config.h +++ b/drivers/gdisp/RA8875/gdisp_lld_config.h @@ -22,14 +22,9 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "RA8875" - -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILL TRUE -#define GDISP_HARDWARE_READPIXEL TRUE - -/* Maybe someday soon */ -#define GDISP_HARDWARE_SCROLL FALSE +#define GDISP_HARDWARE_STREAM_WRITE TRUE +#define GDISP_HARDWARE_STREAM_READ TRUE +#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 From 3cacf9cee22806c6b7c814fdff9ae93dcac1c884 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 17 Oct 2013 17:38:44 +1000 Subject: [PATCH 055/160] Remove unnecessary file from RA8875 driver. --- drivers/gdisp/RA8875/gdisp_lld.c | 5 +---- drivers/gdisp/RA8875/ra8875.h | 18 ------------------ 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 drivers/gdisp/RA8875/ra8875.h diff --git a/drivers/gdisp/RA8875/gdisp_lld.c b/drivers/gdisp/RA8875/gdisp_lld.c index b8072f51..4c146321 100644 --- a/drivers/gdisp/RA8875/gdisp_lld.c +++ b/drivers/gdisp/RA8875/gdisp_lld.c @@ -21,9 +21,6 @@ /* include the users board interface */ #include "board_ra8875.h" -/* include our hardware definitions */ -#include "../drivers/gdisp/RA8875/ra8875.h" - /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ @@ -54,7 +51,7 @@ static inline void set_cursor(GDisplay *g) { write_reg16(g, 0x46, g->p.x); write_reg16(g, 0x48, g->p.y); - write_index(g, RA8875_WRITE_MEMORY_START); + write_index(g, 0x02); } static inline void set_viewport(GDisplay* g) { diff --git a/drivers/gdisp/RA8875/ra8875.h b/drivers/gdisp/RA8875/ra8875.h deleted file mode 100644 index 43210b66..00000000 --- a/drivers/gdisp/RA8875/ra8875.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef RA8875_H -#define RA8875_H - -#define mHIGH(x) (x >> 8) -#define mLOW(x) (x & 0xFF) - -#define RA8875_WRITE_MEMORY_START 0x0002 -#define RA8875_READ_MEMORY_START 0x0002 - -#endif - From 257f7364f8722af721e8b4ee10d75839486e8ae1 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 15:56:30 +1000 Subject: [PATCH 056/160] Update some doxygen documentation --- drivers/gdisp/RA8875/board_RA8875_marlin.h | 2 +- drivers/gdisp/RA8875/board_RA8875_template.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gdisp/RA8875/board_RA8875_marlin.h b/drivers/gdisp/RA8875/board_RA8875_marlin.h index 0d675833..95fb7f9d 100644 --- a/drivers/gdisp/RA8875/board_RA8875_marlin.h +++ b/drivers/gdisp/RA8875/board_RA8875_marlin.h @@ -6,7 +6,7 @@ */ /** - * @file drivers/gdisp/RA8875/gdisp_lld_board_marlin.h + * @file drivers/gdisp/RA8875/board_RA8875_marlin.h * @brief GDISP Graphic Driver subsystem board interface for the RA8875 display. */ diff --git a/drivers/gdisp/RA8875/board_RA8875_template.h b/drivers/gdisp/RA8875/board_RA8875_template.h index f60067f2..564f60c0 100644 --- a/drivers/gdisp/RA8875/board_RA8875_template.h +++ b/drivers/gdisp/RA8875/board_RA8875_template.h @@ -6,8 +6,8 @@ */ /** - * @file drivers/gdisp/SSD1963/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board interface for the SSD1963 display. + * @file drivers/gdisp/SSD1963/board_RA8875_template.h + * @brief GDISP Graphic Driver subsystem board interface for the RA8875 display. * * @addtogroup GDISP * @{ From c4ae7fd6c830bca85ac7c1c6da6e806dec4accdb Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 15:57:13 +1000 Subject: [PATCH 057/160] Convert HX8437D driver to new format --- .../HX8347D/board_HX8347D_stm32f4discovery.h | 163 ++++++++++++++ .../gdisp/HX8347D/board_HX8347D_template.h | 150 +++++++++++++ drivers/gdisp/HX8347D/gdisp_lld.c | 199 +++++++++--------- drivers/gdisp/HX8347D/gdisp_lld.mk | 5 +- .../gdisp_lld_board_st_stm32f4_discovery.h | 197 ----------------- .../gdisp/HX8347D/gdisp_lld_board_template.h | 109 ---------- drivers/gdisp/HX8347D/gdisp_lld_config.h | 3 - 7 files changed, 415 insertions(+), 411 deletions(-) create mode 100644 drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h create mode 100644 drivers/gdisp/HX8347D/board_HX8347D_template.h delete mode 100644 drivers/gdisp/HX8347D/gdisp_lld_board_st_stm32f4_discovery.h delete mode 100644 drivers/gdisp/HX8347D/gdisp_lld_board_template.h diff --git a/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h new file mode 100644 index 00000000..0fe5ded3 --- /dev/null +++ b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h @@ -0,0 +1,163 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h + * @brief GDISP Graphic Driver subsystem board SPI interface for the HX8347D display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. + +/* Pin assignments */ +#define SET_RST palSetPad(GPIOB, 8) +#define CLR_RST palClearPad(GPIOB, 8) +#define SET_DATA palSetPad(GPIOB, 9) +#define CLR_DATA palClearPad(GPIOB, 9) +#define SET_CS palSetPad(GPIOA, 4) +#define CLR_CS palClearPad(GPIOA, 4) + +/* PWM configuration structure. We use timer 4 channel 2 (orange LED on board). */ +static const PWMConfig pwmcfg = { + 1000000, /* 1 MHz PWM clock frequency. */ + 100, /* PWM period is 100 cycles. */ + NULL, + { + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL} + }, + 0 +}; + +/* + * SPI1 configuration structure. + * Speed 42MHz, CPHA=0, CPOL=0, 8bits frames, MSb transmitted first. + * The slave select line is the pin 4 on the port GPIOA. + */ +static const SPIConfig spi1cfg_8bit = { + NULL, + /* HW dependent part.*/ + GPIOA, + 4, + 0 //SPI_CR1_BR_0 +}; + +/* + * SPI1 configuration structure. + * Speed 42MHz, CPHA=0, CPOL=0, 16bits frames, MSb transmitted first. + * The slave select line is the pin 4 on the port GPIOA. + */ +static const SPIConfig spi1cfg_16bit = { + NULL, + /* HW dependent part.*/ + GPIOA, + 4, + SPI_CR1_DFF //SPI_CR1_BR_0 +}; + +static inline void init_board(GDisplay *g, unsigned display) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + if (display == 0) { + + /** + * Set up for Display 0 + */ + + /* Display backlight control */ + /* TIM4 is an alternate function 2 (AF2) */ + pwmStart(&PWMD4, &pwmcfg); + palSetPadMode(GPIOD, 13, PAL_MODE_ALTERNATE(2)); + pwmEnableChannel(&PWMD4, 1, 100); + + palSetPadMode(GPIOB, 8, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST); /* RST */ + palSetPadMode(GPIOB, 9, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST); /* RS */ + /* + * Initializes the SPI driver 1. The SPI1 signals are routed as follow: + * PB12 - NSS. + * PB13 - SCK. + * PB14 - MISO. + * PB15 - MOSI. + */ + SET_CS; SET_DATA; + spiStart(&SPID1, &spi1cfg_8bit); + palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST); /* NSS. */ + palSetPadMode(GPIOA, 5, PAL_MODE_ALTERNATE(5)|PAL_STM32_OSPEED_HIGHEST); /* SCK. */ + palSetPadMode(GPIOA, 6, PAL_MODE_ALTERNATE(5)); /* MISO. */ + palSetPadMode(GPIOA, 7, PAL_MODE_ALTERNATE(5)|PAL_STM32_OSPEED_HIGHEST); /* MOSI. */ + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if (state) { + CLR_RST; + } else { + SET_RST; + } +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + pwmEnableChannel(&PWMD4, 1, percent); +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; + spiAcquireBus(&SPID1); + while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); // Safety + CLR_CS; +} + +static inline void release_bus(GDisplay *g) { + (void) g; + SET_CS; + spiReleaseBus(&SPID1); +} + +static inline void busmode16(GDisplay *g) { + (void) g; + spiStart(&SPID1, &spi1cfg_16bit); +} + +static inline void busmode8(GDisplay *g) { + (void) g; + spiStart(&SPID1, &spi1cfg_8bit); +} + +static inline void write_index(GDisplay *g, uint8_t index) { + (void) g; + CLR_DATA; + SPI1->DR = cmd; + while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); + SET_DATA; +} + +static inline void write_data(GDisplay *g, uint8_t data) { + (void) g; + SPI1->DR = data; + while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); +} + +static inline void write_ram16(GDisplay *g, uint16_t data) { + (void) g; + SPI1->DR = data; + while((SPI1->SR & SPI_SR_TXE) == 0); +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/HX8347D/board_HX8347D_template.h b/drivers/gdisp/HX8347D/board_HX8347D_template.h new file mode 100644 index 00000000..6084d1bf --- /dev/null +++ b/drivers/gdisp/HX8347D/board_HX8347D_template.h @@ -0,0 +1,150 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/HX8347D/board_HX8347D_template.h + * @brief GDISP Graphic Driver subsystem board SPI interface for the HX8347D display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * @param[in] display The display number on this controller (0..n) + * + * @note Set the g->priv member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g, unsigned display) { +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + +} + +/** + * @brief Set the lcd back-light level. + * + * @param[in] g The GDisplay structure + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + +} + +/** + * @brief Set the bus in 16 bit mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void busmode16(GDisplay *g) { + +} + +/** + * @brief Set the bus in 8 bit mode (the default) + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void busmode8(GDisplay *g) { + +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint8_t index) { + +} + +/** + * @brief Send 8 bits of data to the lcd. + * @pre The bus is in 8 bit mode + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint8_t data) { + +} + +/** + * @brief Send 16 bits of data to the lcd. + * @pre The bus is in 16 bit mode + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_ram16(GDisplay *g, uint16_t data) { + +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/HX8347D/gdisp_lld.c b/drivers/gdisp/HX8347D/gdisp_lld.c index a1e2c15b..19d1b822 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld.c +++ b/drivers/gdisp/HX8347D/gdisp_lld.c @@ -8,18 +8,17 @@ /** * @file drivers/gdisp/HX8347D/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for the HX8347D display. - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP -#define GDISP_LLD_DECLARATIONS +#define GDISP_DRIVER_VMT GDISPVMT_HX8347D +#include "../drivers/gdisp/HX8347D/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" -#include "gdisp_lld_board.h" + +#include "board_HX8347D.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -42,106 +41,111 @@ /* Driver local functions. */ /*===========================================================================*/ -#include "HX8347D.h" +#include "../drivers/gdisp/HX8347D/HX8347D.h" -static inline void set_viewport(GDISPDriver* g) { - write_reg(HX8347D_REG_SCL, (uint8_t) g->p.x); - write_reg(HX8347D_REG_SCH, (uint8_t) (g->p.x >> 8)); - write_reg(HX8347D_REG_ECL, (uint8_t) (g->p.x + g->p.cx -1)); - write_reg(HX8347D_REG_ECH, (uint8_t) ((g->p.x + g->p.cx -1) >> 8)); - write_reg(HX8347D_REG_SPL, (uint8_t) g->p.y); - write_reg(HX8347D_REG_SPH, (uint8_t) (g->p.y >> 8)); - write_reg(HX8347D_REG_EPL, (uint8_t) (g->p.y + g->p.cy -1)); - write_reg(HX8347D_REG_EPH, (uint8_t) ((g->p.y + g->p.cy -1) >> 8)); - write_index(HX8347D_REG_SRAMWC); +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } + +static inline void set_viewport(GDisplay* g) { + write_reg(g, HX8347D_REG_SCL, g->p.x); + write_reg(g, HX8347D_REG_SCH, g->p.x >> 8); + write_reg(g, HX8347D_REG_ECL, g->p.x + g->p.cx -1); + write_reg(g, HX8347D_REG_ECH, (g->p.x + g->p.cx -1) >> 8); + write_reg(g, HX8347D_REG_SPL, g->p.y); + write_reg(g, HX8347D_REG_SPH, g->p.y >> 8); + write_reg(g, HX8347D_REG_EPL, g->p.y + g->p.cy -1); + write_reg(g, HX8347D_REG_EPH, (g->p.y + g->p.cy -1) >> 8); + write_index(g, HX8347D_REG_SRAMWC); } /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { /* Initialise your display */ - init_board(); + init_board(g, display); // Hardware reset - setpin_reset(TRUE); + setpin_reset(g, TRUE); gfxSleepMilliseconds(1); - setpin_reset(FALSE); + setpin_reset(g, FALSE); gfxSleepMilliseconds(5); // Get the bus for the following initialisation commands - acquire_bus(); + acquire_bus(g); /* Start Initial Sequence ----------------------------------------------------*/ - write_reg(HX8347D_REG_STBAH, 0x00); /* Reset Power Control 1 */ - write_reg(HX8347D_REG_STBAL, 0x20); /* Power Control 2 */ - write_reg(HX8347D_REG_PTBAH, 0x0C); /* Power Control 1 */ - write_reg(HX8347D_REG_PTBAL, 0xC4); /* Power Control 2 */ - write_reg(HX8347D_REG_OPONN, 0x40); /* Source OPON_N */ - write_reg(HX8347D_REG_OPONI, 0x38); /* Source OPON_I */ - write_reg(HX8347D_REG_DC2, 0xA3); /* Display Control 2 */ + write_reg(g, HX8347D_REG_STBAH, 0x00); /* Reset Power Control 1 */ + write_reg(g, HX8347D_REG_STBAL, 0x20); /* Power Control 2 */ + write_reg(g, HX8347D_REG_PTBAH, 0x0C); /* Power Control 1 */ + write_reg(g, HX8347D_REG_PTBAL, 0xC4); /* Power Control 2 */ + write_reg(g, HX8347D_REG_OPONN, 0x40); /* Source OPON_N */ + write_reg(g, HX8347D_REG_OPONI, 0x38); /* Source OPON_I */ + write_reg(g, HX8347D_REG_DC2, 0xA3); /* Display Control 2 */ /* Power On sequence ---------------------------------------------------------*/ - write_reg(HX8347D_REG_PWC2, 0x1B); /* Power Control 2 */ - write_reg(HX8347D_REG_PWC1, 0x01); /* Power Control 1 */ - write_reg(HX8347D_REG_VMH, 0x2F); /* Vcom Control 2 */ - write_reg(HX8347D_REG_VML, 0x57); /* Vcom Control 3 */ - write_reg(HX8347D_REG_VMF, 0x8D); /* Vcom Control 1 */ + write_reg(g, HX8347D_REG_PWC2, 0x1B); /* Power Control 2 */ + write_reg(g, HX8347D_REG_PWC1, 0x01); /* Power Control 1 */ + write_reg(g, HX8347D_REG_VMH, 0x2F); /* Vcom Control 2 */ + write_reg(g, HX8347D_REG_VML, 0x57); /* Vcom Control 3 */ + write_reg(g, HX8347D_REG_VMF, 0x8D); /* Vcom Control 1 */ /* Gamma settings -----------------------------------------------------------*/ - write_reg(HX8347D_REG_VRP0,0x01); // default setup - write_reg(HX8347D_REG_VRP1,0x0e); // - write_reg(HX8347D_REG_VRP2,0x11); // - write_reg(HX8347D_REG_VRP3,0x1a); // - write_reg(HX8347D_REG_VRP4,0x18); // - write_reg(HX8347D_REG_VRP5,0x24); // - write_reg(HX8347D_REG_PRP0,0x15); // - write_reg(HX8347D_REG_PRP1,0x65); // - write_reg(HX8347D_REG_PKP0,0x0b); // - write_reg(HX8347D_REG_PKP1,0x18); // - write_reg(HX8347D_REG_PKP2,0x19); // - write_reg(HX8347D_REG_PKP3,0x1a); // - write_reg(HX8347D_REG_PKP4,0x18); // - write_reg(HX8347D_REG_VRN0,0x1b); // - write_reg(HX8347D_REG_VRN1,0x27); // - write_reg(HX8347D_REG_VRN2,0x25); // - write_reg(HX8347D_REG_VRN3,0x2e); // - write_reg(HX8347D_REG_VRN4,0x31); // - write_reg(HX8347D_REG_VRN5,0x3e); // - write_reg(HX8347D_REG_PRN0,0x1a); // - write_reg(HX8347D_REG_PRN1,0x6a); // - write_reg(HX8347D_REG_PKN0,0x07); // - write_reg(HX8347D_REG_PKN1,0x05); // - write_reg(HX8347D_REG_PKN2,0x06); // - write_reg(HX8347D_REG_PKN3,0x0b); // - write_reg(HX8347D_REG_PKN4,0x14); // - write_reg(HX8347D_REG_CGM,0xcc); // + write_reg(g, HX8347D_REG_VRP0, 0x01); // default setup + write_reg(g, HX8347D_REG_VRP1, 0x0e); // + write_reg(g, HX8347D_REG_VRP2, 0x11); // + write_reg(g, HX8347D_REG_VRP3, 0x1a); // + write_reg(g, HX8347D_REG_VRP4, 0x18); // + write_reg(g, HX8347D_REG_VRP5, 0x24); // + write_reg(g, HX8347D_REG_PRP0, 0x15); // + write_reg(g, HX8347D_REG_PRP1, 0x65); // + write_reg(g, HX8347D_REG_PKP0, 0x0b); // + write_reg(g, HX8347D_REG_PKP1, 0x18); // + write_reg(g, HX8347D_REG_PKP2, 0x19); // + write_reg(g, HX8347D_REG_PKP3, 0x1a); // + write_reg(g, HX8347D_REG_PKP4, 0x18); // + write_reg(g, HX8347D_REG_VRN0, 0x1b); // + write_reg(g, HX8347D_REG_VRN1, 0x27); // + write_reg(g, HX8347D_REG_VRN2, 0x25); // + write_reg(g, HX8347D_REG_VRN3, 0x2e); // + write_reg(g, HX8347D_REG_VRN4, 0x31); // + write_reg(g, HX8347D_REG_VRN5, 0x3e); // + write_reg(g, HX8347D_REG_PRN0, 0x1a); // + write_reg(g, HX8347D_REG_PRN1, 0x6a); // + write_reg(g, HX8347D_REG_PKN0, 0x07); // + write_reg(g, HX8347D_REG_PKN1, 0x05); // + write_reg(g, HX8347D_REG_PKN2, 0x06); // + write_reg(g, HX8347D_REG_PKN3, 0x0b); // + write_reg(g, HX8347D_REG_PKN4, 0x14); // + write_reg(g, HX8347D_REG_CGM, 0xcc); // /* Power + Osc ---------------------------------------------------------------*/ - write_reg(HX8347D_REG_OSCCH, 0x36); /* OSC Control 1 */ - write_reg(HX8347D_REG_OSCCL, 0x01); /* OSC Control 2 */ - write_reg(HX8347D_REG_DMODE, 0x00); /* Display Mode Control */ - write_reg(HX8347D_REG_PWC6, 0x88); /* Power Control 6 */ + write_reg(g, HX8347D_REG_OSCCH, 0x36); /* OSC Control 1 */ + write_reg(g, HX8347D_REG_OSCCL, 0x01); /* OSC Control 2 */ + write_reg(g, HX8347D_REG_DMODE, 0x00); /* Display Mode Control */ + write_reg(g, HX8347D_REG_PWC6, 0x88); /* Power Control 6 */ gfxSleepMilliseconds(5); /* Delay 5 ms */ - write_reg(HX8347D_REG_PWC6, 0x80); /* Power Control 6 */ + write_reg(g, HX8347D_REG_PWC6, 0x80); /* Power Control 6 */ gfxSleepMilliseconds(5); /* Delay 5 ms */ - write_reg(HX8347D_REG_PWC6, 0x90); /* Power Control 6 */ + write_reg(g, HX8347D_REG_PWC6, 0x90); /* Power Control 6 */ gfxSleepMilliseconds(5); /* Delay 5 ms */ - write_reg(HX8347D_REG_PWC6, 0xD0); /* Power Control 6 */ + write_reg(g, HX8347D_REG_PWC6, 0xD0); /* Power Control 6 */ gfxSleepMilliseconds(5); /* Delay 5 ms */ - write_reg(HX8347D_REG_COLMOD, 0x05); /* Colmod 16Bit/Pixel */ - write_reg(HX8347D_REG_PCH, 0x00); /* Panel Characteristic */ - write_reg(HX8347D_REG_DC3, 0x38); /* Display Control 3 */ + write_reg(g, HX8347D_REG_COLMOD, 0x05); /* Colmod 16Bit/Pixel */ + write_reg(g, HX8347D_REG_PCH, 0x00); /* Panel Characteristic */ + write_reg(g, HX8347D_REG_DC3, 0x38); /* Display Control 3 */ gfxSleepMilliseconds(40); /* Delay 40 ms */ - write_reg(HX8347D_REG_DC3, 0x3C); /* Display Control 3 */ - write_reg(HX8347D_REG_MAC, 0x08); /* Memory access control */ + write_reg(g, HX8347D_REG_DC3, 0x3C); /* Display Control 3 */ + write_reg(g, HX8347D_REG_MAC, 0x08); /* Memory access control */ + + // Finish Init + post_init_board(g); // Release the bus - release_bus(); + release_bus(g); /* Turn on the backlight */ - set_backlight(GDISP_INITIAL_BACKLIGHT); + set_backlight(g, GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ g->g.Width = GDISP_SCREEN_WIDTH; @@ -154,55 +158,55 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } #if GDISP_HARDWARE_STREAM_WRITE - LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); set_viewport(g); - busmode16(); + busmode16(g); } - LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { - write_ram16(g->p.color); + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_ram16(g, g->p.color); } - LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { - busmode8(); - release_bus(); + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + busmode8(g); + release_bus(g); } #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + LLDSPEC void gdisp_lld_control(GDisplay *g) { switch(g->p.x) { case GDISP_CONTROL_ORIENTATION: if (g->g.Orientation == (orientation_t)g->p.ptr) return; switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: - acquire_bus(); - write_reg(HX8347D_REG_MAC, 0x08); /* Memory access control */ - release_bus(); + acquire_bus(g); + write_reg(g, HX8347D_REG_MAC, 0x08); /* Memory access control */ + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: - acquire_bus(); - write_reg(HX8347D_REG_MAC, 0x68); /* Memory access control */ - release_bus(); + acquire_bus(g); + write_reg(g, HX8347D_REG_MAC, 0x68); /* Memory access control */ + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: - acquire_bus(); - write_reg(HX8347D_REG_MAC, 0xc8); /* Memory access control */ - release_bus(); + acquire_bus(g); + write_reg(g, HX8347D_REG_MAC, 0xc8); /* Memory access control */ + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: - acquire_bus(); - write_reg(HX8347D_REG_MAC, 0xa8); /* Memory access control */ - release_bus(); + acquire_bus(g); + write_reg(g, HX8347D_REG_MAC, 0xa8); /* Memory access control */ + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; @@ -215,7 +219,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; - set_backlight((unsigned)g->p.ptr); + set_backlight(g, (unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; @@ -226,4 +230,3 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif #endif /* GFX_USE_GDISP */ -/** @} */ diff --git a/drivers/gdisp/HX8347D/gdisp_lld.mk b/drivers/gdisp/HX8347D/gdisp_lld.mk index fed905e1..72d9cf75 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld.mk +++ b/drivers/gdisp/HX8347D/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/HX8347D/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/HX8347D +GFXSRC += $(GFXLIB)/drivers/gdisp/HX8347D/gdisp_lld.c diff --git a/drivers/gdisp/HX8347D/gdisp_lld_board_st_stm32f4_discovery.h b/drivers/gdisp/HX8347D/gdisp_lld_board_st_stm32f4_discovery.h deleted file mode 100644 index 8365fe74..00000000 --- a/drivers/gdisp/HX8347D/gdisp_lld_board_st_stm32f4_discovery.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/HX8347D/gdisp_lld_board_st_stm32f4_discovery.h - * @brief GDISP Graphic Driver subsystem board SPI interface for the HX8347D display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -// Overrides -#ifndef GDISP_INITIAL_BACKLIGHT - #define GDISP_INITIAL_BACKLIGHT 50 -#endif - -/* Pin assignments */ -#define SET_RST palSetPad(GPIOB, 8) -#define CLR_RST palClearPad(GPIOB, 8) -#define SET_DATA palSetPad(GPIOB, 9) -#define CLR_DATA palClearPad(GPIOB, 9) -#define SET_CS palSetPad(GPIOA, 4) -#define CLR_CS palClearPad(GPIOA, 4) - -/* PWM configuration structure. We use timer 4 channel 2 (orange LED on board). */ -static const PWMConfig pwmcfg = { - 1000000, /* 1 MHz PWM clock frequency. */ - 100, /* PWM period is 100 cycles. */ - NULL, - { - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL} - }, - 0 -}; - -/* - * SPI1 configuration structure. - * Speed 42MHz, CPHA=0, CPOL=0, 8bits frames, MSb transmitted first. - * The slave select line is the pin 4 on the port GPIOA. - */ -static const SPIConfig spi1cfg_8bit = { - NULL, - /* HW dependent part.*/ - GPIOA, - 4, - 0 //SPI_CR1_BR_0 -}; - -/* - * SPI1 configuration structure. - * Speed 42MHz, CPHA=0, CPOL=0, 16bits frames, MSb transmitted first. - * The slave select line is the pin 4 on the port GPIOA. - */ -static const SPIConfig spi1cfg_16bit = { - NULL, - /* HW dependent part.*/ - GPIOA, - 4, - SPI_CR1_DFF //SPI_CR1_BR_0 -}; - -/** - * @brief Initialise the board for the display. - * @notes This board definition uses GPIO and SPI. It assumes exclusive access to these GPIO pins but not necessarily the SPI port. - * - * @notapi - */ -static inline void init_board(void) { - /* Display backlight control */ - /* TIM4 is an alternate function 2 (AF2) */ - pwmStart(&PWMD4, &pwmcfg); - palSetPadMode(GPIOD, 13, PAL_MODE_ALTERNATE(2)); - pwmEnableChannel(&PWMD4, 1, 100); - - palSetPadMode(GPIOB, 8, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST); /* RST */ - palSetPadMode(GPIOB, 9, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST); /* RS */ - /* - * Initializes the SPI driver 1. The SPI1 signals are routed as follow: - * PB12 - NSS. - * PB13 - SCK. - * PB14 - MISO. - * PB15 - MOSI. - */ - SET_CS; SET_DATA; - spiStart(&SPID1, &spi1cfg_8bit); - palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL|PAL_STM32_OSPEED_HIGHEST); /* NSS. */ - palSetPadMode(GPIOA, 5, PAL_MODE_ALTERNATE(5)|PAL_STM32_OSPEED_HIGHEST); /* SCK. */ - palSetPadMode(GPIOA, 6, PAL_MODE_ALTERNATE(5)); /* MISO. */ - palSetPadMode(GPIOA, 7, PAL_MODE_ALTERNATE(5)|PAL_STM32_OSPEED_HIGHEST); /* MOSI. */ - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - if (state) { - CLR_RST; - } else { - SET_RST; - } -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - pwmEnableChannel(&PWMD4, 1, percent); -} - -/** - * @brief Take exclusive control of the bus - * @notapi - */ -static inline void acquire_bus(void) { - spiAcquireBus(&SPID1); - while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); // Safety - CLR_CS; -} - -/** - * @brief Release exclusive control of the bus - * @notapi - */ -static inline void release_bus(void) { - SET_CS; - spiReleaseBus(&SPID1); -} - -/** - * @brief Set the bus in 16 bit mode - * @notapi - */ -static inline void busmode16(void) { - spiStart(&SPID1, &spi1cfg_16bit); -} - -/** - * @brief Set the bus in 8 bit mode (the default) - * @notapi - */ -static inline void busmode8(void) { - spiStart(&SPID1, &spi1cfg_8bit); -} - -/** - * @brief Set which index register to use. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint8_t cmd) { - CLR_DATA; - SPI1->DR = cmd; - while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); - SET_DATA; -} - -/** - * @brief Send a command to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_reg(uint8_t cmd, uint8_t data) { - write_index(cmd); - SPI1->DR = data; - while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); -} - -static inline void write_ram16(uint16_t data) { - SPI1->DR = data; - while((SPI1->SR & SPI_SR_TXE) == 0); -} - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/HX8347D/gdisp_lld_board_template.h b/drivers/gdisp/HX8347D/gdisp_lld_board_template.h deleted file mode 100644 index d3b71d97..00000000 --- a/drivers/gdisp/HX8347D/gdisp_lld_board_template.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/HX8347D/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board SPI interface for the HX8347D display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief Initialise the board for the display. - * @notapi - */ -static inline void init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Set the bus in 16 bit mode - * @notapi - */ -static inline void busmode16(void) { - -} - -/** - * @brief Set the bus in 8 bit mode (the default) - * @notapi - */ -static inline void busmode8(void) { - -} - -/** - * @brief Set which index register to use. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint8_t cmd) { - -} - -/** - * @brief Send a command to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_reg(uint8_t cmd, uint8_t data) { - -} - -static inline void write_ram16(uint16_t data) { - -} - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/HX8347D/gdisp_lld_config.h b/drivers/gdisp/HX8347D/gdisp_lld_config.h index a5a8e2b8..48801f55 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld_config.h +++ b/drivers/gdisp/HX8347D/gdisp_lld_config.h @@ -22,9 +22,6 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "HX8347D" -#define GDISP_DRIVER_STRUCT GDISP_HX8347D - #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_CONTROL TRUE From 66d2d279674852f9c8631e1eb6a82f68b01778c1 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 16:43:09 +1000 Subject: [PATCH 058/160] Fix compile error --- drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h index 0fe5ded3..4899baa5 100644 --- a/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h +++ b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h @@ -143,7 +143,7 @@ static inline void busmode8(GDisplay *g) { static inline void write_index(GDisplay *g, uint8_t index) { (void) g; CLR_DATA; - SPI1->DR = cmd; + SPI1->DR = index; while(((SPI1->SR & SPI_SR_TXE) == 0) || ((SPI1->SR & SPI_SR_BSY) != 0)); SET_DATA; } From c9311d9851c28f555a26de8757d7aca9caa255d3 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 16:44:56 +1000 Subject: [PATCH 059/160] Changed board_XXXX_template.h so that it can be directly copied to board_XXXX.h in the project directory and it will compile with stub functions. --- .../gdisp/HX8347D/board_HX8347D_template.h | 26 +++++++++------ .../gdisp/SSD1289/board_SSD1289_template.h | 32 +++++++++++++------ 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/drivers/gdisp/HX8347D/board_HX8347D_template.h b/drivers/gdisp/HX8347D/board_HX8347D_template.h index 6084d1bf..528fb027 100644 --- a/drivers/gdisp/HX8347D/board_HX8347D_template.h +++ b/drivers/gdisp/HX8347D/board_HX8347D_template.h @@ -28,6 +28,8 @@ * @notapi */ static inline void init_board(GDisplay *g, unsigned display) { + (void) g; + (void) display; } /** @@ -38,6 +40,7 @@ static inline void init_board(GDisplay *g, unsigned display) { * @notapi */ static inline void post_init_board(GDisplay *g) { + (void) g; } /** @@ -49,7 +52,8 @@ static inline void post_init_board(GDisplay *g) { * @notapi */ static inline void setpin_reset(GDisplay *g, bool_t state) { - + (void) g; + (void) state; } /** @@ -61,7 +65,8 @@ static inline void setpin_reset(GDisplay *g, bool_t state) { * @notapi */ static inline void set_backlight(GDisplay *g, uint8_t percent) { - + (void) g; + (void) percent; } /** @@ -72,7 +77,7 @@ static inline void set_backlight(GDisplay *g, uint8_t percent) { * @notapi */ static inline void acquire_bus(GDisplay *g) { - + (void) g; } /** @@ -83,7 +88,7 @@ static inline void acquire_bus(GDisplay *g) { * @notapi */ static inline void release_bus(GDisplay *g) { - + (void) g; } /** @@ -94,7 +99,7 @@ static inline void release_bus(GDisplay *g) { * @notapi */ static inline void busmode16(GDisplay *g) { - + (void) g; } /** @@ -105,7 +110,7 @@ static inline void busmode16(GDisplay *g) { * @notapi */ static inline void busmode8(GDisplay *g) { - + (void) g; } /** @@ -117,7 +122,8 @@ static inline void busmode8(GDisplay *g) { * @notapi */ static inline void write_index(GDisplay *g, uint8_t index) { - + (void) g; + (void) index; } /** @@ -130,7 +136,8 @@ static inline void write_index(GDisplay *g, uint8_t index) { * @notapi */ static inline void write_data(GDisplay *g, uint8_t data) { - + (void) g; + (void) data; } /** @@ -143,7 +150,8 @@ static inline void write_data(GDisplay *g, uint8_t data) { * @notapi */ static inline void write_ram16(GDisplay *g, uint16_t data) { - + (void) g; + (void) data; } #endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/SSD1289/board_SSD1289_template.h b/drivers/gdisp/SSD1289/board_SSD1289_template.h index 941950b3..db841c2c 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_template.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_template.h @@ -28,6 +28,8 @@ * @notapi */ static inline void init_board(GDisplay *g, unsigned display) { + (void) g; + (void) display; } /** @@ -38,6 +40,7 @@ static inline void init_board(GDisplay *g, unsigned display) { * @notapi */ static inline void post_init_board(GDisplay *g) { + (void) g; } /** @@ -49,7 +52,8 @@ static inline void post_init_board(GDisplay *g) { * @notapi */ static inline void setpin_reset(GDisplay *g, bool_t state) { - + (void) g; + (void) state; } /** @@ -61,7 +65,8 @@ static inline void setpin_reset(GDisplay *g, bool_t state) { * @notapi */ static inline void set_backlight(GDisplay *g, uint8_t percent) { - + (void) g; + (void) percent; } /** @@ -72,7 +77,7 @@ static inline void set_backlight(GDisplay *g, uint8_t percent) { * @notapi */ static inline void acquire_bus(GDisplay *g) { - + (void) g; } /** @@ -83,7 +88,7 @@ static inline void acquire_bus(GDisplay *g) { * @notapi */ static inline void release_bus(GDisplay *g) { - + (void) g; } /** @@ -95,7 +100,8 @@ static inline void release_bus(GDisplay *g) { * @notapi */ static inline void write_index(GDisplay *g, uint16_t index) { - + (void) g; + (void) index; } /** @@ -107,7 +113,8 @@ static inline void write_index(GDisplay *g, uint16_t index) { * @notapi */ static inline void write_data(GDisplay *g, uint16_t data) { - + (void) g; + (void) data; } /** @@ -118,7 +125,7 @@ static inline void write_data(GDisplay *g, uint16_t data) { * @notapi */ static inline void setreadmode(GDisplay *g) { - + (void) g; } /** @@ -129,7 +136,7 @@ static inline void setreadmode(GDisplay *g) { * @notapi */ static inline void setwritemode(GDisplay *g) { - + (void) g; } /** @@ -144,7 +151,8 @@ static inline void setwritemode(GDisplay *g) { * @notapi */ static inline uint16_t read_data(GDisplay *g) { - + (void) g; + return 0; } /** @@ -163,6 +171,9 @@ static inline uint16_t read_data(GDisplay *g) { * @notapi */ static inline void dma_with_noinc(GDisplay *g, color_t *buffer, int area) { + (void) g; + (void) buffer; + (void) area; } /** @@ -175,6 +186,9 @@ static inline uint16_t read_data(GDisplay *g) { * @notapi */ static inline void dma_with_inc(GDisplay *g, color_t *buffer, int area) { + (void) g; + (void) buffer; + (void) area; } #endif From 9eabf4576df62d87de18a42090e3ae9133a320de Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 16:45:35 +1000 Subject: [PATCH 060/160] Convert ILI9320 driver to new format --- .../board_ILI9320_olimex_pic32mx_lcd.h | 129 +++++++ .../ILI9320/board_ILI9320_olimex_stm32_lcd.h | 103 ++++++ .../gdisp/ILI9320/board_ILI9320_template.h | 159 +++++++++ drivers/gdisp/ILI9320/gdisp_lld.c | 323 +++++++++--------- drivers/gdisp/ILI9320/gdisp_lld.mk | 5 +- .../gdisp_lld_board_olimex_pic32mx_lcd.h | 113 ------ .../gdisp_lld_board_olimex_stm32_lcd.h | 86 ----- .../gdisp/ILI9320/gdisp_lld_board_template.h | 61 ---- drivers/gdisp/ILI9320/gdisp_lld_config.h | 3 - 9 files changed, 557 insertions(+), 425 deletions(-) create mode 100644 drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h create mode 100644 drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h create mode 100644 drivers/gdisp/ILI9320/board_ILI9320_template.h delete mode 100644 drivers/gdisp/ILI9320/gdisp_lld_board_olimex_pic32mx_lcd.h delete mode 100644 drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h delete mode 100644 drivers/gdisp/ILI9320/gdisp_lld_board_template.h diff --git a/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h b/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h new file mode 100644 index 00000000..81d493ed --- /dev/null +++ b/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h @@ -0,0 +1,129 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h + * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display. + */ + +#ifndef GDISP_LLD_BOARD_H +#define GDISP_LLD_BOARD_H + +#ifndef noinline +#define noinline __attribute__((noinline)) +#endif + +static void init_board(GDisplay *g, unsigned display) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + if (display == 0) { + + /** + * Set up for Display 0 + */ + + // RST + palSetPadMode(IOPORTA, 7, PAL_MODE_OUTPUT); + palClearPad(IOPORTA, 7); + + // RS + palSetPadMode(IOPORTA, 10, PAL_MODE_OUTPUT); + palSetPad(IOPORTA, 10); + + // CS + palSetPadMode(IOPORTA, 9, PAL_MODE_OUTPUT); + palClearPad(IOPORTA, 9); + + // Backlight + palSetPadMode(IOPORTD, 3, PAL_MODE_OUTPUT); + palSetPad(IOPORTD, 3); + + // PMP setup + PMMODE = 0; + PMAEN = 0; + PMCON = 0; + PMMODEbits.MODE = 2; + PMMODEbits.WAITB = 0; + PMMODEbits.WAITM = 1; + PMMODEbits.WAITE = 0; + PMCONbits.CSF = 0; + PMCONbits.PTRDEN = 1; + PMCONbits.PTWREN = 1; + PMMODEbits.MODE16 = 1; + PMCONbits.PMPEN = 1; + + palClearPad(IOPORTA, 9); + } +} + +#define PmpWaitBusy() do {} while (PMMODEbits.BUSY) + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static noinline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if (state) + palClearPad(IOPORTA, 7); + else + palSetPad(IOPORTA, 7); +} + +static void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + if (percentage) + palClearPad(IOPORTD, 3); + else + palSetPad(IOPORTD, 3); +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static noinline void write_index(GDisplay *g, uint16_t index) { + volatile uint16_t dummy; + (void) g; + + PmpWaitBusy(); + palClearPad(IOPORTA, 10); + PMDIN = index; + PmpWaitBusy(); + palSetPad(IOPORTA, 10); + + dummy = PMDIN; + (void)dummy; +} + +static noinline void write_data(GDisplay *g, uint16_t data) { + (void) g; + PMDIN = data; + PmpWaitBusy(); +} + +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +static noinline uint16_t read_data(GDisplay *g) { + (void) g; + PmpWaitBusy(); + return PMDIN; +} + +#endif /* GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h b/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h new file mode 100644 index 00000000..df02a716 --- /dev/null +++ b/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h @@ -0,0 +1,103 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h + * @brief GDISP Graphic Driver subsystem board interface for the ILI9320 display. + */ + +#ifndef GDISP_LLD_BOARD_H +#define GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. +#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ +#define GDISP_RAM (*((volatile uint16_t *) 0x60100000)) /* RS = 1 */ + +static inline void init_board(GDisplay *g, unsigned display) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + if (display == 0) { + + /** + * Set up for Display 0 + */ + + /* FSMC setup for F1 */ + rccEnableAHB(RCC_AHBENR_FSMCEN, 0); + + /* set pin modes */ + IOBus busD = {GPIOD, PAL_WHOLE_PORT, 0}; + IOBus busE = {GPIOE, PAL_WHOLE_PORT, 0}; + palSetBusMode(&busD, PAL_MODE_STM32_ALTERNATE_PUSHPULL); + palSetBusMode(&busE, PAL_MODE_STM32_ALTERNATE_PUSHPULL); + palSetPadMode(GPIOE, GPIOE_TFT_RST, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, GPIOD_TFT_LIGHT, PAL_MODE_OUTPUT_PUSHPULL); + + /* FSMC timing */ + FSMC_Bank1->BTCR[0+1] = (6) | (10 << 8) | (10 << 16); + + /* Bank1 NOR/SRAM control register configuration + * This is actually not needed as already set by default after reset */ + FSMC_Bank1->BTCR[0] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if(state) + palClearPad(GPIOE, GPIOE_TFT_RST); + else + palSetPad(GPIOE, GPIOE_TFT_RST); +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + if(percent) + palClearPad(GPIOD, GPIOD_TFT_LIGHT); + else + palSetPad(GPIOD, GPIOD_TFT_LIGHT); +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + GDISP_REG = index; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + GDISP_RAM = data; +} + +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return GDISP_RAM; +} + +#endif /* GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/ILI9320/board_ILI9320_template.h b/drivers/gdisp/ILI9320/board_ILI9320_template.h new file mode 100644 index 00000000..ead9aee0 --- /dev/null +++ b/drivers/gdisp/ILI9320/board_ILI9320_template.h @@ -0,0 +1,159 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9320/board_ILI9320_template.h + * @brief GDISP Graphic Driver subsystem board interface for the ILI9320 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef GDISP_LLD_BOARD_H +#define GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * @param[in] display The display number on this controller (0..n) + * + * @note Set the g->priv member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g, unsigned display) { + (void) g; + (void) display; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Set the lcd back-light level. + * + * @param[in] g The GDisplay structure + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; +} + +/** + * @brief Set the bus in read mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +/** + * @brief Set the bus back into write mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +/** + * @brief Read data from the lcd. + * @return The data from the lcd + * + * @param[in] g The GDisplay structure + * + * @note The chip select may need to be asserted/de-asserted + * around the actual spi read + * + * @notapi + */ +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return 0; +} + +#endif /* GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index 68081b96..228cbb09 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -24,9 +24,11 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_LLD_DECLARATIONS +#define GDISP_DRIVER_VMT GDISPVMT_SSD1289 +#include "../drivers/gdisp/ILI9320/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" -#include "gdisp_lld_board.h" + +#include "board_ILI9320.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -48,129 +50,137 @@ /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ -uint32_t DISPLAY_CODE; /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -#define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } -#define write_reg(reg, data) { write_index(reg); write_data(data); } +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } -static void set_cursor(GDISPDriver *g) { +static void set_cursor(GDisplay *g) { switch(g->g.Orientation) { case GDISP_ROTATE_0: case GDISP_ROTATE_180: - write_reg(0x0020, g->p.x); - write_reg(0x0021, g->p.y); + write_reg(g, 0x20, g->p.x); + write_reg(g, 0x21, g->p.y); break; case GDISP_ROTATE_90: case GDISP_ROTATE_270: - write_reg(0x0020, g->p.y); - write_reg(0x0021, g->p.x); + write_reg(g, 0x20, g->p.y); + write_reg(g, 0x21, g->p.x); break; } - write_index(0x0022); + write_index(g, 0x22); } -static void set_viewport(GDISPDriver *g) { +static void set_viewport(GDisplay *g) { switch(g->g.Orientation) { case GDISP_ROTATE_0: case GDISP_ROTATE_180: - write_reg(0x0050, g->p.x); - write_reg(0x0051, g->p.x + g->p.cx - 1); - write_reg(0x0052, g->p.y); - write_reg(0x0053, g->p.y + g->p.cy - 1); + write_reg(g, 0x50, g->p.x); + write_reg(g, 0x51, g->p.x + g->p.cx - 1); + write_reg(g, 0x52, g->p.y); + write_reg(g, 0x53, g->p.y + g->p.cy - 1); break; case GDISP_ROTATE_90: case GDISP_ROTATE_270: - write_reg(0x0050, g->p.y); - write_reg(0x0051, g->p.y + g->p.cy - 1); - write_reg(0x0052, g->p.x); - write_reg(0x0053, g->p.x + g->p.cx - 1); + write_reg(g, 0x50, g->p.y); + write_reg(g, 0x51, g->p.y + g->p.cy - 1); + write_reg(g, 0x52, g->p.x); + write_reg(g, 0x53, g->p.x + g->p.cx - 1); break; } } -LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { + uint16_t cver; + /* Initialise your display */ - init_board(); + init_board(g, display); /* Hardware reset */ - setpin_reset(TRUE); + setpin_reset(g, TRUE); gfxSleepMicroseconds(1000); - setpin_reset(FALSE); + setpin_reset(g, FALSE); gfxSleepMicroseconds(1000); - acquire_bus(); - write_index(0); // Get controller version - dummy_read(); - DISPLAY_CODE = read_data(); - write_reg(0x0000, 0x0001); //start Int. osc + acquire_bus(g); + write_index(g, 0); // Get controller version + setreadmode(g); + dummy_read(g); + cver = read_data(g); + setwritemode(g); + write_reg(g, 0x00, 0x0001); //start Int. osc gfxSleepMicroseconds(500); - write_reg(0x0001, 0x0100); //Set SS bit (shift direction of outputs is from S720 to S1) - write_reg(0x0002, 0x0700); //select the line inversion - write_reg(0x0003, 0x1038); //Entry mode(Horizontal : increment,Vertical : increment, AM=1) - write_reg(0x0004, 0x0000); //Resize control(No resizing) - write_reg(0x0008, 0x0202); //front and back porch 2 lines - write_reg(0x0009, 0x0000); //select normal scan - write_reg(0x000A, 0x0000); //display control 4 - write_reg(0x000C, 0x0000); //system interface(2 transfer /pixel), internal sys clock, - write_reg(0x000D, 0x0000); //Frame marker position - write_reg(0x000F, 0x0000); //selects clk, enable and sync signal polarity, - write_reg(0x0010, 0x0000); // - write_reg(0x0011, 0x0000); //power control 2 reference voltages = 1:1, - write_reg(0x0012, 0x0000); //power control 3 VRH - write_reg(0x0013, 0x0000); //power control 4 VCOM amplitude + write_reg(g, 0x01, 0x0100); //Set SS bit (shift direction of outputs is from S720 to S1) + write_reg(g, 0x02, 0x0700); //select the line inversion + write_reg(g, 0x03, 0x1038); //Entry mode(Horizontal : increment,Vertical : increment, AM=1) + write_reg(g, 0x04, 0x0000); //Resize control(No resizing) + write_reg(g, 0x08, 0x0202); //front and back porch 2 lines + write_reg(g, 0x09, 0x0000); //select normal scan + write_reg(g, 0x0A, 0x0000); //display control 4 + write_reg(g, 0x0C, 0x0000); //system interface(2 transfer /pixel), internal sys clock, + write_reg(g, 0x0D, 0x0000); //Frame marker position + write_reg(g, 0x0F, 0x0000); //selects clk, enable and sync signal polarity, + write_reg(g, 0x10, 0x0000); // + write_reg(g, 0x11, 0x0000); //power control 2 reference voltages = 1:1, + write_reg(g, 0x12, 0x0000); //power control 3 VRH + write_reg(g, 0x13, 0x0000); //power control 4 VCOM amplitude gfxSleepMicroseconds(500); - write_reg(0x0010, 0x17B0); //power control 1 BT,AP - write_reg(0x0011, 0x0137); //power control 2 DC,VC + write_reg(g, 0x10, 0x17B0); //power control 1 BT,AP + write_reg(g, 0x11, 0x0137); //power control 2 DC,VC gfxSleepMicroseconds(500); - write_reg(0x0012, 0x0139); //power control 3 VRH + write_reg(g, 0x12, 0x0139); //power control 3 VRH gfxSleepMicroseconds(500); - write_reg(0x0013, 0x1d00); //power control 4 vcom amplitude - write_reg(0x0029, 0x0011); //power control 7 VCOMH + write_reg(g, 0x13, 0x1d00); //power control 4 vcom amplitude + write_reg(g, 0x29, 0x0011); //power control 7 VCOMH gfxSleepMicroseconds(500); - write_reg(0x0030, 0x0007); - write_reg(0x0031, 0x0403); - write_reg(0x0032, 0x0404); - write_reg(0x0035, 0x0002); - write_reg(0x0036, 0x0707); - write_reg(0x0037, 0x0606); - write_reg(0x0038, 0x0106); - write_reg(0x0039, 0x0007); - write_reg(0x003c, 0x0700); - write_reg(0x003d, 0x0707); - write_reg(0x0020, 0x0000); //starting Horizontal GRAM Address - write_reg(0x0021, 0x0000); //starting Vertical GRAM Address - write_reg(0x0050, 0x0000); //Horizontal GRAM Start Position - write_reg(0x0051, 0x00EF); //Horizontal GRAM end Position - write_reg(0x0052, 0x0000); //Vertical GRAM Start Position - write_reg(0x0053, 0x013F); //Vertical GRAM end Position - switch (DISPLAY_CODE) { + write_reg(g, 0x30, 0x0007); + write_reg(g, 0x31, 0x0403); + write_reg(g, 0x32, 0x0404); + write_reg(g, 0x35, 0x0002); + write_reg(g, 0x36, 0x0707); + write_reg(g, 0x37, 0x0606); + write_reg(g, 0x38, 0x0106); + write_reg(g, 0x39, 0x0007); + write_reg(g, 0x3c, 0x0700); + write_reg(g, 0x3d, 0x0707); + write_reg(g, 0x20, 0x0000); //starting Horizontal GRAM Address + write_reg(g, 0x21, 0x0000); //starting Vertical GRAM Address + write_reg(g, 0x50, 0x0000); //Horizontal GRAM Start Position + write_reg(g, 0x51, 0x00EF); //Horizontal GRAM end Position + write_reg(g, 0x52, 0x0000); //Vertical GRAM Start Position + write_reg(g, 0x53, 0x013F); //Vertical GRAM end Position + switch (cver) { case 0x9320: - write_reg(0x0060, 0x2700); //starts scanning from G1, and 320 drive lines + write_reg(g, 0x60, 0x2700); //starts scanning from G1, and 320 drive lines break; case 0x9325: - write_reg(0x0060, 0xA700); //starts scanning from G1, and 320 drive lines + write_reg(g, 0x60, 0xA700); //starts scanning from G1, and 320 drive lines break; } - write_reg(0x0061, 0x0001); //fixed base display - write_reg(0x006a, 0x0000); //no scroll - write_reg(0x0090, 0x0010); //set Clocks/Line =16, Internal Operation Clock Frequency=fosc/1, - write_reg(0x0092, 0x0000); //set gate output non-overlap period=0 - write_reg(0x0093, 0x0003); //set Source Output Position=3 - write_reg(0x0095, 0x0110); //RGB interface(Clocks per line period=16 clocks) - write_reg(0x0097, 0x0110); //set Gate Non-overlap Period 0 locksc - write_reg(0x0098, 0x0110); // - write_reg(0x0007, 0x0173); //display On - release_bus(); + write_reg(g, 0x61, 0x0001); //fixed base display + write_reg(g, 0x6a, 0x0000); //no scroll + write_reg(g, 0x90, 0x0010); //set Clocks/Line =16, Internal Operation Clock Frequency=fosc/1, + write_reg(g, 0x92, 0x0000); //set gate output non-overlap period=0 + write_reg(g, 0x93, 0x0003); //set Source Output Position=3 + write_reg(g, 0x95, 0x0110); //RGB interface(Clocks per line period=16 clocks) + write_reg(g, 0x97, 0x0110); //set Gate Non-overlap Period 0 locksc + write_reg(g, 0x98, 0x0110); // + write_reg(g, 0x07, 0x0173); //display On + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); // Turn on the backlight - set_backlight(GDISP_INITIAL_BACKLIGHT); + set_backlight(g, GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ g->g.Width = GDISP_SCREEN_WIDTH; @@ -183,108 +193,105 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } #if GDISP_HARDWARE_STREAM_WRITE - LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); set_viewport(g); } - LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { - write_data(g->p.color); + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, g->p.color); } - LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { - release_bus(); + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); } - LLDSPEC void gdisp_lld_write_pos(GDISPDriver *g) { + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { set_cursor(g); } - #endif #endif #if GDISP_HARDWARE_STREAM_READ - LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_read_start(GDisplay *g) { + acquire_bus(g); set_viewport(g); set_cursor(g); - setreadmode(); - dummy_read(); + setreadmode(g); + dummy_read(g); } - LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g) { - return read_data(); + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { + return read_data(g); } - LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g) { - setwritemode(); - release_bus(); + LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { + setwritemode(g); + release_bus(g); } #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + LLDSPEC void gdisp_lld_control(GDisplay *g) { switch(g->p.x) { case GDISP_CONTROL_POWER: if (g->g.Powermode == (powermode_t)g->p.ptr) return; switch((powermode_t)g->p.ptr) { case powerOff: - acquire_bus(); - write_reg(0x0007, 0x0000); - write_reg(0x0010, 0x0000); - write_reg(0x0011, 0x0000); - write_reg(0x0012, 0x0000); - write_reg(0x0013, 0x0000); - release_bus(); + acquire_bus(g); + write_reg(g, 0x07, 0x0000); + write_reg(g, 0x10, 0x0000); + write_reg(g, 0x11, 0x0000); + write_reg(g, 0x12, 0x0000); + write_reg(g, 0x13, 0x0000); + release_bus(g); - set_backlight(0); + set_backlight(g, 0); break; case powerOn: //*************Power On sequence ******************// - acquire_bus(); - write_reg(0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ - write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ - write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + acquire_bus(g); + write_reg(g, 0x10, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(g, 0x11, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x12, 0x0000); /* VREG1OUT voltage */ + write_reg(g, 0x13, 0x0000); /* VDV[4:0] for VCOM amplitude */ gfxSleepMicroseconds(2000); /* Dis-charge capacitor power voltage */ - write_reg(0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ - write_reg(0x0011, 0x0147); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x10, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(g, 0x11, 0x0147); /* DC1[2:0], DC0[2:0], VC[2:0] */ gfxSleepMicroseconds(500); - write_reg(0x0012, 0x013C); /* VREG1OUT voltage */ + write_reg(g, 0x12, 0x013C); /* VREG1OUT voltage */ gfxSleepMicroseconds(500); - write_reg(0x0013, 0x0E00); /* VDV[4:0] for VCOM amplitude */ - write_reg(0x0029, 0x0009); /* VCM[4:0] for VCOMH */ + write_reg(g, 0x13, 0x0E00); /* VDV[4:0] for VCOM amplitude */ + write_reg(g, 0x29, 0x0009); /* VCM[4:0] for VCOMH */ gfxSleepMicroseconds(500); - write_reg(0x0007, 0x0173); /* 262K color and display ON */ - release_bus(); + write_reg(g, 0x07, 0x0173); /* 262K color and display ON */ + release_bus(g); - set_backlight(g->g.Backlight); - if(g->g.Powermode != powerSleep || g->g.Powermode != powerDeepSleep) - gdisp_lld_init(); + set_backlight(g, g->g.Backlight); break; case powerSleep: - acquire_bus(); - write_reg(0x0007, 0x0000); /* display OFF */ - write_reg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ - write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + acquire_bus(g); + write_reg(g, 0x07, 0x0000); /* display OFF */ + write_reg(g, 0x10, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(g, 0x11, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x12, 0x0000); /* VREG1OUT voltage */ + write_reg(g, 0x13, 0x0000); /* VDV[4:0] for VCOM amplitude */ gfxSleepMicroseconds(2000); /* Dis-charge capacitor power voltage */ - write_reg(0x0010, 0x0002); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - release_bus(); + write_reg(g, 0x10, 0x0002); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(g); - set_backlight(0); + set_backlight(g, 0); break; case powerDeepSleep: - acquire_bus(); - write_reg(0x0007, 0x0000); /* display OFF */ - write_reg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ - write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + acquire_bus(g); + write_reg(g, 0x07, 0x0000); /* display OFF */ + write_reg(g, 0x10, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(g, 0x11, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x12, 0x0000); /* VREG1OUT voltage */ + write_reg(g, 0x13, 0x0000); /* VDV[4:0] for VCOM amplitude */ gfxSleepMicroseconds(2000); /* Dis-charge capacitor power voltage */ - write_reg(0x0010, 0x0004); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - release_bus(); + write_reg(g, 0x10, 0x0004); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(g); - set_backlight(0); + set_backlight(g, 0); break; default: @@ -298,44 +305,44 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return; switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: - acquire_bus(); - write_reg(0x0001, 0x0100); - write_reg(0x0003, 0x1038); - write_reg(0x0060, 0x2700); - release_bus(); + acquire_bus(g); + write_reg(g, 0x01, 0x0100); + write_reg(g, 0x03, 0x1038); + write_reg(g, 0x60, 0x2700); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: - acquire_bus(); - write_reg(0x0001, 0x0100); - write_reg(0x0003, 0x1030); - write_reg(0x0060, 0x2700); - release_bus(); + acquire_bus(g); + write_reg(g, 0x01, 0x0100); + write_reg(g, 0x03, 0x1030); + write_reg(g, 0x60, 0x2700); + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: - acquire_bus(); - write_reg(0x0001, 0x0000); - write_reg(0x0003, 0x1030); - write_reg(0x0060, 0x2700); - release_bus(); + acquire_bus(g); + write_reg(g, 0x01, 0x0000); + write_reg(g, 0x03, 0x1030); + write_reg(g, 0x60, 0x2700); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: - acquire_bus(); - write_reg(0x0001, 0x0000); - write_reg(0x0003, 0x1038); - write_reg(0x0060, 0xA700); - release_bus(); + acquire_bus(g); + write_reg(g, 0x01, 0x0000); + write_reg(g, 0x03, 0x1038); + write_reg(g, 0x60, 0xA700); + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; @@ -350,7 +357,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; - set_backlight((unsigned)g->p.ptr); + set_backlight(g, (unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; default: diff --git a/drivers/gdisp/ILI9320/gdisp_lld.mk b/drivers/gdisp/ILI9320/gdisp_lld.mk index bcdd3230..656f5930 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.mk +++ b/drivers/gdisp/ILI9320/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9320/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/ILI9320 +GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9320/gdisp_lld.c diff --git a/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_pic32mx_lcd.h b/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_pic32mx_lcd.h deleted file mode 100644 index faa54a3e..00000000 --- a/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_pic32mx_lcd.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/ILI9320/gdisp_lld_board_olimex_pic32mx_lcd.h - * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef GDISP_LLD_BOARD_H -#define GDISP_LLD_BOARD_H - -#ifndef noinline -#define noinline __attribute__((noinline)) -#endif - -static void init_board(void) { - // RST - palSetPadMode(IOPORTA, 7, PAL_MODE_OUTPUT); - palClearPad(IOPORTA, 7); - - // RS - palSetPadMode(IOPORTA, 10, PAL_MODE_OUTPUT); - palSetPad(IOPORTA, 10); - - // CS - palSetPadMode(IOPORTA, 9, PAL_MODE_OUTPUT); - palClearPad(IOPORTA, 9); - - // Backlight - palSetPadMode(IOPORTD, 3, PAL_MODE_OUTPUT); - palSetPad(IOPORTD, 3); - - // PMP setup - PMMODE = 0; - PMAEN = 0; - PMCON = 0; - PMMODEbits.MODE = 2; - PMMODEbits.WAITB = 0; - PMMODEbits.WAITM = 1; - PMMODEbits.WAITE = 0; - PMCONbits.CSF = 0; - PMCONbits.PTRDEN = 1; - PMCONbits.PTWREN = 1; - PMMODEbits.MODE16 = 1; - PMCONbits.PMPEN = 1; - - palClearPad(IOPORTA, 9); -} - -#define PmpWaitBusy() do {} while (PMMODEbits.BUSY) - -static noinline void setpin_reset(bool_t state) { - if (state) - palClearPad(IOPORTA, 7); - else - palSetPad(IOPORTA, 7); -} - -static noinline void write_index(uint16_t data) { - volatile uint16_t dummy; - - PmpWaitBusy(); - palClearPad(IOPORTA, 10); - PMDIN = data; - PmpWaitBusy(); - palSetPad(IOPORTA, 10); - - dummy = PMDIN; - (void)dummy; -} - -static noinline void write_data(uint16_t data) { - PMDIN = data; - PmpWaitBusy(); -} - -static inline void setreadmode(void) { -} - -static inline void setwritemode(void) { -} - -static noinline uint16_t read_data(void) { - PmpWaitBusy(); - return PMDIN; -} - -/* if not available, just ignore the argument and return */ -static void set_backlight(uint8_t percentage) { - if (percentage) - palClearPad(IOPORTD, 3); - else - palSetPad(IOPORTD, 3); -} - -static inline void acquire_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -static inline void release_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -#endif /* GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h b/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h deleted file mode 100644 index 1662385a..00000000 --- a/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h - * @brief GDISP Graphic Driver subsystem board interface for the ILI9320 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef GDISP_LLD_BOARD_H -#define GDISP_LLD_BOARD_H - -#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ -#define GDISP_RAM (*((volatile uint16_t *) 0x60100000)) /* RS = 1 */ - -static inline void init_board(void) { - /* FSMC setup for F1 */ - rccEnableAHB(RCC_AHBENR_FSMCEN, 0); - - /* set pin modes */ - IOBus busD = {GPIOD, PAL_WHOLE_PORT, 0}; - IOBus busE = {GPIOE, PAL_WHOLE_PORT, 0}; - palSetBusMode(&busD, PAL_MODE_STM32_ALTERNATE_PUSHPULL); - palSetBusMode(&busE, PAL_MODE_STM32_ALTERNATE_PUSHPULL); - palSetPadMode(GPIOE, GPIOE_TFT_RST, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, GPIOD_TFT_LIGHT, PAL_MODE_OUTPUT_PUSHPULL); - - const unsigned char FSMC_Bank = 0; - - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = (6) | (10 << 8) | (10 << 16); - - /* Bank1 NOR/SRAM control register configuration - * This is actually not needed as already set by default after reset */ - FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; -} - -static inline void setpin_reset(bool_t state) { - if(state) - palClearPad(GPIOE, GPIOE_TFT_RST); - else - palSetPad(GPIOE, GPIOE_TFT_RST); -} - -static inline void acquire_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -static inline void release_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -static inline void write_index(uint16_t reg) { - GDISP_REG = reg; -} - -static inline void write_data(uint16_t data) { - GDISP_RAM = data; -} - -static inline void setreadmode(void) { -} - -static inline void setwritemode(void) { -} - -static inline uint16_t read_data(void) { - return GDISP_RAM; -} - -static inline void set_backlight(uint8_t percent) { - if(percent == 100) - palClearPad(GPIOD, GPIOD_TFT_LIGHT); - else - palSetPad(GPIOD, GPIOD_TFT_LIGHT); -} - -#endif /* GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/ILI9320/gdisp_lld_board_template.h b/drivers/gdisp/ILI9320/gdisp_lld_board_template.h deleted file mode 100644 index 201b3630..00000000 --- a/drivers/gdisp/ILI9320/gdisp_lld_board_template.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/ILI9320/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board interface for the ILI9320 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef GDISP_LLD_BOARD_H -#define GDISP_LLD_BOARD_H - -static inline void init_board(void) { - -} - -static inline void setpin_reset(bool_t state) { - -} - -static inline void acquire_bus(void) { - -} - -static inline void release_bus(void) { - -} - -static inline void write_index(uint16_t data) { - -} - -static inline void write_data(uint16_t data) { - -} - -static inline void setreadmode(void) { - -} - -static inline void setwritemode(void) { - -} - -static inline uint16_t read_data(void) { - -} - -static inline uint16_t set_backlight(uint8_t percentage) { - -} - -#endif /* GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/ILI9320/gdisp_lld_config.h b/drivers/gdisp/ILI9320/gdisp_lld_config.h index 02533e8b..3c5c7484 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_config.h @@ -22,9 +22,6 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "ILI9320" -#define GDISP_DRIVER_STRUCT GDISP_ILI9320 - #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE #define GDISP_HARDWARE_STREAM_POS TRUE From a3714ae7c4438d6b3247c45a1c8fe3f217a9a2af Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 17:07:26 +1000 Subject: [PATCH 061/160] Bug fix ILI9320 driver --- drivers/gdisp/ILI9320/gdisp_lld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index 228cbb09..3747b3d7 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -24,7 +24,7 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_DRIVER_VMT GDISPVMT_SSD1289 +#define GDISP_DRIVER_VMT GDISPVMT_ILI9320 #include "../drivers/gdisp/ILI9320/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" From 313956b2154875e479735a17468af7013d4d6de6 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 17:07:53 +1000 Subject: [PATCH 062/160] Remove incorrect comment. --- drivers/gdisp/SSD1289/board_SSD1289_template.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gdisp/SSD1289/board_SSD1289_template.h b/drivers/gdisp/SSD1289/board_SSD1289_template.h index db841c2c..b24789ea 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_template.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_template.h @@ -145,9 +145,6 @@ static inline void setwritemode(GDisplay *g) { * * @param[in] g The GDisplay structure * - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * * @notapi */ static inline uint16_t read_data(GDisplay *g) { From 668afded53f3e35f73126808688fbf659cf1a63c Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 17:08:21 +1000 Subject: [PATCH 063/160] Convert ILI9325 driver to new format --- .../ILI9325/board_ILI9325_hy_stm32_100p.h | 117 +++++++ .../gdisp/ILI9325/board_ILI9325_template.h | 157 +++++++++ drivers/gdisp/ILI9325/gdisp_lld.c | 300 +++++++++--------- drivers/gdisp/ILI9325/gdisp_lld.mk | 5 +- .../ILI9325/gdisp_lld_board_hy_stm32_100p.h | 119 ------- .../gdisp/ILI9325/gdisp_lld_board_template.h | 123 ------- drivers/gdisp/ILI9325/gdisp_lld_config.h | 3 - 7 files changed, 428 insertions(+), 396 deletions(-) create mode 100644 drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h create mode 100644 drivers/gdisp/ILI9325/board_ILI9325_template.h delete mode 100644 drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h delete mode 100644 drivers/gdisp/ILI9325/gdisp_lld_board_template.h diff --git a/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h new file mode 100644 index 00000000..ed697b6f --- /dev/null +++ b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h @@ -0,0 +1,117 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/* + driver quickly hacked together from a chinese sourcecode that came + with the board and existing ili9320 code by Chris van Dongen (sjaak) + (sjaak2002 at msn.com) + + Also added rotation for 180 and 270 degrees and minor tweaks to + setcursor + + Added code comes without warranty and free bugs. Feel free to use + or misuse the added code :D +*/ + + +/** + * @file drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h + * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display. + */ + +#ifndef GDISP_LLD_BOARD_H +#define GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. +#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ +#define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ + +static inline void init_board(GDisplay *g, unsigned display) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + if (display == 0) { + + /** + * Set up for Display 0 + */ + + /* FSMC setup for F1 */ + rccEnableAHB(RCC_AHBENR_FSMCEN, 0); + + /* set pin modes */ + /* IOBus busD = {GPIOD, PAL_WHOLE_PORT, 0}; + IOBus busE = {GPIOE, PAL_WHOLE_PORT, 0}; + palSetBusMode(&busD, PAL_MODE_STM32_ALTERNATE_PUSHPULL); + palSetBusMode(&busE, PAL_MODE_STM32_ALTERNATE_PUSHPULL); + palSetPadMode(GPIOE, GPIOE_TFT_RST, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, GPIOD_TFT_LIGHT, PAL_MODE_OUTPUT_PUSHPULL); */ + + const unsigned char FSMC_Bank = 0; + + /* FSMC timing */ + FSMC_Bank1->BTCR[FSMC_Bank+1] = (6) | (10 << 8) | (10 << 16); + + /* Bank1 NOR/SRAM control register configuration + * This is actually not needed as already set by default after reset */ + FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if(state) + palClearPad(GPIOE, GPIOE_TFT_RST); + else + palSetPad(GPIOE, GPIOE_TFT_RST); +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void)percent; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + GDISP_REG = index; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + GDISP_RAM = data; +} + +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return GDISP_RAM; +} + +#endif /* GDISP_LLD_BOARD_H */ +/** @} */ + diff --git a/drivers/gdisp/ILI9325/board_ILI9325_template.h b/drivers/gdisp/ILI9325/board_ILI9325_template.h new file mode 100644 index 00000000..4d54ba34 --- /dev/null +++ b/drivers/gdisp/ILI9325/board_ILI9325_template.h @@ -0,0 +1,157 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9325/gdisp_lld_board_template.h + * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef GDISP_LLD_BOARD_H +#define GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * @param[in] display The display number on this controller (0..n) + * + * @note Set the g->priv member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g, unsigned display) { + (void) g; + (void) display; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Set the lcd back-light level. + * + * @param[in] g The GDisplay structure + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; +} + +/** + * @brief Set the bus in read mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +/** + * @brief Set the bus back into write mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +/** + * @brief Read data from the lcd. + * @return The data from the lcd + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return 0; +} + +#endif /* GDISP_LLD_BOARD_H */ +/** @} */ + diff --git a/drivers/gdisp/ILI9325/gdisp_lld.c b/drivers/gdisp/ILI9325/gdisp_lld.c index 4795887e..42acdc46 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld.c +++ b/drivers/gdisp/ILI9325/gdisp_lld.c @@ -8,9 +8,6 @@ /** * @file drivers/gdisp/ILI9325/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for the ILI9325 display. - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" @@ -27,9 +24,11 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_LLD_DECLARATIONS +#define GDISP_DRIVER_VMT GDISPVMT_ILI9325 +#include "../drivers/gdisp/ILI9325/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" -#include "gdisp_lld_board.h" + +#include "board_ILI9325.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -51,126 +50,135 @@ /*===========================================================================*/ /* Driver local variables. */ /*===========================================================================*/ -uint32_t DISPLAY_CODE; /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ // Some common routines and macros -#define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } -#define write_reg(reg, data) { write_index(reg); write_data(data); } +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } -static void set_cursor(GDISPDriver *g) { +static void set_cursor(GDisplay *g) { switch(g->g.Orientation) { case GDISP_ROTATE_0: case GDISP_ROTATE_180: - write_reg(0x0020, g->p.x); - write_reg(0x0021, g->p.y); + write_reg(g, 0x20, g->p.x); + write_reg(g, 0x21, g->p.y); break; case GDISP_ROTATE_90: case GDISP_ROTATE_270: - write_reg(0x0020, g->p.y); - write_reg(0x0021, g->p.x); + write_reg(g, 0x20, g->p.y); + write_reg(g, 0x21, g->p.x); break; } - write_index(0x0022); + write_index(g, 0x22); } -static void set_viewport(GDISPDriver* g) { +static void set_viewport(GDisplay* g) { switch(g->g.Orientation) { case GDISP_ROTATE_0: case GDISP_ROTATE_180: - write_reg(0x0050, g->p.x); - write_reg(0x0051, g->p.x + g->p.cx - 1); - write_reg(0x0052, g->p.y); - write_reg(0x0053, g->p.y + g->p.cy - 1); + write_reg(g, 0x50, g->p.x); + write_reg(g, 0x51, g->p.x + g->p.cx - 1); + write_reg(g, 0x52, g->p.y); + write_reg(g, 0x53, g->p.y + g->p.cy - 1); break; case GDISP_ROTATE_90: case GDISP_ROTATE_270: - write_reg(0x0050, g->p.y); - write_reg(0x0051, g->p.y + g->p.cy - 1); - write_reg(0x0052, g->p.x); - write_reg(0x0053, g->p.x + g->p.cx - 1); + write_reg(g, 0x50, g->p.y); + write_reg(g, 0x51, g->p.y + g->p.cy - 1); + write_reg(g, 0x52, g->p.x); + write_reg(g, 0x53, g->p.x + g->p.cx - 1); break; } } -LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { + uint16_t cver; + /* Initialise your display */ - init_board(); + init_board(g, display); /* Hardware reset */ - setpin_reset(TRUE); + setpin_reset(g, TRUE); gfxSleepMicroseconds(1000); - setpin_reset(FALSE); + setpin_reset(g, FALSE); gfxSleepMicroseconds(1000); - acquire_bus(); - write_index(0); // Get controller version - dummy_read(); - DISPLAY_CODE = read_data(); + acquire_bus(g); + write_index(g, 0); // Get controller version + setreadmode(g); + dummy_read(g); + cver = read_data(g); + setwritemode(g); // chinese code starts here - write_reg(0x0000,0x0001); + write_reg(g, 0x00, 0x0001); gfxSleepMilliseconds(10); - write_reg(0x0015,0x0030); - write_reg(0x0011,0x0040); - write_reg(0x0010,0x1628); - write_reg(0x0012,0x0000); - write_reg(0x0013,0x104d); + write_reg(g, 0x15, 0x0030); + write_reg(g, 0x11, 0x0040); + write_reg(g, 0x10, 0x1628); + write_reg(g, 0x12, 0x0000); + write_reg(g, 0x13, 0x104d); gfxSleepMilliseconds(10); - write_reg(0x0012,0x0010); + write_reg(g, 0x12, 0x0010); gfxSleepMilliseconds(10); - write_reg(0x0010,0x2620); - write_reg(0x0013,0x344d); //304d + write_reg(g, 0x10, 0x2620); + write_reg(g, 0x13, 0x344d); //304d gfxSleepMilliseconds(10); - write_reg(0x0001,0x0100); - write_reg(0x0002,0x0300); - write_reg(0x0003,0x1038);//0x1030 - write_reg(0x0008,0x0604); - write_reg(0x0009,0x0000); - write_reg(0x000A,0x0008); + write_reg(g, 0x01, 0x0100); + write_reg(g, 0x02, 0x0300); + write_reg(g, 0x03, 0x1038);//0x1030 + write_reg(g, 0x08, 0x0604); + write_reg(g, 0x09, 0x0000); + write_reg(g, 0x0A, 0x0008); - write_reg(0x0041,0x0002); - write_reg(0x0060,0x2700); - write_reg(0x0061,0x0001); - write_reg(0x0090,0x0182); - write_reg(0x0093,0x0001); - write_reg(0x00a3,0x0010); + write_reg(g, 0x41, 0x0002); + write_reg(g, 0x60, 0x2700); + write_reg(g, 0x61, 0x0001); + write_reg(g, 0x90, 0x0182); + write_reg(g, 0x93, 0x0001); + write_reg(g, 0xa3, 0x0010); gfxSleepMilliseconds(10); //################# void Gamma_Set(void) ####################// - write_reg(0x30,0x0000); - write_reg(0x31,0x0502); - write_reg(0x32,0x0307); - write_reg(0x33,0x0305); - write_reg(0x34,0x0004); - write_reg(0x35,0x0402); - write_reg(0x36,0x0707); - write_reg(0x37,0x0503); - write_reg(0x38,0x1505); - write_reg(0x39,0x1505); + write_reg(g, 0x30, 0x0000); + write_reg(g, 0x31, 0x0502); + write_reg(g, 0x32, 0x0307); + write_reg(g, 0x33, 0x0305); + write_reg(g, 0x34, 0x0004); + write_reg(g, 0x35, 0x0402); + write_reg(g, 0x36, 0x0707); + write_reg(g, 0x37, 0x0503); + write_reg(g, 0x38, 0x1505); + write_reg(g, 0x39, 0x1505); gfxSleepMilliseconds(10); //################## void Display_ON(void) ####################// - write_reg(0x0007,0x0001); + write_reg(g, 0x07, 0x0001); gfxSleepMilliseconds(10); - write_reg(0x0007,0x0021); - write_reg(0x0007,0x0023); + write_reg(g, 0x07, 0x0021); + write_reg(g, 0x07, 0x0023); gfxSleepMilliseconds(10); - write_reg(0x0007,0x0033); + write_reg(g, 0x07, 0x0033); gfxSleepMilliseconds(10); - write_reg(0x0007,0x0133); + write_reg(g, 0x07, 0x0133); // chinese code ends here + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + // Turn on the backlight - set_backlight(GDISP_INITIAL_BACKLIGHT); + set_backlight(g, GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ g->g.Width = GDISP_SCREEN_WIDTH; @@ -184,101 +192,101 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } #if GDISP_HARDWARE_STREAM_WRITE - LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); set_viewport(g); } - LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { - write_data(g->p.color); + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, g->p.color); } - LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { - release_bus(); + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); } - LLDSPEC void gdisp_lld_write_pos(GDISPDriver *g) { + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { set_cursor(g); } #endif #if GDISP_HARDWARE_STREAM_READ - LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_read_start(GDisplay *g) { + acquire_bus(g); set_viewport(g); set_cursor(g); - setreadmode(); - dummy_read(); + setreadmode(g); + dummy_read(g); } - LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g) { - return read_data(); + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { + return read_data(g); } - LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g) { - setwritemode(); - release_bus(); + LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { + setwritemode(g); + release_bus(g); } #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + LLDSPEC void gdisp_lld_control(GDisplay *g) { switch(g->p.x) { case GDISP_CONTROL_POWER: if (g->g.Powermode == (powermode_t)g->p.ptr) return; switch((powermode_t)g->p.ptr) { case powerOff: - acquire_bus(); - write_reg(0x0007, 0x0000); - write_reg(0x0010, 0x0000); - write_reg(0x0011, 0x0000); - write_reg(0x0012, 0x0000); - write_reg(0x0013, 0x0000); - release_bus(); - set_backlight(0); + acquire_bus(g); + write_reg(g, 0x07, 0x0000); + write_reg(g, 0x10, 0x0000); + write_reg(g, 0x11, 0x0000); + write_reg(g, 0x12, 0x0000); + write_reg(g, 0x13, 0x0000); + release_bus(g); + set_backlight(g, 0); break; case powerOn: //*************Power On sequence ******************// - acquire_bus(); - write_reg(0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ - write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ - write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + acquire_bus(g); + write_reg(g, 0x10, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(g, 0x11, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x12, 0x0000); /* VREG1OUT voltage */ + write_reg(g, 0x13, 0x0000); /* VDV[4:0] for VCOM amplitude */ gfxSleepMilliseconds(200); /* Dis-charge capacitor power voltage */ - write_reg(0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ - write_reg(0x0011, 0x0147); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x10, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */ + write_reg(g, 0x11, 0x0147); /* DC1[2:0], DC0[2:0], VC[2:0] */ gfxSleepMilliseconds(50); - write_reg(0x0012, 0x013C); /* VREG1OUT voltage */ + write_reg(g, 0x12, 0x013C); /* VREG1OUT voltage */ gfxSleepMilliseconds(50); - write_reg(0x0013, 0x0E00); /* VDV[4:0] for VCOM amplitude */ - write_reg(0x0029, 0x0009); /* VCM[4:0] for VCOMH */ + write_reg(g, 0x13, 0x0E00); /* VDV[4:0] for VCOM amplitude */ + write_reg(g, 0x29, 0x0009); /* VCM[4:0] for VCOMH */ gfxSleepMilliseconds(50); - write_reg(0x0007, 0x0173); /* 262K color and display ON */ - release_bus(); - set_backlight(g->g.Backlight); + write_reg(g, 0x07, 0x0173); /* 262K color and display ON */ + release_bus(g); + set_backlight(g, g->g.Backlight); break; case powerSleep: - acquire_bus(); - write_reg(0x0007, 0x0000); /* display OFF */ - write_reg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ - write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + acquire_bus(g); + write_reg(g, 0x07, 0x0000); /* display OFF */ + write_reg(g, 0x10, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(g, 0x11, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x12, 0x0000); /* VREG1OUT voltage */ + write_reg(g, 0x13, 0x0000); /* VDV[4:0] for VCOM amplitude */ gfxSleepMilliseconds(200); /* Dis-charge capacitor power voltage */ - write_reg(0x0010, 0x0002); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - release_bus(); - gdisp_lld_backlight(0); + write_reg(g, 0x10, 0x0002); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(g); + gdisp_lld_backlight(g, 0); break; case powerDeepSleep: - acquire_bus(); - write_reg(0x0007, 0x0000); /* display OFF */ - write_reg(0x0010, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - write_reg(0x0011, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ - write_reg(0x0012, 0x0000); /* VREG1OUT voltage */ - write_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */ + acquire_bus(g); + write_reg(g, 0x07, 0x0000); /* display OFF */ + write_reg(g, 0x10, 0x0000); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + write_reg(g, 0x11, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */ + write_reg(g, 0x12, 0x0000); /* VREG1OUT voltage */ + write_reg(g, 0x13, 0x0000); /* VDV[4:0] for VCOM amplitude */ gfxSleepMilliseconds(200); /* Dis-charge capacitor power voltage */ - write_reg(0x0010, 0x0004); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ - release_bus(); - gdisp_lld_backlight(0); + write_reg(g, 0x10, 0x0004); /* SAP, BT[3:0], APE, AP, DSTB, SLP */ + release_bus(g); + gdisp_lld_backlight(g, 0); break; default: @@ -292,41 +300,41 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return; switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: - acquire_bus(); - write_reg(0x0001, 0x0100); - write_reg(0x0003, 0x1038); - write_reg(0x0060, 0x2700); - release_bus(); + acquire_bus(g); + write_reg(g, 0x01, 0x0100); + write_reg(g, 0x03, 0x1038); + write_reg(g, 0x60, 0x2700); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: - acquire_bus(); - write_reg(0x0001, 0x0000); - write_reg(0x0003, 0x1030); - write_reg(0x0060, 0x2700); - release_bus(); + acquire_bus(g); + write_reg(g, 0x01, 0x0000); + write_reg(g, 0x03, 0x1030); + write_reg(g, 0x60, 0x2700); + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: - acquire_bus(); - write_reg(0x0001, 0x0000); - write_reg(0x0003, 0x1038); - write_reg(0x0060, 0xa700); - release_bus(); + acquire_bus(g); + write_reg(g, 0x01, 0x0000); + write_reg(g, 0x03, 0x1038); + write_reg(g, 0x60, 0xa700); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: - acquire_bus(); - write_reg(0x0001, 0x0100); - write_reg(0x0003, 0x1030); - write_reg(0x0060, 0xA700); - release_bus(); + acquire_bus(g); + write_reg(g, 0x01, 0x0100); + write_reg(g, 0x03, 0x1030); + write_reg(g, 0x60, 0xA700); + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; @@ -341,7 +349,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; - set_backlight((unsigned)g->p.ptr); + set_backlight(g, (unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; @@ -353,5 +361,3 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif #endif /* GFX_USE_GDISP */ -/** @} */ - diff --git a/drivers/gdisp/ILI9325/gdisp_lld.mk b/drivers/gdisp/ILI9325/gdisp_lld.mk index b5061324..61565164 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld.mk +++ b/drivers/gdisp/ILI9325/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9325/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/ILI9325 +GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9325/gdisp_lld.c diff --git a/drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h b/drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h deleted file mode 100644 index 3e2c269b..00000000 --- a/drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/* - driver quickly hacked together from a chinese sourcecode that came - with the board and existing ili9320 code by Chris van Dongen (sjaak) - (sjaak2002 at msn.com) - - Also added rotation for 180 and 270 degrees and minor tweaks to - setcursor - - Added code comes without warranty and free bugs. Feel free to use - or misuse the added code :D -*/ - - -/** - * @file drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h - * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef GDISP_LLD_BOARD_H -#define GDISP_LLD_BOARD_H - -#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ -#define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ - -static inline void init_board(void) { - /* FSMC setup for F1 */ - rccEnableAHB(RCC_AHBENR_FSMCEN, 0); - - /* set pin modes */ -/* IOBus busD = {GPIOD, PAL_WHOLE_PORT, 0}; - IOBus busE = {GPIOE, PAL_WHOLE_PORT, 0}; - palSetBusMode(&busD, PAL_MODE_STM32_ALTERNATE_PUSHPULL); - palSetBusMode(&busE, PAL_MODE_STM32_ALTERNATE_PUSHPULL); - palSetPadMode(GPIOE, GPIOE_TFT_RST, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, GPIOD_TFT_LIGHT, PAL_MODE_OUTPUT_PUSHPULL); */ - - const unsigned char FSMC_Bank = 0; - - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = (6) | (10 << 8) | (10 << 16); - - /* Bank1 NOR/SRAM control register configuration - * This is actually not needed as already set by default after reset */ - FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; - -} - -static inline void setpin_reset(bool_t state) { - if(state) - palClearPad(GPIOE, GPIOE_TFT_RST); - else - palSetPad(GPIOE, GPIOE_TFT_RST); -} - -static inline void write_index(uint16_t reg) { - GDISP_REG = reg; -} - -static inline void write_data(uint16_t data) { - GDISP_RAM = data; -} - -static inline uint16_t read_data(void) { - return GDISP_RAM; -} - -static inline void set_backlight(uint8_t percent) { - (void)percent; -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Set the bus in read mode - * - * @notapi - */ -static inline void setreadmode(void) { - -} - -/** - * @brief Set the bus back into write mode - * - * @notapi - */ -static inline void setwritemode(void) { - -} - -#endif /* GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/ILI9325/gdisp_lld_board_template.h b/drivers/gdisp/ILI9325/gdisp_lld_board_template.h deleted file mode 100644 index c07b4ba1..00000000 --- a/drivers/gdisp/ILI9325/gdisp_lld_board_template.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/ILI9325/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef GDISP_LLD_BOARD_H -#define GDISP_LLD_BOARD_H - -/** - * @brief Initialise the board for the display. - * - * @notapi - */ -static inline void init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - -} - -/** - * @brief Set the bus in read mode - * - * @notapi - */ -static inline void setreadmode(void) { - -} - -/** - * @brief Set the bus back into write mode - * - * @notapi - */ -static inline void setwritemode(void) { - -} - -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} - -#endif /* GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/ILI9325/gdisp_lld_config.h b/drivers/gdisp/ILI9325/gdisp_lld_config.h index aabf768f..8c586c78 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9325/gdisp_lld_config.h @@ -22,9 +22,6 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "ILI9325" -#define GDISP_DRIVER_STRUCT GDISP_ILI9325 - #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE #define GDISP_HARDWARE_STREAM_POS TRUE From 29cf77746c973f63b694a3b56008173eb208939e Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 17:10:15 +1000 Subject: [PATCH 064/160] Fix doxygen comments. --- drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h | 4 +--- drivers/gdisp/ILI9325/board_ILI9325_template.h | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h index ed697b6f..166ebc33 100644 --- a/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h +++ b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h @@ -19,7 +19,7 @@ /** - * @file drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h + * @file drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display. */ @@ -113,5 +113,3 @@ static inline uint16_t read_data(GDisplay *g) { } #endif /* GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/ILI9325/board_ILI9325_template.h b/drivers/gdisp/ILI9325/board_ILI9325_template.h index 4d54ba34..7b067293 100644 --- a/drivers/gdisp/ILI9325/board_ILI9325_template.h +++ b/drivers/gdisp/ILI9325/board_ILI9325_template.h @@ -6,7 +6,7 @@ */ /** - * @file drivers/gdisp/ILI9325/gdisp_lld_board_template.h + * @file drivers/gdisp/ILI9325/board_ILI9325_template.h * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display. * * @addtogroup GDISP From 443d14c21f10fea9b0c6fc5559ec4c6b31f99546 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 18 Oct 2013 17:29:27 +1000 Subject: [PATCH 065/160] Convert driver ILI9481 to new format --- .../ILI9481/board_ILI9481_firebullstm32f103.h | 109 ++++++++ .../gdisp/ILI9481/board_ILI9481_template.h | 157 +++++++++++ drivers/gdisp/ILI9481/gdisp_lld.c | 243 +++++++++--------- drivers/gdisp/ILI9481/gdisp_lld.mk | 5 +- .../gdisp_lld_board_firebullstm32f103.h | 156 ----------- .../gdisp/ILI9481/gdisp_lld_board_template.h | 123 --------- drivers/gdisp/ILI9481/gdisp_lld_config.h | 3 - 7 files changed, 391 insertions(+), 405 deletions(-) create mode 100644 drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h create mode 100644 drivers/gdisp/ILI9481/board_ILI9481_template.h delete mode 100644 drivers/gdisp/ILI9481/gdisp_lld_board_firebullstm32f103.h delete mode 100644 drivers/gdisp/ILI9481/gdisp_lld_board_template.h diff --git a/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h b/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h new file mode 100644 index 00000000..6614d578 --- /dev/null +++ b/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h @@ -0,0 +1,109 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h + * @brief GDISP Graphics Driver subsystem low level driver source for + * the ILI9481 and compatible HVGA display + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. +#define SET_CS palSetPad(GPIOD, 12); +#define CLR_CS palClearPad(GPIOD, 12); +#define SET_RS palSetPad(GPIOD, 13); +#define CLR_RS palClearPad(GPIOD, 13); +#define SET_WR palSetPad(GPIOD, 14); +#define CLR_WR palClearPad(GPIOD, 14); +#define SET_RD palSetPad(GPIOD, 15); +#define CLR_RD palClearPad(GPIOD, 15); + +static inline void init_board(GDisplay *g, unsigned display) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + if (display == 0) { + + /** + * Set up for Display 0 + */ + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, 12, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, 13, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, 14, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOD, 15, PAL_MODE_OUTPUT_PUSHPULL); + + // Configure the pins to a well know state + SET_RS; + SET_RD; + SET_WR; + CLR_CS; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + palWritePort(GPIOE, index); + CLR_RS; CLR_WR; SET_WR; SET_RS; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + palWritePort(GPIOE, data); + CLR_WR; SET_WR; +} + +static inline void setreadmode(GDisplay *g) { + (void) g; + // change pin mode to digital input + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); +} + +static inline void setwritemode(GDisplay *g) { + (void) g; + // change pin mode back to digital output + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); +} + +static inline uint16_t read_data(GDisplay *g) { + uint16_t value; + (void) g; + + CLR_RD; + value = palReadPort(GPIOE); + SET_RD; + + return value; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/ILI9481/board_ILI9481_template.h b/drivers/gdisp/ILI9481/board_ILI9481_template.h new file mode 100644 index 00000000..f3f8bbb7 --- /dev/null +++ b/drivers/gdisp/ILI9481/board_ILI9481_template.h @@ -0,0 +1,157 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9481/board_ILI9481_template.h + * @brief GDISP Graphics Driver subsystem low level driver source for + * the ILI9481 and compatible HVGA display + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * @param[in] display The display number on this controller (0..n) + * + * @note Set the g->priv member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g, unsigned display) { + (void) g; + (void) display; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Set the lcd back-light level. + * + * @param[in] g The GDisplay structure + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; +} + +/** + * @brief Set the bus in read mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +/** + * @brief Set the bus back into write mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +/** + * @brief Read data from the lcd. + * @return The data from the lcd + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return 0; +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/ILI9481/gdisp_lld.c b/drivers/gdisp/ILI9481/gdisp_lld.c index a70b7c03..06a9e681 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld.c +++ b/drivers/gdisp/ILI9481/gdisp_lld.c @@ -24,9 +24,11 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_LLD_DECLARATIONS +#define GDISP_DRIVER_VMT GDISPVMT_ILI9481 +#include "../drivers/gdisp/ILI9481/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" -#include "gdisp_lld_board.h" + +#include "board_ILI9481.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -50,14 +52,14 @@ /*===========================================================================*/ // Some common routines and macros -#define dummy_read() { volatile uint16_t dummy; dummy = read_data(); (void) dummy; } -#define write_reg(reg, data) { write_index(reg); write_data(data); } -#define write_reg2x16(reg, data1, data2) { write_index(reg); write_data((data1)>>8); write_data((uint8_t)(data1)); write_data((data2)>>8); write_data((uint8_t)(data2));} +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } +#define write_reg2x16(g, reg, data1, data2) { write_index(g, reg); write_data(g, (data1)>>8); write_data(g, (uint8_t)(data1)); write_data(g, (data2)>>8); write_data(g, (uint8_t)(data2));} -static void set_viewport(GDISPDriver* g) { - write_reg2x16(0x2A, g->p.x, g->p.x + g->p.cx - 1); - write_reg2x16(0x2B, g->p.y, g->p.y + g->p.cy - 1); - write_index(0x2C); +static void set_viewport(GDisplay* g) { + write_reg2x16(g, 0x2A, g->p.x, g->p.x + g->p.cx - 1); + write_reg2x16(g, 0x2B, g->p.y, g->p.y + g->p.cy - 1); + write_index(g, 0x2C); } /*===========================================================================*/ @@ -68,124 +70,127 @@ static void set_viewport(GDISPDriver* g) { /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { /* Initialise your display */ - init_board(); + init_board(g, display); /* Hardware reset */ - setpin_reset(TRUE); + setpin_reset(g, TRUE); gfxSleepMilliseconds(20); - setpin_reset(FALSE); + setpin_reset(g, FALSE); gfxSleepMilliseconds(20); /* Get the bus for the following initialisation commands */ - acquire_bus(); + acquire_bus(g); /* Enable Access to all Manufacturer commands (0xB0 and higher opcodes) */ - write_reg(0xB0, 0x00); + write_reg(g, 0xB0, 0x00); /* Frame Memory Access and Interface Setting */ - write_index(0xB3); - write_data(0x02); - write_data(0x00); - write_data(0x00); - write_data(0x10); + write_index(g, 0xB3); + write_data(g, 0x02); + write_data(g, 0x00); + write_data(g, 0x00); + write_data(g, 0x10); /* Display Mode and Frame Memory Write Mode Setting (B4h) */ /* Use internal clock for synchronization */ /* Use DBI interface (only DB0-17, no HSYNC, VSYNC or CLK) */ - write_reg(0xB4, 0x00); + write_reg(g, 0xB4, 0x00); /* Internal Backlight Control */ -/* write_index(0xB9); /*PWM Settings for Brightness Control */ -/* write_data(0x01); /* Disabled by default. */ -/* write_data(0xFF); /*0xFF = Max brightness */ -/* write_data(0xFF); -/* write_data(0x18); +/* write_index(g, 0xB9); // PWM Settings for Brightness Control + write_data(g, 0x01); // Disabled by default. + write_data(g, 0xFF); // 0xFF = Max brightness + write_data(g, 0xFF); + write_data(g, 0x18); */ /* Panel Driving settings */ - write_index(0xC0); - write_data(0x03); - write_data(0x3B); - write_data(0x00); - write_data(0x00); - write_data(0x00); - write_data(0x01); - write_data(0x00); /* NW */ - write_data(0x43); + write_index(g, 0xC0); + write_data(g, 0x03); + write_data(g, 0x3B); + write_data(g, 0x00); + write_data(g, 0x00); + write_data(g, 0x00); + write_data(g, 0x01); + write_data(g, 0x00); /* NW */ + write_data(g, 0x43); /* Display timings in Operating Mode */ - write_index(0xC1); - write_data(0x08); - write_data(0x15); /* CLOCK */ - write_data(0x08); - write_data(0x08); + write_index(g, 0xC1); + write_data(g, 0x08); + write_data(g, 0x15); /* CLOCK */ + write_data(g, 0x08); + write_data(g, 0x08); /* S/VCOM/Gate Driving timing setting */ - write_index(0xC4); - write_data(0x15); - write_data(0x03); - write_data(0x03); - write_data(0x01); + write_index(g, 0xC4); + write_data(g, 0x15); + write_data(g, 0x03); + write_data(g, 0x03); + write_data(g, 0x01); /* Interface Setting */ - write_reg(0xC6, 0x02); + write_reg(g, 0xC6, 0x02); /* Gamma Setting - should be changed if using a different panel */ - write_index(0xC8); - write_data(0x0C); - write_data(0x05); - write_data(0x0A); /*0X12 */ - write_data(0x6B); /*0x7D */ - write_data(0x04); - write_data(0x06); /*0x08 */ - write_data(0x15); /*0x0A */ - write_data(0x10); - write_data(0x00); - write_data(0x60); /*0x23 */ + write_index(g, 0xC8); + write_data(g, 0x0C); + write_data(g, 0x05); + write_data(g, 0x0A); /*0X12 */ + write_data(g, 0x6B); /*0x7D */ + write_data(g, 0x04); + write_data(g, 0x06); /*0x08 */ + write_data(g, 0x15); /*0x0A */ + write_data(g, 0x10); + write_data(g, 0x00); + write_data(g, 0x60); /*0x23 */ /* Address Mode setting */ - write_reg(0x36, 0x00); + write_reg(g, 0x36, 0x00); /* Set Pixel Format = 16 bits per pixel */ /* The driver supports upto 24 bits per pixel, with dither */ - write_reg(0x3A, 0x55); + write_reg(g, 0x3A, 0x55); /* Exit Idle Mode */ - write_index(0x38); + write_index(g, 0x38); /* Power Setting */ - write_index(0xD0); - write_data(0x07); - write_data(0x07); /* VCI = VCI1 */ - write_data(0x14); /* VRH 0x1D */ - write_data(0xA2); /* BT 0x06 */ + write_index(g, 0xD0); + write_data(g, 0x07); + write_data(g, 0x07); /* VCI = VCI1 */ + write_data(g, 0x14); /* VRH 0x1D */ + write_data(g, 0xA2); /* BT 0x06 */ /* VCOM Setting */ - write_index(0xD1); - write_data(0x03); - write_data(0x5A); /* VCM 0x5A */ - write_data(0x10); /* VDV */ + write_index(g, 0xD1); + write_data(g, 0x03); + write_data(g, 0x5A); /* VCM 0x5A */ + write_data(g, 0x10); /* VDV */ /* Power Setting for Normal Mode */ - write_index(0xD2); - write_data(0x03); - write_data(0x04); /* 0x24 */ - write_data(0x04); + write_index(g, 0xD2); + write_data(g, 0x03); + write_data(g, 0x04); /* 0x24 */ + write_data(g, 0x04); /* Exit Sleep Mode */ - write_index(0x11); + write_index(g, 0x11); gfxSleepMilliseconds(150); /* Display ON */ - write_index(0x29); + write_index(g, 0x29); gfxSleepMilliseconds(30); - /* Release the bus */ - release_bus(); + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); /* Turn on the back-light */ - set_backlight(GDISP_INITIAL_BACKLIGHT); + set_backlight(g, GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure */ g->g.Width = GDISP_SCREEN_WIDTH; @@ -198,57 +203,57 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } #if GDISP_HARDWARE_STREAM_WRITE - LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); set_viewport(g); } - LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { - write_data(g->p.color); + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, g->p.color); } - LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { - release_bus(); + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); } #endif #if GDISP_HARDWARE_STREAM_READ - LLDSPEC void gdisp_lld_read_start(GDISPDriver *g) { - acquire_bus(); + LLDSPEC void gdisp_lld_read_start(GDisplay *g) { + acquire_bus(g); set_viewport(g); - setreadmode(); - dummy_read(); + setreadmode(g); + dummy_read(g); } - LLDSPEC color_t gdisp_lld_read_color(GDISPDriver *g) { - return read_data(); + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { + return read_data(g); } - LLDSPEC void gdisp_lld_read_stop(GDISPDriver *g) { - setwritemode(); - release_bus(); + LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { + setwritemode(g); + release_bus(g); } #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + LLDSPEC void gdisp_lld_control(GDisplay *g) { switch(g->p.x) { case GDISP_CONTROL_POWER: if (g->g.Powermode == (powermode_t)g->p.ptr) return; switch((powermode_t)g->p.ptr) { case powerOff: - acquire_bus(); - write_reg(0x0010, 0x0001); /* enter sleep mode */ - release_bus(); + acquire_bus(g); + write_reg(g, 0x0010, 0x0001); /* enter sleep mode */ + release_bus(g); break; case powerOn: - acquire_bus(); - write_reg(0x0010, 0x0000); /* leave sleep mode */ - release_bus(); + acquire_bus(g); + write_reg(g, 0x0010, 0x0000); /* leave sleep mode */ + release_bus(g); if (g->g.Powermode != powerSleep) gdisp_lld_init(); break; case powerSleep: - acquire_bus(); - write_reg(0x0010, 0x0001); /* enter sleep mode */ - release_bus(); + acquire_bus(g); + write_reg(g, 0x0010, 0x0001); /* enter sleep mode */ + release_bus(g); break; default: return; @@ -261,42 +266,42 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return; switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: - acquire_bus(); + acquire_bus(g); - write_reg(0xC0, 0x03); - write_reg(0x36, 0x00); /* X and Y axes non-inverted */ + write_reg(g, 0xC0, 0x03); + write_reg(g, 0x36, 0x00); /* X and Y axes non-inverted */ - release_bus(); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: - acquire_bus(); + acquire_bus(g); - write_reg(0xC0, 0x02); - write_reg(0x36, 0x20); /* Invert X and Y axes */ + write_reg(g, 0xC0, 0x02); + write_reg(g, 0x36, 0x20); /* Invert X and Y axes */ - release_bus(); + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: - acquire_bus(); + acquire_bus(g); - write_reg(0xC0, 0x06); - write_reg(0x36, 0x00); /* X and Y axes non-inverted */ + write_reg(g, 0xC0, 0x06); + write_reg(g, 0x36, 0x00); /* X and Y axes non-inverted */ - release_bus(); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: - acquire_bus(); + acquire_bus(g); - write_reg(0xC0, 0x07); - write_reg(0x36, 0x20); /* Invert X and Y axes */ + write_reg(g, 0xC0, 0x07); + write_reg(g, 0x36, 0x20); /* Invert X and Y axes */ - release_bus(); + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; diff --git a/drivers/gdisp/ILI9481/gdisp_lld.mk b/drivers/gdisp/ILI9481/gdisp_lld.mk index b0b3f533..6af4d1f8 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld.mk +++ b/drivers/gdisp/ILI9481/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9481/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/ILI9481 +GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9481/gdisp_lld.c diff --git a/drivers/gdisp/ILI9481/gdisp_lld_board_firebullstm32f103.h b/drivers/gdisp/ILI9481/gdisp_lld_board_firebullstm32f103.h deleted file mode 100644 index 7270cdaf..00000000 --- a/drivers/gdisp/ILI9481/gdisp_lld_board_firebullstm32f103.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/ILI9481/gdisp_lld_board_firebullstm32f103.h - * @brief GDISP Graphics Driver subsystem low level driver source for - * the ILI9481 and compatible HVGA display - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -#define SET_CS palSetPad(GPIOD, 12); -#define CLR_CS palClearPad(GPIOD, 12); -#define SET_RS palSetPad(GPIOD, 13); -#define CLR_RS palClearPad(GPIOD, 13); -#define SET_WR palSetPad(GPIOD, 14); -#define CLR_WR palClearPad(GPIOD, 14); -#define SET_RD palSetPad(GPIOD, 15); -#define CLR_RD palClearPad(GPIOD, 15); - -/** - * @brief Initialise the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins - * - * @notapi - */ -static inline void init_board(void) { - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, 12, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, 13, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, 14, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOD, 15, PAL_MODE_OUTPUT_PUSHPULL); - - // Configure the pins to a well know state - SET_RS; - SET_RD; - SET_WR; - CLR_CS; -} - - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - (void) state; - /* Nothing to do here - reset pin tied to Vcc */ -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - (void) percent; - /* Nothing to do here - Backlight always on */ -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - palWritePort(GPIOE, index); - CLR_RS; CLR_WR; SET_WR; SET_RS; -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - palWritePort(GPIOE, data); - CLR_WR; SET_WR; -} - -/** - * @brief Set the bus in read mode - * - * @notapi - */ -static inline void setreadmode(void) { - // change pin mode to digital input - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); -} - -/** - * @brief Set the bus back into write mode - * - * @notapi - */ -static inline void setwritemode(void) { - // change pin mode back to digital output - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); -} - -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - uint16_t value; - - CLR_RD; - value = palReadPort(GPIOE); - SET_RD; - - return value; -} - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/ILI9481/gdisp_lld_board_template.h b/drivers/gdisp/ILI9481/gdisp_lld_board_template.h deleted file mode 100644 index e35f0c27..00000000 --- a/drivers/gdisp/ILI9481/gdisp_lld_board_template.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/ILI9481/gdisp_lld_board_template.h - * @brief GDISP Graphics Driver subsystem low level driver source for - * the ILI9481 and compatible HVGA display - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief Initialise the board for the display. - * - * @notapi - */ -static inline void init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - -} - -/** - * @brief Set the bus in read mode - * - * @notapi - */ -static inline void setreadmode(void) { - -} - -/** - * @brief Set the bus back into write mode - * - * @notapi - */ -static inline void setwritemode(void) { - -} - -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/ILI9481/gdisp_lld_config.h b/drivers/gdisp/ILI9481/gdisp_lld_config.h index c41edd6b..4a33d110 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9481/gdisp_lld_config.h @@ -23,9 +23,6 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "ILI9481" -#define GDISP_DRIVER_STRUCT GDISP_ILI9481 - #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE #define GDISP_HARDWARE_CONTROL TRUE From 87a6af81f4edd9f638238d785aae716749a7fc13 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 19 Oct 2013 15:36:05 +1000 Subject: [PATCH 066/160] Change to gdisp low level driver API. Display number is now in the GDriver structure (It was required for a Nokia driver). --- .../HX8347D/board_HX8347D_stm32f4discovery.h | 11 +++----- .../gdisp/HX8347D/board_HX8347D_template.h | 4 +-- drivers/gdisp/HX8347D/gdisp_lld.c | 4 +-- .../board_ILI9320_olimex_pic32mx_lcd.h | 11 +++----- .../ILI9320/board_ILI9320_olimex_stm32_lcd.h | 11 +++----- .../gdisp/ILI9320/board_ILI9320_template.h | 4 +-- drivers/gdisp/ILI9320/gdisp_lld.c | 4 +-- .../ILI9325/board_ILI9325_hy_stm32_100p.h | 11 +++----- .../gdisp/ILI9325/board_ILI9325_template.h | 4 +-- drivers/gdisp/ILI9325/gdisp_lld.c | 4 +-- .../ILI9481/board_ILI9481_firebullstm32f103.h | 10 +++----- .../gdisp/ILI9481/board_ILI9481_template.h | 4 +-- drivers/gdisp/ILI9481/gdisp_lld.c | 4 +-- drivers/gdisp/RA8875/board_RA8875_marlin.h | 11 +++----- drivers/gdisp/RA8875/board_RA8875_template.h | 25 +++++++++++-------- drivers/gdisp/RA8875/gdisp_lld.c | 4 +-- .../SSD1289/board_SSD1289_firebullstm32f103.h | 10 +++----- .../SSD1289/board_SSD1289_stm32f4discovery.h | 9 +++---- .../gdisp/SSD1289/board_SSD1289_template.h | 4 +-- drivers/gdisp/SSD1289/gdisp_lld.c | 4 +-- drivers/multiple/Win32/gdisp_lld.c | 10 ++++---- drivers/multiple/X/gdisp_lld.c | 4 +-- include/gdisp/lld/gdisp_lld.h | 13 +++++----- src/gdisp/gdisp.c | 10 +++++--- 24 files changed, 84 insertions(+), 106 deletions(-) diff --git a/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h index 4899baa5..daabe75d 100644 --- a/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h +++ b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h @@ -64,17 +64,13 @@ static const SPIConfig spi1cfg_16bit = { SPI_CR1_DFF //SPI_CR1_BR_0 }; -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->priv to NULL as we don't use it. g->priv = 0; - if (display == 0) { - - /** - * Set up for Display 0 - */ - + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 /* Display backlight control */ /* TIM4 is an alternate function 2 (AF2) */ pwmStart(&PWMD4, &pwmcfg); @@ -96,6 +92,7 @@ static inline void init_board(GDisplay *g, unsigned display) { palSetPadMode(GPIOA, 5, PAL_MODE_ALTERNATE(5)|PAL_STM32_OSPEED_HIGHEST); /* SCK. */ palSetPadMode(GPIOA, 6, PAL_MODE_ALTERNATE(5)); /* MISO. */ palSetPadMode(GPIOA, 7, PAL_MODE_ALTERNATE(5)|PAL_STM32_OSPEED_HIGHEST); /* MOSI. */ + break; } } diff --git a/drivers/gdisp/HX8347D/board_HX8347D_template.h b/drivers/gdisp/HX8347D/board_HX8347D_template.h index 528fb027..58fd9338 100644 --- a/drivers/gdisp/HX8347D/board_HX8347D_template.h +++ b/drivers/gdisp/HX8347D/board_HX8347D_template.h @@ -20,16 +20,14 @@ * @brief Initialise the board for the display. * * @param[in] g The GDisplay structure - * @param[in] display The display number on this controller (0..n) * * @note Set the g->priv member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi */ -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { (void) g; - (void) display; } /** diff --git a/drivers/gdisp/HX8347D/gdisp_lld.c b/drivers/gdisp/HX8347D/gdisp_lld.c index 19d1b822..8cdbb781 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld.c +++ b/drivers/gdisp/HX8347D/gdisp_lld.c @@ -61,9 +61,9 @@ static inline void set_viewport(GDisplay* g) { /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Initialise your display */ - init_board(g, display); + init_board(g); // Hardware reset setpin_reset(g, TRUE); diff --git a/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h b/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h index 81d493ed..cf101aaf 100644 --- a/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h +++ b/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h @@ -17,17 +17,13 @@ #define noinline __attribute__((noinline)) #endif -static void init_board(GDisplay *g, unsigned display) { +static void init_board(GDisplay *g) { // As we are not using multiple displays we set g->priv to NULL as we don't use it. g->priv = 0; - if (display == 0) { - - /** - * Set up for Display 0 - */ - + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 // RST palSetPadMode(IOPORTA, 7, PAL_MODE_OUTPUT); palClearPad(IOPORTA, 7); @@ -59,6 +55,7 @@ static void init_board(GDisplay *g, unsigned display) { PMCONbits.PMPEN = 1; palClearPad(IOPORTA, 9); + break; } } diff --git a/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h b/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h index df02a716..4738db61 100644 --- a/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h +++ b/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h @@ -18,17 +18,13 @@ #define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ #define GDISP_RAM (*((volatile uint16_t *) 0x60100000)) /* RS = 1 */ -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->priv to NULL as we don't use it. g->priv = 0; - if (display == 0) { - - /** - * Set up for Display 0 - */ - + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 /* FSMC setup for F1 */ rccEnableAHB(RCC_AHBENR_FSMCEN, 0); @@ -46,6 +42,7 @@ static inline void init_board(GDisplay *g, unsigned display) { /* Bank1 NOR/SRAM control register configuration * This is actually not needed as already set by default after reset */ FSMC_Bank1->BTCR[0] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + break; } } diff --git a/drivers/gdisp/ILI9320/board_ILI9320_template.h b/drivers/gdisp/ILI9320/board_ILI9320_template.h index ead9aee0..4725e1eb 100644 --- a/drivers/gdisp/ILI9320/board_ILI9320_template.h +++ b/drivers/gdisp/ILI9320/board_ILI9320_template.h @@ -20,16 +20,14 @@ * @brief Initialise the board for the display. * * @param[in] g The GDisplay structure - * @param[in] display The display number on this controller (0..n) * * @note Set the g->priv member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi */ -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { (void) g; - (void) display; } /** diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index 3747b3d7..d4639617 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -95,11 +95,11 @@ static void set_viewport(GDisplay *g) { } } -LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { uint16_t cver; /* Initialise your display */ - init_board(g, display); + init_board(g); /* Hardware reset */ setpin_reset(g, TRUE); diff --git a/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h index 166ebc33..ae9e96fc 100644 --- a/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h +++ b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h @@ -31,17 +31,13 @@ #define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ #define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->priv to NULL as we don't use it. g->priv = 0; - if (display == 0) { - - /** - * Set up for Display 0 - */ - + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 /* FSMC setup for F1 */ rccEnableAHB(RCC_AHBENR_FSMCEN, 0); @@ -61,6 +57,7 @@ static inline void init_board(GDisplay *g, unsigned display) { /* Bank1 NOR/SRAM control register configuration * This is actually not needed as already set by default after reset */ FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + break; } } diff --git a/drivers/gdisp/ILI9325/board_ILI9325_template.h b/drivers/gdisp/ILI9325/board_ILI9325_template.h index 7b067293..65ab5704 100644 --- a/drivers/gdisp/ILI9325/board_ILI9325_template.h +++ b/drivers/gdisp/ILI9325/board_ILI9325_template.h @@ -20,16 +20,14 @@ * @brief Initialise the board for the display. * * @param[in] g The GDisplay structure - * @param[in] display The display number on this controller (0..n) * * @note Set the g->priv member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi */ -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { (void) g; - (void) display; } /** diff --git a/drivers/gdisp/ILI9325/gdisp_lld.c b/drivers/gdisp/ILI9325/gdisp_lld.c index 42acdc46..8a4b8603 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld.c +++ b/drivers/gdisp/ILI9325/gdisp_lld.c @@ -96,11 +96,11 @@ static void set_viewport(GDisplay* g) { } } -LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { uint16_t cver; /* Initialise your display */ - init_board(g, display); + init_board(g); /* Hardware reset */ setpin_reset(g, TRUE); diff --git a/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h b/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h index 6614d578..9933d17b 100644 --- a/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h +++ b/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h @@ -25,16 +25,13 @@ #define SET_RD palSetPad(GPIOD, 15); #define CLR_RD palClearPad(GPIOD, 15); -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->priv to NULL as we don't use it. g->priv = 0; - if (display == 0) { - - /** - * Set up for Display 0 - */ + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); palSetPadMode(GPIOD, 12, PAL_MODE_OUTPUT_PUSHPULL); palSetPadMode(GPIOD, 13, PAL_MODE_OUTPUT_PUSHPULL); @@ -46,6 +43,7 @@ static inline void init_board(GDisplay *g, unsigned display) { SET_RD; SET_WR; CLR_CS; + break; } } diff --git a/drivers/gdisp/ILI9481/board_ILI9481_template.h b/drivers/gdisp/ILI9481/board_ILI9481_template.h index f3f8bbb7..8dcee19c 100644 --- a/drivers/gdisp/ILI9481/board_ILI9481_template.h +++ b/drivers/gdisp/ILI9481/board_ILI9481_template.h @@ -21,16 +21,14 @@ * @brief Initialise the board for the display. * * @param[in] g The GDisplay structure - * @param[in] display The display number on this controller (0..n) * * @note Set the g->priv member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi */ -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { (void) g; - (void) display; } /** diff --git a/drivers/gdisp/ILI9481/gdisp_lld.c b/drivers/gdisp/ILI9481/gdisp_lld.c index 06a9e681..fc00be10 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld.c +++ b/drivers/gdisp/ILI9481/gdisp_lld.c @@ -70,9 +70,9 @@ static void set_viewport(GDisplay* g) { /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Initialise your display */ - init_board(g, display); + init_board(g); /* Hardware reset */ setpin_reset(g, TRUE); diff --git a/drivers/gdisp/RA8875/board_RA8875_marlin.h b/drivers/gdisp/RA8875/board_RA8875_marlin.h index 95fb7f9d..88523060 100644 --- a/drivers/gdisp/RA8875/board_RA8875_marlin.h +++ b/drivers/gdisp/RA8875/board_RA8875_marlin.h @@ -20,17 +20,13 @@ #define FSMC_BANK 4 -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->priv to NULL as we don't use it. g->priv = 0; - if (display == 0) { - - /** - * Set up for Display 0 - */ - + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 /* set pins to FSMC mode */ IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; @@ -52,6 +48,7 @@ static inline void init_board(GDisplay *g, unsigned display) { /* Bank1 NOR/SRAM control register configuration * This is actually not needed as already set by default after reset */ FSMC_Bank1->BTCR[FSMC_BANK] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + break; } } diff --git a/drivers/gdisp/RA8875/board_RA8875_template.h b/drivers/gdisp/RA8875/board_RA8875_template.h index 564f60c0..32d12de5 100644 --- a/drivers/gdisp/RA8875/board_RA8875_template.h +++ b/drivers/gdisp/RA8875/board_RA8875_template.h @@ -20,14 +20,14 @@ * @brief Initialise the board for the display. * * @param[in] g The GDisplay structure - * @param[in] display The display number on this controller (0..n) * * @note Set the g->priv member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi */ -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { + (void) g; } /** @@ -38,6 +38,7 @@ static inline void init_board(GDisplay *g, unsigned display) { * @notapi */ static inline void post_init_board(GDisplay *g) { + (void) g; } /** @@ -49,7 +50,8 @@ static inline void post_init_board(GDisplay *g) { * @notapi */ static inline void setpin_reset(GDisplay *g, bool_t state) { - + (void) g; + (void) state; } /** @@ -60,7 +62,7 @@ static inline void setpin_reset(GDisplay *g, bool_t state) { * @notapi */ static inline void acquire_bus(GDisplay *g) { - + (void) g; } /** @@ -71,7 +73,7 @@ static inline void acquire_bus(GDisplay *g) { * @notapi */ static inline void release_bus(GDisplay *g) { - + (void) g; } /** @@ -83,7 +85,8 @@ static inline void release_bus(GDisplay *g) { * @notapi */ static inline void write_index(GDisplay *g, uint16_t index) { - + (void) g; + (void) index; } /** @@ -95,7 +98,8 @@ static inline void write_index(GDisplay *g, uint16_t index) { * @notapi */ static inline void write_data(GDisplay *g, uint16_t data) { - + (void) g; + (void) data; } /** @@ -106,7 +110,7 @@ static inline void write_data(GDisplay *g, uint16_t data) { * @notapi */ static inline void setreadmode(GDisplay *g) { - + (void) g; } /** @@ -117,7 +121,7 @@ static inline void setreadmode(GDisplay *g) { * @notapi */ static inline void setwritemode(GDisplay *g) { - + (void) g; } /** @@ -132,9 +136,8 @@ static inline void setwritemode(GDisplay *g) { * @notapi */ static inline uint16_t read_data(GDisplay *g) { - + (void) g; } #endif /* _GDISP_LLD_BOARD_H */ /** @} */ - diff --git a/drivers/gdisp/RA8875/gdisp_lld.c b/drivers/gdisp/RA8875/gdisp_lld.c index 4c146321..6697d9fd 100644 --- a/drivers/gdisp/RA8875/gdisp_lld.c +++ b/drivers/gdisp/RA8875/gdisp_lld.c @@ -106,9 +106,9 @@ static inline void set_backlight(GDisplay* g, uint8_t percent) { /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Initialise your display */ - init_board(g, display); + init_board(g); // Hardware reset setpin_reset(g, TRUE); diff --git a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h index df7594f8..338d9799 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h @@ -24,16 +24,13 @@ #define SET_RD palSetPad(GPIOD, 15); #define CLR_RD palClearPad(GPIOD, 15); -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->priv to NULL as we don't use it. g->priv = 0; - if (display == 0) { - - /** - * Set up for Display 0 - */ + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); palSetPadMode(GPIOD, 12, PAL_MODE_OUTPUT_PUSHPULL); palSetPadMode(GPIOD, 13, PAL_MODE_OUTPUT_PUSHPULL); @@ -45,6 +42,7 @@ static inline void init_board(GDisplay *g, unsigned display) { SET_RD; SET_WR; CLR_CS; + break; } } diff --git a/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h index 84082089..d1e23c4a 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h @@ -34,16 +34,14 @@ static const PWMConfig pwmcfg = { 0 }; -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->priv to NULL as we don't use it. g->priv = 0; - if (display == 0) { - + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 /** - * Set up for Display 0 - * * Performs the following functions: * 1. initialise the io port used by the display * 2. initialise the reset pin (initial state not-in-reset) @@ -95,6 +93,7 @@ static inline void init_board(GDisplay *g, unsigned display) { pwmStart(&PWMD3, &pwmcfg); palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATE(2)); pwmEnableChannel(&PWMD3, 2, 100); + break; } } diff --git a/drivers/gdisp/SSD1289/board_SSD1289_template.h b/drivers/gdisp/SSD1289/board_SSD1289_template.h index b24789ea..8bef95b9 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_template.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_template.h @@ -20,16 +20,14 @@ * @brief Initialise the board for the display. * * @param[in] g The GDisplay structure - * @param[in] display The display number on this controller (0..n) * * @note Set the g->priv member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi */ -static inline void init_board(GDisplay *g, unsigned display) { +static inline void init_board(GDisplay *g) { (void) g; - (void) display; } /** diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index dca11d5d..b376083c 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -114,9 +114,9 @@ static void set_viewport(GDisplay* g) { /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Initialise your display */ - init_board(g, display); + init_board(g); // Hardware reset setpin_reset(g, TRUE); diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index dae92821..6c2e7f33 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -381,7 +381,7 @@ static DECLARE_THREAD_FUNCTION(WindowThread, param) { /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { winPriv * priv; char buf[132]; @@ -426,13 +426,13 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { // Turn on toggles for the first GINPUT_TOGGLE_CONFIG_ENTRIES windows #if GINPUT_NEED_TOGGLE - if (display < GINPUT_TOGGLE_CONFIG_ENTRIES) + if (g->controllerdisplay < GINPUT_TOGGLE_CONFIG_ENTRIES) g->flags |= GDISP_FLG_HASTOGGLE; #endif // Only turn on mouse on the first window for now #if GINPUT_NEED_MOUSE - if (!display) + if (!g->controllerdisplay) g->flags |= GDISP_FLG_HASMOUSE; #endif @@ -443,13 +443,13 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { g->priv = priv; // Create the window in the message thread - PostThreadMessage(winThreadId, WM_USER, (WPARAM)display, (LPARAM)g); + PostThreadMessage(winThreadId, WM_USER, (WPARAM)g->controllerdisplay, (LPARAM)g); // Wait for the window creation to complete (for safety) while(!(((volatile GDisplay *)g)->flags & GDISP_FLG_READY)) Sleep(1); - sprintf(buf, APP_NAME " - %u", display+1); + sprintf(buf, APP_NAME " - %u", g->systemdisplay+1); SetWindowText(priv->hwnd, buf); ShowWindow(priv->hwnd, SW_SHOW); UpdateWindow(priv->hwnd); diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld.c index fc573c87..188724ed 100644 --- a/drivers/multiple/X/gdisp_lld.c +++ b/drivers/multiple/X/gdisp_lld.c @@ -145,7 +145,7 @@ static int FatalXIOError(Display *d) { exit(0); } -LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { XSizeHints *pSH; XSetWindowAttributes xa; XTextProperty WindowTitle; @@ -208,7 +208,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display) { { char buf[132]; - sprintf(buf, "uGFX - %u", display+1); + sprintf(buf, "uGFX - %u", g->systemdisplay+1); WindowTitleText = buf; XStringListToTextProperty(&WindowTitleText, 1, &WindowTitle); XSetWMName(dis, priv->win, &WindowTitle); diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 1a08b330..442e9b6d 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -172,7 +172,8 @@ /*===========================================================================*/ struct GDisplay { - GDISPControl g; // The public GDISP stuff - must be the first element + // The public GDISP stuff - must be the first element + GDISPControl g; #if GDISP_TOTAL_CONTROLLERS > 1 const struct GDISPVMT const * vmt; // The Virtual Method Table @@ -180,7 +181,8 @@ struct GDisplay { void * priv; // A private area just for the drivers use. - + uint8_t systemdisplay; + uint8_t controllerdisplay; uint16_t flags; #define GDISP_FLG_INSTREAM 0x0001 // We are in a user based stream operation #define GDISP_FLG_SCRSTREAM 0x0002 // The stream area currently covers the whole screen @@ -241,10 +243,9 @@ struct GDisplay { * @brief Initialize the driver. * @return TRUE if successful. * @param[in] g The driver structure - * @param[in] display The display number for this controller 0..n * @param[out] g->g The driver must fill in the GDISPControl structure */ - LLDSPEC bool_t gdisp_lld_init(GDisplay *g, unsigned display); + LLDSPEC bool_t gdisp_lld_init(GDisplay *g); #if GDISP_HARDWARE_STREAM_WRITE || defined(__DOXYGEN__) /** @@ -477,7 +478,7 @@ struct GDisplay { #if GDISP_TOTAL_CONTROLLERS > 1 typedef struct GDISPVMT { - bool_t (*init)(GDisplay *g, unsigned display); + bool_t (*init)(GDisplay *g); void (*writestart)(GDisplay *g); // Uses p.x,p.y p.cx,p.cy void (*writepos)(GDisplay *g); // Uses p.x,p.y void (*writecolor)(GDisplay *g); // Uses p.color @@ -569,7 +570,7 @@ struct GDisplay { }}; #else - #define gdisp_lld_init(g, display) g->vmt->init(g, display) + #define gdisp_lld_init(g) g->vmt->init(g) #define gdisp_lld_write_start(g) g->vmt->writestart(g) #define gdisp_lld_write_pos(g) g->vmt->writepos(g) #define gdisp_lld_write_color(g) g->vmt->writecolor(g) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index ef388df5..66cd59fd 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -493,9 +493,9 @@ static void line_clip(GDisplay *g) { /* Our module initialiser */ void _gdispInit(void) { GDisplay *g; - unsigned i; + uint16_t i; #if GDISP_TOTAL_CONTROLLERS > 1 - unsigned j; + uint16_t j; #endif @@ -504,13 +504,17 @@ void _gdispInit(void) { for(g = GDisplayArray, j=0; j < GDISP_TOTAL_CONTROLLERS; j++) for(i = 0; i < DisplayCountList[j]; g++, i++) { g->vmt = ControllerList[j]; + g->systemdisplay = j*GDISP_TOTAL_CONTROLLERS+i; + g->controllerdisplay = i; #else for(g = GDisplayArray, i = 0; i < GDISP_TOTAL_DISPLAYS; g++, i++) { + g->systemdisplay = i; + g->controllerdisplay = i; #endif MUTEX_INIT(g); MUTEX_ENTER(g); g->flags = 0; - gdisp_lld_init(g, i); + gdisp_lld_init(g); // Set the initial clipping region #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP From e9895b5d14714683b1a98f8d24028d94e22b4bb5 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 19 Oct 2013 15:38:00 +1000 Subject: [PATCH 067/160] Convert Nokia6610GE12 driver to new format. --- ... => board_Nokia6610GE12_olimexsam7ex256.h} | 458 +++++++++--------- ...plate.h => board_Nokia6610GE12_template.h} | 99 ++-- drivers/gdisp/Nokia6610GE12/gdisp_lld.c | 138 +++--- drivers/gdisp/Nokia6610GE12/gdisp_lld.mk | 5 +- .../gdisp/Nokia6610GE12/gdisp_lld_config.h | 8 - 5 files changed, 349 insertions(+), 359 deletions(-) rename drivers/gdisp/Nokia6610GE12/{gdisp_lld_board_olimexsam7ex256.h => board_Nokia6610GE12_olimexsam7ex256.h} (52%) rename drivers/gdisp/Nokia6610GE12/{gdisp_lld_board_template.h => board_Nokia6610GE12_template.h} (54%) diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h similarity index 52% rename from drivers/gdisp/Nokia6610GE12/gdisp_lld_board_olimexsam7ex256.h rename to drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h index c8215c75..e0f8e988 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_olimexsam7ex256.h +++ b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h @@ -1,233 +1,225 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h - * @brief GDISP Graphic Driver subsystem board interface for the Olimex SAM7-EX256 board. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/* - * Set various display properties. These properties mostly depend on the exact controller chip you get. - * The defaults should work for most controllers. - */ -//#define GDISP_SCREEN_HEIGHT 130 // The visible display height -//#define GDISP_SCREEN_WIDTH 130 // The visible display width -//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area -//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area -//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display -//#define GDISP_INITIAL_CONTRAST 50 // The initial contrast percentage -//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage - -// ****************************************************** -// Pointers to AT91SAM7X256 peripheral data structures -// ****************************************************** -static volatile AT91PS_PIO pPIOA = AT91C_BASE_PIOA; -static volatile AT91PS_PIO pPIOB = AT91C_BASE_PIOB; -static volatile AT91PS_SPI pSPI = AT91C_BASE_SPI0; -static volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; -static volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_SPI0; - -/* The PWM backlight control is non-linear on this board. - * We pick values here that make it look a bit more linear. - */ -#define PWM_TOP_VALUE 500 -#define PWM_BOTTOM_VALUE 200 - -#define PWM_VALUE(x) (PWM_BOTTOM_VALUE+(PWM_TOP_VALUE-PWM_BOTTOM_VALUE)*(x)/100) - -/* PWM configuration structure. The LCD Backlight is on PWM1/PB20 ie PWM2/PIN1 in ChibiOS speak */ -static const PWMConfig pwmcfg = { - 1000000, /* 1 MHz PWM clock frequency. Ignored as we are using PWM_MCK_DIV_n */ - 1000, /* PWM period is 1000 cycles. */ - NULL, - { - {PWM_MCK_DIV_1 | PWM_OUTPUT_ACTIVE_HIGH | PWM_OUTPUT_PIN1 | PWM_DISABLEPULLUP_PIN1, NULL}, - }, -}; - -static bool_t pwmRunning = FALSE; - -/** - * @brief Initialise the board for the display. - * @notes Performs the following functions: - * 1. initialise the spi port used by your display - * 2. initialise the reset pin (initial state not-in-reset) - * 3. initialise the chip select pin (initial state not-active) - * 4. initialise the backlight pin (initial state back-light off) - * - * @notapi - */ -static inline void init_board(void) { - // ********************************************************************************************* - // InitSpi( ) - // - // Sets up SPI channel 0 for communications to Nokia 6610 LCD Display - // - // I/O ports used: PA2 = LCD Reset (set to low to reset) - // PA12 = LCD chip select (set to low to select the LCD chip) - // PA16 = SPI0_MISO Master In - Slave Out (not used in LCD interface) - // PA17 = SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave) - // PA18 = SPI0_SPCK Serial Clock (to LCD slave) - // PB20 = backlight control (normally PWM control, 1 = full on) - // - // *********************************************************************************************} - - /* This code should really use the ChibiOS driver for these functions */ - - // Pin for backlight - pPIOB->PIO_CODR = PIOB_LCD_BL_MASK; // Set PB20 to LOW - pPIOB->PIO_OER = PIOB_LCD_BL_MASK; // Configure PB20 as output - - // Reset pin - pPIOA->PIO_SODR = PIOA_LCD_RESET_MASK; // Set PA2 to HIGH - pPIOA->PIO_OER = PIOA_LCD_RESET_MASK; // Configure PA2 as output - - // CS pin - this seems to be ignored - // pPIOA->PIO_SODR = 1<<12; // Set PA2 to HIGH - // pPIOA->PIO_OER = 1<<12; // Configure PA2 as output - - // Init SPI0 - // Disable the following pins from PIO control (will be used instead by the SPI0 peripheral) - // BIT12 = PA12 -> SPI0_NPCS0 chip select - // BIT16 = PA16 -> SPI0_MISO Master In - Slave Out (not used in LCD interface) - // BIT17 = PA17 -> SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave) - // BIT18 = PA18 -> SPI0_SPCK Serial Clock (to LCD slave) - pPIOA->PIO_PDR = (1<<12) | (1<<16) | (1<<17) | (1<<18); - pPIOA->PIO_ASR = (1<<12) | (1<<16) | (1<<17) | (1<<18); - pPIOA->PIO_BSR = 0; - - //enable the clock of SPI - pPMC->PMC_PCER = 1 << AT91C_ID_SPI0; - - // Fixed mode - pSPI->SPI_CR = 0x81; //SPI Enable, Software reset - pSPI->SPI_CR = 0x01; //SPI Enable - pSPI->SPI_MR = 0xE0011; //Master mode, fixed select, disable decoder, PCS=1110 - pSPI->SPI_CSR[0] = 0x01010311; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/3 = 16MHz - - /* Display backlight control at 100% */ - pwmRunning = FALSE; - palSetPad(IOPORT2, PIOB_LCD_BL); -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - if (state) - palClearPad(IOPORT1, PIOA_LCD_RESET); - else - palSetPad(IOPORT1, PIOA_LCD_RESET); -} - -/** - * @brief Set the lcd back-light level. - * @note For now 0% turns the backlight off, anything else the backlight is on. - * While the hardware supports PWM backlight control, we are not using it - * yet. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - if (percent == 100) { - /* Turn the pin on - No PWM */ - if (pwmRunning) { - pwmStop(&PWMD2); - pwmRunning = FALSE; - } - palSetPad(IOPORT2, PIOB_LCD_BL); - } else if (percent == 0) { - /* Turn the pin off - No PWM */ - if (pwmRunning) { - pwmStop(&PWMD2); - pwmRunning = FALSE; - } - palClearPad(IOPORT2, PIOB_LCD_BL); - } else { - /* Use the PWM */ - if (!pwmRunning) { - pwmStart(&PWMD2, &pwmcfg); - pwmRunning = TRUE; - } - pwmEnableChannel(&PWMD2, 0, PWM_VALUE(percent)); - } -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do for this board as the LCD is the only device on the SPI port */ -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - // Nothing to do for this board as the LCD is the only device on the SPI port -} - -/** - * @brief Send an 8 bit command to the lcd. - * - * @param[in] cmd The command to send - * - * @notapi - */ -static inline void write_cmd(uint16_t cmd) { - // wait for the previous transfer to complete - while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); - // send the command - pSPI->SPI_TDR = cmd & 0xFF; -} - -/** - * @brief Send an 8 bit data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - // wait for the previous transfer to complete - while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); - // send the data - pSPI->SPI_TDR = data | 0x0100; -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * - * @notapi - */ -static inline uint16_t read_data(void) { - #error "gdispNokia6610GE12: GDISP_HARDWARE_READPIXEL and GDISP_HARDWARE_SCROLL are not supported on this board" - return 0; -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/Nokia6610GE8/board_Nokia6610GE12_olimexsam7ex256.h + * @brief GDISP Graphic Driver subsystem board interface for the Olimex SAM7-EX256 board. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/* + * Set various display properties. These properties mostly depend on the exact controller chip you get. + * The defaults should work for most controllers. + */ +//#define GDISP_SCREEN_HEIGHT 130 // The visible display height +//#define GDISP_SCREEN_WIDTH 130 // The visible display width +//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area +//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area +//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display +//#define GDISP_INITIAL_CONTRAST 50 // The initial contrast percentage +//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. + +// ****************************************************** +// Pointers to AT91SAM7X256 peripheral data structures +// ****************************************************** +static volatile AT91PS_PIO pPIOA = AT91C_BASE_PIOA; +static volatile AT91PS_PIO pPIOB = AT91C_BASE_PIOB; +static volatile AT91PS_SPI pSPI = AT91C_BASE_SPI0; +static volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; +static volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_SPI0; + +/* The PWM backlight control is non-linear on this board. + * We pick values here that make it look a bit more linear. + */ +#define PWM_TOP_VALUE 500 +#define PWM_BOTTOM_VALUE 200 + +#define PWM_VALUE(x) (PWM_BOTTOM_VALUE+(PWM_TOP_VALUE-PWM_BOTTOM_VALUE)*(x)/100) + +/* PWM configuration structure. The LCD Backlight is on PWM1/PB20 ie PWM2/PIN1 in ChibiOS speak */ +static const PWMConfig pwmcfg = { + 1000000, /* 1 MHz PWM clock frequency. Ignored as we are using PWM_MCK_DIV_n */ + 1000, /* PWM period is 1000 cycles. */ + NULL, + { + {PWM_MCK_DIV_1 | PWM_OUTPUT_ACTIVE_HIGH | PWM_OUTPUT_PIN1 | PWM_DISABLEPULLUP_PIN1, NULL}, + }, +}; + +static bool_t pwmRunning = FALSE; + +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + // ********************************************************************************************* + // InitSpi( ) + // + // Sets up SPI channel 0 for communications to Nokia 6610 LCD Display + // + // I/O ports used: PA2 = LCD Reset (set to low to reset) + // PA12 = LCD chip select (set to low to select the LCD chip) + // PA16 = SPI0_MISO Master In - Slave Out (not used in LCD interface) + // PA17 = SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave) + // PA18 = SPI0_SPCK Serial Clock (to LCD slave) + // PB20 = backlight control (normally PWM control, 1 = full on) + // + // *********************************************************************************************} + + /* This code should really use the ChibiOS driver for these functions */ + + // Pin for backlight + pPIOB->PIO_CODR = PIOB_LCD_BL_MASK; // Set PB20 to LOW + pPIOB->PIO_OER = PIOB_LCD_BL_MASK; // Configure PB20 as output + + // Reset pin + pPIOA->PIO_SODR = PIOA_LCD_RESET_MASK; // Set PA2 to HIGH + pPIOA->PIO_OER = PIOA_LCD_RESET_MASK; // Configure PA2 as output + + // CS pin - this seems to be ignored + // pPIOA->PIO_SODR = 1<<12; // Set PA2 to HIGH + // pPIOA->PIO_OER = 1<<12; // Configure PA2 as output + + // Init SPI0 + // Disable the following pins from PIO control (will be used instead by the SPI0 peripheral) + // BIT12 = PA12 -> SPI0_NPCS0 chip select + // BIT16 = PA16 -> SPI0_MISO Master In - Slave Out (not used in LCD interface) + // BIT17 = PA17 -> SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave) + // BIT18 = PA18 -> SPI0_SPCK Serial Clock (to LCD slave) + pPIOA->PIO_PDR = (1<<12) | (1<<16) | (1<<17) | (1<<18); + pPIOA->PIO_ASR = (1<<12) | (1<<16) | (1<<17) | (1<<18); + pPIOA->PIO_BSR = 0; + + //enable the clock of SPI + pPMC->PMC_PCER = 1 << AT91C_ID_SPI0; + + // Fixed mode + pSPI->SPI_CR = 0x81; //SPI Enable, Software reset + pSPI->SPI_CR = 0x01; //SPI Enable + pSPI->SPI_MR = 0xE0011; //Master mode, fixed select, disable decoder, PCS=1110 + pSPI->SPI_CSR[0] = 0x01010311; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/3 = 16MHz + + /* Display backlight control at 100% */ + pwmRunning = FALSE; + palSetPad(IOPORT2, PIOB_LCD_BL); + break; + } +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if (state) + palClearPad(IOPORT1, PIOA_LCD_RESET); + else + palSetPad(IOPORT1, PIOA_LCD_RESET); +} + +/** + * @brief Set the lcd back-light level. + * @note For now 0% turns the backlight off, anything else the backlight is on. + * While the hardware supports PWM backlight control, we are not using it + * yet. + * + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + + if (percent == 100) { + /* Turn the pin on - No PWM */ + if (pwmRunning) { + pwmStop(&PWMD2); + pwmRunning = FALSE; + } + palSetPad(IOPORT2, PIOB_LCD_BL); + } else if (percent == 0) { + /* Turn the pin off - No PWM */ + if (pwmRunning) { + pwmStop(&PWMD2); + pwmRunning = FALSE; + } + palClearPad(IOPORT2, PIOB_LCD_BL); + } else { + /* Use the PWM */ + if (!pwmRunning) { + pwmStart(&PWMD2, &pwmcfg); + pwmRunning = TRUE; + } + pwmEnableChannel(&PWMD2, 0, PWM_VALUE(percent)); + } +} + +/** + * @brief Take exclusive control of the bus + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; + /* Nothing to do for this board as the LCD is the only device on the SPI port */ +} + +/** + * @brief Release exclusive control of the bus + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; + // Nothing to do for this board as the LCD is the only device on the SPI port +} + +/** + * @brief Send an 8 bit command to the lcd. + * + * @param[in] cmd The command to send + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t cmd) { + (void) g; + + // wait for the previous transfer to complete + while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); + // send the command + pSPI->SPI_TDR = cmd & 0xFF; +} + +/** + * @brief Send an 8 bit data to the lcd. + * + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + + // wait for the previous transfer to complete + while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); + // send the data + pSPI->SPI_TDR = data | 0x0100; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_template.h b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_template.h similarity index 54% rename from drivers/gdisp/Nokia6610GE12/gdisp_lld_board_template.h rename to drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_template.h index d3594434..b4d39918 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld_board_template.h +++ b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_template.h @@ -6,7 +6,7 @@ */ /** - * @file drivers/gdisp/Nokia6610GE12/gdisp_lld_board_template.h + * @file drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_template.h * @brief GDISP Graphic Driver subsystem board interface for the Nokia6610 GE12 display. * * @addtogroup GDISP @@ -30,97 +30,102 @@ /** * @brief Initialise the board for the display. - * @notes Performs the following functions: - * 1. initialise the spi port used by your display - * 2. initialise the reset pin (initial state not-in-reset) - * 3. initialise the chip select pin (initial state not-active) - * 4. initialise the backlight pin (initial state back-light off) + * + * @param[in] g The GDisplay structure + * + * @note Set the g->priv member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. * * @notapi */ -static inline void init_board(void) { +static inline void init_board(GDisplay *g) { + (void) g; +} +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; } /** * @brief Set or clear the lcd reset pin. * + * @param[in] g The GDisplay structure * @param[in] state TRUE = lcd in reset, FALSE = normal operation * * @notapi */ -static inline void setpin_reset(bool_t state) { - +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; } /** * @brief Set the lcd back-light level. - * @note For now 0% turns the backlight off, anything else the backlight is on. - * While the hardware supports PWM backlight control, we are not using it - * yet. * + * @param[in] g The GDisplay structure * @param[in] percent 0 to 100% * * @notapi */ -static inline void set_backlight(uint8_t percent) { - +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; } /** * @brief Take exclusive control of the bus * + * @param[in] g The GDisplay structure + * * @notapi */ -static inline void acquire_bus(void) { - +static inline void acquire_bus(GDisplay *g) { + (void) g; } /** * @brief Release exclusive control of the bus * - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Send an 8 bit command to the lcd. - * - * @param[in] cmd The command to send + * @param[in] g The GDisplay structure * * @notapi */ -static inline void write_cmd(uint16_t cmd) { - +static inline void release_bus(GDisplay *g) { + (void) g; } /** - * @brief Send an 8 bit data to the lcd. + * @brief Send data to the index register. * - * @param[in] data The data to send + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send * * @notapi */ -static inline void write_data(uint16_t data) { - +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; } -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} -#endif - #endif /* _GDISP_LLD_BOARD_H */ /** @} */ diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c index c8071917..d190c91a 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c @@ -8,14 +8,11 @@ /** * @file drivers/gdisp/Nokia6610GE12/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for the Nokia6610 GE12 display. - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." @@ -26,9 +23,11 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_LLD_DECLARATIONS +#define GDISP_DRIVER_VMT GDISPVMT_Nokia6610GE12 +#include "../drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" -#include "gdisp_lld_board.h" + +#include "board_Nokia6610GE12.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -70,46 +69,52 @@ /* Driver local variables. */ /*===========================================================================*/ -static color_t savecolor; +static color_t savecolor[GDISP_TOTAL_DISPLAYS]; -#define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0) +#define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0) /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ // Some macros just to make reading the code easier -#define delayms(ms) gfxSleepMilliseconds(ms) -#define write_data2(d1, d2) { write_data(d1); write_data(d2); } -#define write_data3(d1, d2, d3) { write_data(d1); write_data(d2); write_data(d3); } -#define write_cmd1(cmd, d1) { write_cmd(cmd); write_data(d1); } -#define write_cmd2(cmd, d1, d2) { write_cmd(cmd); write_data2(d1, d2); } -#define write_cmd3(cmd, d1, d2, d3) { write_cmd(cmd); write_data3(d1, d2, d3); } +#define delayms(ms) gfxSleepMilliseconds(ms) +#define write_data2(g, d1, d2) { write_data(g, d1); write_data(g, d2); } +#define write_data3(g, d1, d2, d3) { write_data(g, d1); write_data(g, d2); write_data(g, d3); } +#define write_reg(g, cmd, d1) { write_index(g, cmd); write_data(g, d1); } +#define write_reg2(g, cmd, d1, d2) { write_index(g, cmd); write_data2(g, d1, d2); } +#define write_reg3(g, cmd, d1, d2, d3) { write_index(g, cmd); write_data3(g, d1, d2, d3); } + +static inline void set_viewport(GDisplay* g) { + write_reg2(g, CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set + write_reg2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set + write_index(g, RAMWR); +} /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Initialise your display */ - init_board(); + init_board(g); // Hardware reset - setpin_reset(TRUE); + setpin_reset(g, TRUE); delayms(20); - setpin_reset(FALSE); + setpin_reset(g, FALSE); delayms(20); - acquire_bus(); - write_cmd(SLEEPOUT); // Sleep out - write_cmd1(COLMOD, 0x03); // Color Interface Pixel Format - 0x03 = 12 bits-per-pixel - write_cmd1(MADCTL, 0x00); // Memory access controller - write_cmd1(SETCON, 127*GDISP_INITIAL_CONTRAST/100-64); // Write contrast + acquire_bus(g); + write_index(g, SLEEPOUT); // Sleep out + write_reg(g, COLMOD, 0x03); // Color Interface Pixel Format - 0x03 = 12 bits-per-pixel + write_reg(g, MADCTL, 0x00); // Memory access controller + write_reg(g, SETCON, 127*GDISP_INITIAL_CONTRAST/100-64); // Write contrast delayms(20); - release_bus(); + release_bus(g); /* Turn on the back-light */ - set_backlight(GDISP_INITIAL_BACKLIGHT); + set_backlight(g, GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure to match */ g->g.Width = GDISP_SCREEN_WIDTH; @@ -122,34 +127,34 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } #if GDISP_HARDWARE_STREAM_WRITE - LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { - acquire_bus(); - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set - write_cmd(RAMWR); + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); g->flags &= ~GDISP_FLG_ODDBYTE; } - LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { if ((g->flags & GDISP_FLG_ODDBYTE)) { // Write the pair of pixels to the display - write_data3(((savecolor >> 4) & 0xFF), (((savecolor << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); + write_data3(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), + (((savecolor[g->controllerdisplay] << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), + (g->p.color & 0xFF)); g->flags &= ~GDISP_FLG_ODDBYTE; } else { - savecolor = g->p.color; + savecolor[g->controllerdisplay] = g->p.color; g->flags |= GDISP_FLG_ODDBYTE; } } - LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { if ((g->flags & GDISP_FLG_ODDBYTE)) { - write_data2(((savecolor >> 4) & 0xFF), ((savecolor << 4) & 0xF0)); - write_cmd(NOP); + write_data2(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), ((savecolor[g->controllerdisplay] << 4) & 0xF0)); + write_index(g, NOP); } - release_bus(); + release_bus(g); } #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + LLDSPEC void gdisp_lld_control(GDisplay *g) { /* The hardware is capable of supporting... * GDISP_CONTROL_POWER - supported * GDISP_CONTROL_ORIENTATION - supported @@ -162,24 +167,24 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return; switch((powermode_t)g->p.ptr) { case powerOff: - acquire_bus(); - write_cmd(SLEEPIN); - release_bus(); + acquire_bus(g); + write_index(g, SLEEPIN); + release_bus(g); break; case powerOn: - acquire_bus(); - write_cmd(SLEEPOUT); + acquire_bus(g); + write_index(g, SLEEPOUT); delayms(20); - write_cmd(NORON); // Set Normal mode (my) - release_bus(); + write_index(g, NORON); // Set Normal mode (my) + release_bus(g); break; case powerSleep: - acquire_bus(); - write_cmd(SLEEPOUT); + acquire_bus(g); + write_index(g, SLEEPOUT); delayms(20); - write_cmd2(PTLAR, GDISP_SLEEP_POS, GDISP_SLEEP_POS+GDISP_SLEEP_SIZE) - write_cmd(PTLON); - release_bus(); + write_reg2(g, PTLAR, GDISP_SLEEP_POS, GDISP_SLEEP_POS+GDISP_SLEEP_SIZE) + write_index(g, PTLON); + release_bus(g); break; default: return; @@ -192,30 +197,30 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { return; switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: - acquire_bus(); - write_cmd1(MADCTL, 0x00); - release_bus(); + acquire_bus(g); + write_reg(g, MADCTL, 0x00); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: - acquire_bus(); - write_cmd1(MADCTL, 0xA0); // MY, MX, V, LAO, RGB, X, X, X - release_bus(); + acquire_bus(g); + write_reg(g, MADCTL, 0xA0); // MY, MX, V, LAO, RGB, X, X, X + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: - acquire_bus(); - write_cmd1(MADCTL, 0xC0); - release_bus(); + acquire_bus(g); + write_reg(g, MADCTL, 0xC0); + release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: - acquire_bus(); - write_cmd1(MADCTL, 0x60); - release_bus(); + acquire_bus(g); + write_reg(g, MADCTL, 0x60); + release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; @@ -227,14 +232,14 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; - set_backlight((unsigned)g->p.ptr); + set_backlight(g, (unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; case GDISP_CONTROL_CONTRAST: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; - acquire_bus(); - write_cmd1(CONTRAST,(unsigned)127*g->p.ptr/100-64); - release_bus(); + acquire_bus(g); + write_reg(g, CONTRAST,(unsigned)127*g->p.ptr/100-64); + release_bus(g); g->g.Contrast = (unsigned)g->p.ptr; return; } @@ -242,4 +247,3 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { #endif #endif /* GFX_USE_GDISP */ -/** @} */ diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk b/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk index 575d52a3..892665d5 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/Nokia6610GE12/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/Nokia6610GE12 +GFXSRC += $(GFXLIB)/drivers/gdisp/Nokia6610GE12/gdisp_lld.c diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h b/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h index edbf3290..73f505be 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h @@ -22,18 +22,10 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "Nokia6610GE12" -#define GDISP_DRIVER_STRUCT GDISP_Nokia6610GE12 - #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 -/* This driver supports both packed and unpacked pixel formats and line formats. - * By default we leave these as FALSE. - */ -#define GDISP_PACKED_PIXELS FALSE -#define GDISP_PACKED_LINES FALSE #endif /* GFX_USE_GDISP */ From ad416c32b3558b56c8462dbcadfe1c0520479a1f Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 19 Oct 2013 16:33:13 +1000 Subject: [PATCH 068/160] Small fix to the Nokia6610GE12 driver --- .../board_Nokia6610GE12_olimexsam7ex256.h | 47 ++----------------- drivers/gdisp/Nokia6610GE12/gdisp_lld.c | 5 ++ 2 files changed, 9 insertions(+), 43 deletions(-) diff --git a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h index e0f8e988..7aad94d3 100644 --- a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h +++ b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h @@ -118,13 +118,10 @@ static inline void init_board(GDisplay *g) { } } -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + static inline void setpin_reset(GDisplay *g, bool_t state) { (void) g; if (state) @@ -133,16 +130,6 @@ static inline void setpin_reset(GDisplay *g, bool_t state) { palSetPad(IOPORT1, PIOA_LCD_RESET); } -/** - * @brief Set the lcd back-light level. - * @note For now 0% turns the backlight off, anything else the backlight is on. - * While the hardware supports PWM backlight control, we are not using it - * yet. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ static inline void set_backlight(GDisplay *g, uint8_t percent) { (void) g; @@ -170,33 +157,14 @@ static inline void set_backlight(GDisplay *g, uint8_t percent) { } } -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ static inline void acquire_bus(GDisplay *g) { (void) g; - /* Nothing to do for this board as the LCD is the only device on the SPI port */ } -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ static inline void release_bus(GDisplay *g) { (void) g; - // Nothing to do for this board as the LCD is the only device on the SPI port } -/** - * @brief Send an 8 bit command to the lcd. - * - * @param[in] cmd The command to send - * - * @notapi - */ static inline void write_index(GDisplay *g, uint16_t cmd) { (void) g; @@ -206,13 +174,6 @@ static inline void write_index(GDisplay *g, uint16_t cmd) { pSPI->SPI_TDR = cmd & 0xFF; } -/** - * @brief Send an 8 bit data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ static inline void write_data(GDisplay *g, uint16_t data) { (void) g; diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c index d190c91a..9aa5ac53 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c @@ -106,11 +106,16 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { delayms(20); acquire_bus(g); + write_index(g, SLEEPOUT); // Sleep out write_reg(g, COLMOD, 0x03); // Color Interface Pixel Format - 0x03 = 12 bits-per-pixel write_reg(g, MADCTL, 0x00); // Memory access controller write_reg(g, SETCON, 127*GDISP_INITIAL_CONTRAST/100-64); // Write contrast delayms(20); + + // Finish Init + post_init_board(g); + release_bus(g); /* Turn on the back-light */ From b6986f5b169631fb76c8cb191807321c3ac04f7a Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 19 Oct 2013 16:33:56 +1000 Subject: [PATCH 069/160] Convert Nokia6610GE8 driver to the new format. --- .../board_Nokia6610GE8_olimexsam7ex256.h | 195 ++++++++++++ .../board_Nokia6610GE8_template.h | 131 ++++++++ drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 282 ++++++++---------- drivers/gdisp/Nokia6610GE8/gdisp_lld.mk | 5 +- .../gdisp_lld_board_olimexsam7ex256.h | 235 --------------- .../Nokia6610GE8/gdisp_lld_board_template.h | 128 -------- drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h | 13 +- 7 files changed, 463 insertions(+), 526 deletions(-) create mode 100644 drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h create mode 100644 drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h delete mode 100644 drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h delete mode 100644 drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h diff --git a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h new file mode 100644 index 00000000..ebd038d5 --- /dev/null +++ b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h @@ -0,0 +1,195 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h + * @brief GDISP Graphic Driver subsystem board interface for the Olimex SAM7-EX256 board. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/* + * Set various display properties. These properties mostly depend on the exact controller chip you get. + * The defaults should work for most controllers. + */ +//#define GDISP_GE8_BROKEN_CONTROLLER FALSE // Uncomment this out if you have a controller thats not window wrap broken. +//#define GDISP_SCREEN_HEIGHT 130 // The visible display height +//#define GDISP_SCREEN_WIDTH 130 // The visible display width +//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area +//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area +//#define GDISP_SLEEP_SIZE 32 // The size of the sleep mode partial display +//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display +//#define GDISP_INITIAL_CONTRAST 38 // The initial contrast percentage +//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. + +// ****************************************************** +// Pointers to AT91SAM7X256 peripheral data structures +// ****************************************************** +static volatile AT91PS_PIO pPIOA = AT91C_BASE_PIOA; +static volatile AT91PS_PIO pPIOB = AT91C_BASE_PIOB; +static volatile AT91PS_SPI pSPI = AT91C_BASE_SPI0; +static volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; +static volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_SPI0; + +/* The PWM backlight control is non-linear on this board. + * We pick values here that make it look a bit more linear. + */ +#define PWM_TOP_VALUE 500 +#define PWM_BOTTOM_VALUE 200 + +#define PWM_VALUE(x) (PWM_BOTTOM_VALUE+(PWM_TOP_VALUE-PWM_BOTTOM_VALUE)*(x)/100) + +/* PWM configuration structure. The LCD Backlight is on PWM1/PB20 ie PWM2/PIN1 in ChibiOS speak */ +static const PWMConfig pwmcfg = { + 1000000, /* 1 MHz PWM clock frequency. Ignored as we are using PWM_MCK_DIV_n */ + 1000, /* PWM period is 1000 cycles. */ + NULL, + { + {PWM_MCK_DIV_1 | PWM_OUTPUT_ACTIVE_HIGH | PWM_OUTPUT_PIN1 | PWM_DISABLEPULLUP_PIN1, NULL}, + }, +}; + +static bool_t pwmRunning = FALSE; + +/** + * @brief Initialise the board for the display. + * @notes Performs the following functions: + * 1. initialise the spi port used by your display + * 2. initialise the reset pin (initial state not-in-reset) + * 3. initialise the chip select pin (initial state not-active) + * 4. initialise the backlight pin (initial state back-light off) + * + * @notapi + */ +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + // ********************************************************************************************* + // InitSpi( ) + // + // Sets up SPI channel 0 for communications to Nokia 6610 LCD Display + // + // I/O ports used: PA2 = LCD Reset (set to low to reset) + // PA12 = LCD chip select (set to low to select the LCD chip) + // PA16 = SPI0_MISO Master In - Slave Out (not used in LCD interface) + // PA17 = SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave) + // PA18 = SPI0_SPCK Serial Clock (to LCD slave) + // PB20 = backlight control (normally PWM control, 1 = full on) + // + // *********************************************************************************************} + + /* This code should really use the ChibiOS driver for these functions */ + + // Pin for backlight + pPIOB->PIO_CODR = PIOB_LCD_BL_MASK; // Set PB20 to LOW + pPIOB->PIO_OER = PIOB_LCD_BL_MASK; // Configure PB20 as output + + // Reset pin + pPIOA->PIO_SODR = PIOA_LCD_RESET_MASK; // Set PA2 to HIGH + pPIOA->PIO_OER = PIOA_LCD_RESET_MASK; // Configure PA2 as output + + // CS pin - this seems to be ignored + // pPIOA->PIO_SODR = 1<<12; // Set PA2 to HIGH + // pPIOA->PIO_OER = 1<<12; // Configure PA2 as output + + // Init SPI0 + // Disable the following pins from PIO control (will be used instead by the SPI0 peripheral) + // BIT12 = PA12 -> SPI0_NPCS0 chip select + // BIT16 = PA16 -> SPI0_MISO Master In - Slave Out (not used in LCD interface) + // BIT17 = PA17 -> SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave) + // BIT18 = PA18 -> SPI0_SPCK Serial Clock (to LCD slave) + pPIOA->PIO_PDR = (1<<12) | (1<<16) | (1<<17) | (1<<18); + pPIOA->PIO_ASR = (1<<12) | (1<<16) | (1<<17) | (1<<18); + pPIOA->PIO_BSR = 0; + + //enable the clock of SPI + pPMC->PMC_PCER = 1 << AT91C_ID_SPI0; + + // Fixed mode + pSPI->SPI_CR = 0x81; //SPI Enable, Software reset + pSPI->SPI_CR = 0x01; //SPI Enable + pSPI->SPI_MR = 0xE0011; //Master mode, fixed select, disable decoder, PCS=1110 + pSPI->SPI_CSR[0] = 0x01010311; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/3 = 16MHz + + /* Display backlight control at 100% */ + pwmRunning = FALSE; + palSetPad(IOPORT2, PIOB_LCD_BL); + break; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if (state) + palClearPad(IOPORT1, PIOA_LCD_RESET); + else + palSetPad(IOPORT1, PIOA_LCD_RESET); +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + if (percent == 100) { + /* Turn the pin on - No PWM */ + if (pwmRunning) { + pwmStop(&PWMD2); + pwmRunning = FALSE; + } + palSetPad(IOPORT2, PIOB_LCD_BL); + } else if (percent == 0) { + /* Turn the pin off - No PWM */ + if (pwmRunning) { + pwmStop(&PWMD2); + pwmRunning = FALSE; + } + palClearPad(IOPORT2, PIOB_LCD_BL); + } else { + /* Use the PWM */ + if (!pwmRunning) { + pwmStart(&PWMD2, &pwmcfg); + pwmRunning = TRUE; + } + pwmEnableChannel(&PWMD2, 0, PWM_VALUE(percent)); + } +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + // wait for the previous transfer to complete + while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); + // send the command + pSPI->SPI_TDR = index & 0xFF; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + // wait for the previous transfer to complete + while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); + // send the data + pSPI->SPI_TDR = data | 0x0100; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h new file mode 100644 index 00000000..93689abc --- /dev/null +++ b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h @@ -0,0 +1,131 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h + * @brief GDISP Graphic Driver subsystem board interface for the Nokia6610 GE12 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/* + * Set various display properties. These properties mostly depend on the exact controller chip you get. + * The defaults should work for most controllers. + */ +//#define GDISP_SCREEN_HEIGHT 130 // The visible display height +//#define GDISP_SCREEN_WIDTH 130 // The visible display width +//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area +//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area +//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display +//#define GDISP_INITIAL_CONTRAST 50 // The initial contrast percentage +//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * + * @note Set the g->priv member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Set the lcd back-light level. + * + * @param[in] g The GDisplay structure + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index d3e30d0e..4906ee78 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -58,9 +58,11 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_LLD_DECLARATIONS +#define GDISP_DRIVER_VMT GDISPVMT_Nokia6610GE8 +#include "../drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" -#include "gdisp_lld_board.h" + +#include "board_Nokia6610GE8.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -108,9 +110,9 @@ /*===========================================================================*/ #if GDISP_HARDWARE_STREAM_WRITE - static color_t savecolor; + static color_t savecolor[GDISP_TOTAL_DISPLAYS]; #if GDISP_GE8_BROKEN_CONTROLLER - static color_t firstcolor; + static color_t firstcolor[GDISP_TOTAL_DISPLAYS]; #endif #endif @@ -122,57 +124,86 @@ /*===========================================================================*/ // Some macros just to make reading the code easier -#define delayms(ms) gfxSleepMilliseconds(ms) -#define write_data2(d1, d2) { write_data(d1); write_data(d2); } -#define write_data3(d1, d2, d3) { write_data(d1); write_data(d2); write_data(d3); } -#define write_data4(d1, d2, d3, d4) { write_data(d1); write_data(d2); write_data(d3); write_data(d4); } -#define write_cmd1(cmd, d1) { write_cmd(cmd); write_data(d1); } -#define write_cmd2(cmd, d1, d2) { write_cmd(cmd); write_data2(d1, d2); } -#define write_cmd3(cmd, d1, d2, d3) { write_cmd(cmd); write_data3(d1, d2, d3); } -#define write_cmd4(cmd, d1, d2, d3, d4) { write_cmd(cmd); write_data4(d1, d2, d3, d4); } +#define delayms(ms) gfxSleepMilliseconds(ms) +#define write_data2(g, d1, d2) { write_data(g, d1); write_data(g, d2); } +#define write_data3(g, d1, d2, d3) { write_data(g, d1); write_data(g, d2); write_data(g, d3); } +#define write_data4(g, d1, d2, d3, d4) { write_data(g, d1); write_data(g, d2); write_data(g, d3); write_data(g, d4); } +#define write_cmd1(g, cmd, d1) { write_index(g, cmd); write_data(g, d1); } +#define write_cmd2(g, cmd, d1, d2) { write_index(g, cmd); write_data2(g, d1, d2); } +#define write_cmd3(g, cmd, d1, d2, d3) { write_index(g, cmd); write_data3(g, d1, d2, d3); } +#define write_cmd4(g, cmd, d1, d2, d3, d4) { write_index(g, cmd); write_data4(g, d1, d2, d3, d4); } +static inline void set_viewport(GDisplay* g) { + #if GDISP_NOKIA_ORIENTATION && GDISP_NEED_CONTROL + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x); // Column address set + write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y); // Page address set + break; + case GDISP_ROTATE_90: + write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y); + write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET-1+g->g.Width-g->p.x, GDISP_RAM_Y_OFFSET-1+g->g.Width-g->p.x); + break; + case GDISP_ROTATE_180: + write_cmd2(g, CASET, GDISP_RAM_X_OFFSET-1+g->g.Width-g->p.x, GDISP_RAM_X_OFFSET-1+g->g.Width-g->p.x); + write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET-1+g->g.Height-g->p.y, GDISP_RAM_Y_OFFSET-1+g->g.Height-g->p.y); + break; + case GDISP_ROTATE_270: + write_cmd2(g, CASET, GDISP_RAM_X_OFFSET-1+g->g.Height-g->p.y, GDISP_RAM_X_OFFSET-1+g->g.Height-g->p.y); + write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x); + break; + } + #else + write_cmd2(g, CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set + write_cmd2(g, PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set + #endif + write_index(g, RAMWR); +} /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ -LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Initialise your display */ - init_board(); + init_board(g); // Hardware reset - setpin_reset(TRUE); + setpin_reset(g, TRUE); delayms(20); - setpin_reset(FALSE); + setpin_reset(g, FALSE); delayms(20); // Get the bus for the following initialisation commands - acquire_bus(); + acquire_bus(g); - write_cmd4(DISCTL, 0x00, GDISP_SCAN_LINES/4-1, 0x0A, 0x00); // Display control - How the controller drives the LCD + write_cmd4(g, DISCTL, 0x00, GDISP_SCAN_LINES/4-1, 0x0A, 0x00); // Display control - How the controller drives the LCD // P1: 0x00 = 2 divisions, switching period=8 (default) // P2: 0x20 = nlines/4 - 1 = 132/4 - 1 = 32) // P3: 0x0A = standard inverse highlight, inversion every frame // P4: 0x00 = dispersion on - write_cmd1(COMSCN, 0x01); // COM scan - How the LCD is connected to the controller + write_cmd1(g, COMSCN, 0x01); // COM scan - How the LCD is connected to the controller // P1: 0x01 = Scan 1->80, 160<-81 - write_cmd(OSCON); // Internal oscillator ON - write_cmd(SLPOUT); // Sleep out - write_cmd1(PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON - write_cmd3(DATCTL, 0x00, 0x00, 0x02); // Data control + write_index(g, OSCON); // Internal oscillator ON + write_index(g, SLPOUT); // Sleep out + write_cmd1(g, PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON + write_cmd3(g, DATCTL, 0x00, 0x00, 0x02); // Data control // P1: 0x00 = page address normal, column address normal, address scan in column direction // P2: 0x00 = RGB sequence (default value) // P3: 0x02 = 4 bits per colour (Type A) - write_cmd2(VOLCTR, 63*GDISP_INITIAL_CONTRAST/100, 0x03); // Voltage control (contrast setting) + write_cmd2(g, VOLCTR, 63*GDISP_INITIAL_CONTRAST/100, 0x03); // Voltage control (contrast setting) // P1 = Contrast (0..63) // P2 = 3 resistance ratio (only value that works) delayms(100); // Allow power supply to stabilise - write_cmd(DISON); // Turn on the display + write_index(g, DISON); // Turn on the display + + // Finish Init + post_init_board(g); // Release the bus - release_bus(); + release_bus(g); /* Turn on the back-light */ - set_backlight(GDISP_INITIAL_BACKLIGHT); + set_backlight(g, GDISP_INITIAL_BACKLIGHT); /* Initialise the GDISP structure to match */ g->g.Orientation = GDISP_ROTATE_0; @@ -185,30 +216,30 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } #if GDISP_HARDWARE_STREAM_WRITE - LLDSPEC void gdisp_lld_write_start(GDISPDriver *g) { - acquire_bus(); - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set - write_cmd(RAMWR); + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); g->flags &= ~(GDISP_FLG_ODDBYTE|GDISP_FLG_RUNBYTE); } - LLDSPEC void gdisp_lld_write_color(GDISPDriver *g) { + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { #if GDISP_GE8_BROKEN_CONTROLLER if (!(g->flags & GDISP_FLG_RUNBYTE)) { - firstcolor = g->p.color; + firstcolor[g->controllerdisplay] = g->p.color; g->flags |= GDISP_FLG_RUNBYTE; } #endif if ((g->flags & GDISP_FLG_ODDBYTE)) { // Write the pair of pixels to the display - write_data3(((savecolor >> 4) & 0xFF), (((savecolor << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); + write_data3(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), + (((savecolor[g->controllerdisplay] << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), + (g->p.color & 0xFF)); g->flags &= ~GDISP_FLG_ODDBYTE; } else { - savecolor = g->p.color; + savecolor[g->controllerdisplay] = g->p.color; g->flags |= GDISP_FLG_ODDBYTE; } } - LLDSPEC void gdisp_lld_write_stop(GDISPDriver *g) { + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { if ((g->flags & GDISP_FLG_ODDBYTE)) { #if GDISP_GE8_BROKEN_CONTROLLER /** @@ -229,80 +260,47 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { * user application uses the streaming calls and then terminates the stream early or after buffer wrap. * Since this is such an unlikely situation we just don't handle it. */ - write_data3(((savecolor >> 4) & 0xFF), (((savecolor << 4) & 0xF0)|((firstcolor >> 8) & 0x0F)), (firstcolor & 0xFF)); + write_data3(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), + (((savecolor[g->controllerdisplay] << 4) & 0xF0)|((firstcolor[g->controllerdisplay] >> 8) & 0x0F)), + (firstcolor[g->controllerdisplay] & 0xFF)); #else - write_data2(((savecolor >> 4) & 0xFF), ((savecolor << 4) & 0xF0)); - write_cmd(NOP); + write_data2(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), ((savecolor[g->controllerdisplay] << 4) & 0xF0)); + write_index(g, NOP); #endif } - release_bus(); + release_bus(g); } #endif #if GDISP_HARDWARE_DRAWPIXEL - LLDSPEC void gdisp_lld_draw_pixel(GDISPDriver *g) { - acquire_bus(); - switch(g->g.Orientation) { - case GDISP_ROTATE_0: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x); // Column address set - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y); // Page address set - break; - case GDISP_ROTATE_90: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET-1+g->g.Width-g->p.x, GDISP_RAM_Y_OFFSET-1+g->g.Width-g->p.x); - break; - case GDISP_ROTATE_180: - write_cmd2(CASET, GDISP_RAM_X_OFFSET-1+g->g.Width-g->p.x, GDISP_RAM_X_OFFSET-1+g->g.Width-g->p.x); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET-1+g->g.Height-g->p.y, GDISP_RAM_Y_OFFSET-1+g->g.Height-g->p.y); - break; - case GDISP_ROTATE_270: - write_cmd2(CASET, GDISP_RAM_X_OFFSET-1+g->g.Height-g->p.y, GDISP_RAM_X_OFFSET-1+g->g.Height-g->p.y); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x); - break; - } - write_cmd3(RAMWR, 0, (g->p.color>>8) & 0x0F, g->p.color & 0xFF); - release_bus(); + LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + write_data3(g, 0, (g->p.color>>8) & 0x0F, g->p.color & 0xFF); + release_bus(g); } #endif /* ---- Optional Routines ---- */ #if GDISP_HARDWARE_FILLS - LLDSPEC void gdisp_lld_fill_area(GDISPDriver *g) { + LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { unsigned tuples; tuples = (g->p.cx*g->p.cy+1)>>1; // With an odd sized area we over-print by one pixel. // This extra pixel overwrites the first pixel (harmless as it is the same colour) - acquire_bus(); - switch(g->g.Orientation) { - case GDISP_ROTATE_0: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set - break; - case GDISP_ROTATE_90: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y+g->p.cy-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-1); - break; - case GDISP_ROTATE_180: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-1); - break; - case GDISP_ROTATE_270: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1); - break; - } - write_cmd(RAMWR); + acquire_bus(g); + set_viewport(g); while(tuples--) - write_data3(((g->p.color >> 4) & 0xFF), (((g->p.color << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); - release_bus(); + write_data3(g, ((g->p.color >> 4) & 0xFF), (((g->p.color << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); + release_bus(g); } #endif #if GDISP_HARDWARE_BITFILLS - LLDSPEC void gdisp_lld_blit_area(GDISPDriver *g) { + LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { coord_t lg, x, y; color_t c1, c2; unsigned tuples; @@ -318,26 +316,8 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { buffer = (const pixel_t *)g->p.ptr; /* Set up the data window to transfer */ - acquire_bus(); - switch(g->g.Orientation) { - case GDISP_ROTATE_0: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.x, GDISP_RAM_X_OFFSET+g->p.x+g->p.cx-1); // Column address set - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.y, GDISP_RAM_Y_OFFSET+g->p.y+g->p.cy-1); // Page address set - break; - case GDISP_ROTATE_90: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->p.y, GDISP_RAM_X_OFFSET+g->p.y+g->p.cy-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_Y_OFFSET+g->g.Width-g->p.x-1); - break; - case GDISP_ROTATE_180: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-g->p.cx, GDISP_RAM_X_OFFSET+g->g.Width-g->p.x-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_Y_OFFSET+g->g.Height-g->p.y-1); - break; - case GDISP_ROTATE_270: - write_cmd2(CASET, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-g->p.cy, GDISP_RAM_X_OFFSET+g->g.Height-g->p.y-1); - write_cmd2(PASET, GDISP_RAM_Y_OFFSET+g->p.x, GDISP_RAM_Y_OFFSET+g->p.x+g->p.cx-1); - break; - } - write_cmd(RAMWR); + acquire_bus(g); + set_viewport(g); /* * Due to the way the Nokia6610 handles a decrementing column or page, @@ -389,7 +369,7 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } /* Write the pair of pixels to the display */ - write_data3(((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF)); + write_data3(g, ((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF)); } #else @@ -445,17 +425,17 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { } /* Write the pair of pixels to the display */ - write_data3(((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF)); + write_data3(g, ((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF)); } #endif /* All done */ - release_bus(); + release_bus(g); } #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDISPDriver *g) { + LLDSPEC void gdisp_lld_control(GDisplay *g) { /* The hardware is capable of supporting... * GDISP_CONTROL_POWER - supported * GDISP_CONTROL_ORIENTATION - supported @@ -466,96 +446,96 @@ LLDSPEC bool_t gdisp_lld_init(GDISPDriver *g) { case GDISP_CONTROL_POWER: if (g->g.Powermode == (powermode_t)g->p.ptr) return; - acquire_bus(); + acquire_bus(g); switch((powermode_t)g->p.ptr) { case powerOff: - set_backlight(0); // Turn off the backlight - write_cmd(DISOFF); // Turn off the display - write_cmd1(PWRCTR, 0x00); // Power control - all off - write_cmd(SLPIN); // Sleep in - write_cmd(OSCOFF); // Internal oscillator off + set_backlight(g, 0); // Turn off the backlight + write_index(g, DISOFF); // Turn off the display + write_cmd1(g, PWRCTR, 0x00); // Power control - all off + write_index(g, SLPIN); // Sleep in + write_index(g, OSCOFF); // Internal oscillator off break; case powerOn: - write_cmd(OSCON); // Internal oscillator on - write_cmd(SLPOUT); // Sleep out - write_cmd1(PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON - write_cmd2(VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting) + write_index(g, OSCON); // Internal oscillator on + write_index(g, SLPOUT); // Sleep out + write_cmd1(g, PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON + write_cmd2(g, VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting) delayms(100); // Allow power supply to stabilise - write_cmd(DISON); // Turn on the display - write_cmd(PTLOUT); // Remove sleep window - set_backlight(g->g.Backlight); // Turn on the backlight + write_index(g, DISON); // Turn on the display + write_index(g, PTLOUT); // Remove sleep window + set_backlight(g, g->g.Backlight); // Turn on the backlight break; case powerSleep: - write_cmd(OSCON); // Internal oscillator on - write_cmd(SLPOUT); // Sleep out - write_cmd1(PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON - write_cmd2(VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting) + write_index(g, OSCON); // Internal oscillator on + write_index(g, SLPOUT); // Sleep out + write_cmd1(g, PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON + write_cmd2(g, VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting) delayms(100); // Allow power supply to stabilise - write_cmd(DISON); // Turn on the display - write_cmd2(PTLIN, GDISP_SLEEP_POS/4, (GDISP_SLEEP_POS+GDISP_SLEEP_SIZE)/4); // Sleep Window - set_backlight(g->g.Backlight); // Turn on the backlight + write_index(g, DISON); // Turn on the display + write_cmd2(g, PTLIN, GDISP_SLEEP_POS/4, (GDISP_SLEEP_POS+GDISP_SLEEP_SIZE)/4); // Sleep Window + set_backlight(g, g->g.Backlight); // Turn on the backlight break; case powerDeepSleep: - write_cmd(OSCON); // Internal oscillator on - write_cmd(SLPOUT); // Sleep out - write_cmd1(PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON - write_cmd2(VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting) + write_index(g, OSCON); // Internal oscillator on + write_index(g, SLPOUT); // Sleep out + write_cmd1(g, PWRCTR, 0x0F); // Power control - reference voltage regulator on, circuit voltage follower on, BOOST ON + write_cmd2(g, VOLCTR, g->g.Contrast, 0x03); // Voltage control (contrast setting) delayms(100); // Allow power supply to stabilise - write_cmd(DISON); // Turn on the display - write_cmd2(PTLIN, GDISP_SLEEP_POS/4, (GDISP_SLEEP_POS+GDISP_SLEEP_SIZE)/4); // Sleep Window - set_backlight(0); // Turn off the backlight + write_index(g, DISON); // Turn on the display + write_cmd2(g, PTLIN, GDISP_SLEEP_POS/4, (GDISP_SLEEP_POS+GDISP_SLEEP_SIZE)/4); // Sleep Window + set_backlight(g, 0); // Turn off the backlight break; default: - release_bus(); + release_bus(g); return; } - release_bus(); + release_bus(g); g->g.Powermode = (powermode_t)g->p.ptr; return; #if GDISP_NOKIA_ORIENTATION case GDISP_CONTROL_ORIENTATION: if (g->g.Orientation == (orientation_t)g->p.ptr) return; - acquire_bus(); + acquire_bus(g); switch((orientation_t)g->p.ptr) { case GDISP_ROTATE_0: - write_cmd3(DATCTL, 0x00, 0x00, 0x02); // P1: page normal, column normal, scan in column direction + write_cmd3(g, DATCTL, 0x00, 0x00, 0x02); // P1: page normal, column normal, scan in column direction g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: - write_cmd3(DATCTL, 0x05, 0x00, 0x02); // P1: page reverse, column normal, scan in page direction + write_cmd3(g, DATCTL, 0x05, 0x00, 0x02); // P1: page reverse, column normal, scan in page direction g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: - write_cmd3(DATCTL, 0x03, 0x00, 0x02); // P1: page reverse, column reverse, scan in column direction + write_cmd3(g, DATCTL, 0x03, 0x00, 0x02); // P1: page reverse, column reverse, scan in column direction g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: - write_cmd3(DATCTL, 0x06, 0x00, 0x02); // P1: page normal, column reverse, scan in page direction + write_cmd3(g, DATCTL, 0x06, 0x00, 0x02); // P1: page normal, column reverse, scan in page direction g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; default: - release_bus(); + release_bus(g); return; } - release_bus(); + release_bus(g); g->g.Orientation = (orientation_t)g->p.ptr; return; #endif case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; - set_backlight((unsigned)g->p.ptr); + set_backlight(g, (unsigned)g->p.ptr); g->g.Backlight = (unsigned)g->p.ptr; return; case GDISP_CONTROL_CONTRAST: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; - acquire_bus(); - write_cmd2(VOLCTR, 63*(unsigned)g->p.ptr/100, 0x03); - release_bus(); + acquire_bus(g); + write_cmd2(g, VOLCTR, 63*(unsigned)g->p.ptr/100, 0x03); + release_bus(g); g->g.Contrast = (unsigned)g->p.ptr; return; } diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk b/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk index 3e1f1851..28c57fd6 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/Nokia6610GE8/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/Nokia6610GE8 +GFXSRC += $(GFXLIB)/drivers/gdisp/Nokia6610GE8/gdisp_lld.c diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h deleted file mode 100644 index 4eeea62f..00000000 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/Nokia6610GE8/gdisp_lld_board_olimexsam7ex256.h - * @brief GDISP Graphic Driver subsystem board interface for the Olimex SAM7-EX256 board. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/* - * Set various display properties. These properties mostly depend on the exact controller chip you get. - * The defaults should work for most controllers. - */ -//#define GDISP_GE8_BROKEN_CONTROLLER FALSE // Uncomment this out if you have a controller thats not window wrap broken. -//#define GDISP_SCREEN_HEIGHT 130 // The visible display height -//#define GDISP_SCREEN_WIDTH 130 // The visible display width -//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area -//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area -//#define GDISP_SLEEP_SIZE 32 // The size of the sleep mode partial display -//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display -//#define GDISP_INITIAL_CONTRAST 38 // The initial contrast percentage -//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage - -// ****************************************************** -// Pointers to AT91SAM7X256 peripheral data structures -// ****************************************************** -static volatile AT91PS_PIO pPIOA = AT91C_BASE_PIOA; -static volatile AT91PS_PIO pPIOB = AT91C_BASE_PIOB; -static volatile AT91PS_SPI pSPI = AT91C_BASE_SPI0; -static volatile AT91PS_PMC pPMC = AT91C_BASE_PMC; -static volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_SPI0; - -/* The PWM backlight control is non-linear on this board. - * We pick values here that make it look a bit more linear. - */ -#define PWM_TOP_VALUE 500 -#define PWM_BOTTOM_VALUE 200 - -#define PWM_VALUE(x) (PWM_BOTTOM_VALUE+(PWM_TOP_VALUE-PWM_BOTTOM_VALUE)*(x)/100) - -/* PWM configuration structure. The LCD Backlight is on PWM1/PB20 ie PWM2/PIN1 in ChibiOS speak */ -static const PWMConfig pwmcfg = { - 1000000, /* 1 MHz PWM clock frequency. Ignored as we are using PWM_MCK_DIV_n */ - 1000, /* PWM period is 1000 cycles. */ - NULL, - { - {PWM_MCK_DIV_1 | PWM_OUTPUT_ACTIVE_HIGH | PWM_OUTPUT_PIN1 | PWM_DISABLEPULLUP_PIN1, NULL}, - }, -}; - -static bool_t pwmRunning = FALSE; - -/** - * @brief Initialise the board for the display. - * @notes Performs the following functions: - * 1. initialise the spi port used by your display - * 2. initialise the reset pin (initial state not-in-reset) - * 3. initialise the chip select pin (initial state not-active) - * 4. initialise the backlight pin (initial state back-light off) - * - * @notapi - */ -static inline void init_board(void) { - // ********************************************************************************************* - // InitSpi( ) - // - // Sets up SPI channel 0 for communications to Nokia 6610 LCD Display - // - // I/O ports used: PA2 = LCD Reset (set to low to reset) - // PA12 = LCD chip select (set to low to select the LCD chip) - // PA16 = SPI0_MISO Master In - Slave Out (not used in LCD interface) - // PA17 = SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave) - // PA18 = SPI0_SPCK Serial Clock (to LCD slave) - // PB20 = backlight control (normally PWM control, 1 = full on) - // - // *********************************************************************************************} - - /* This code should really use the ChibiOS driver for these functions */ - - // Pin for backlight - pPIOB->PIO_CODR = PIOB_LCD_BL_MASK; // Set PB20 to LOW - pPIOB->PIO_OER = PIOB_LCD_BL_MASK; // Configure PB20 as output - - // Reset pin - pPIOA->PIO_SODR = PIOA_LCD_RESET_MASK; // Set PA2 to HIGH - pPIOA->PIO_OER = PIOA_LCD_RESET_MASK; // Configure PA2 as output - - // CS pin - this seems to be ignored - // pPIOA->PIO_SODR = 1<<12; // Set PA2 to HIGH - // pPIOA->PIO_OER = 1<<12; // Configure PA2 as output - - // Init SPI0 - // Disable the following pins from PIO control (will be used instead by the SPI0 peripheral) - // BIT12 = PA12 -> SPI0_NPCS0 chip select - // BIT16 = PA16 -> SPI0_MISO Master In - Slave Out (not used in LCD interface) - // BIT17 = PA17 -> SPI0_MOSI Master Out - Slave In pin (Serial Data to LCD slave) - // BIT18 = PA18 -> SPI0_SPCK Serial Clock (to LCD slave) - pPIOA->PIO_PDR = (1<<12) | (1<<16) | (1<<17) | (1<<18); - pPIOA->PIO_ASR = (1<<12) | (1<<16) | (1<<17) | (1<<18); - pPIOA->PIO_BSR = 0; - - //enable the clock of SPI - pPMC->PMC_PCER = 1 << AT91C_ID_SPI0; - - // Fixed mode - pSPI->SPI_CR = 0x81; //SPI Enable, Software reset - pSPI->SPI_CR = 0x01; //SPI Enable - pSPI->SPI_MR = 0xE0011; //Master mode, fixed select, disable decoder, PCS=1110 - pSPI->SPI_CSR[0] = 0x01010311; //9bit, CPOL=1, ClockPhase=0, SCLK = 48Mhz/3 = 16MHz - - /* Display backlight control at 100% */ - pwmRunning = FALSE; - palSetPad(IOPORT2, PIOB_LCD_BL); -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - if (state) - palClearPad(IOPORT1, PIOA_LCD_RESET); - else - palSetPad(IOPORT1, PIOA_LCD_RESET); -} - -/** - * @brief Set the lcd back-light level. - * @note For now 0% turns the backlight off, anything else the backlight is on. - * While the hardware supports PWM backlight control, we are not using it - * yet. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - if (percent == 100) { - /* Turn the pin on - No PWM */ - if (pwmRunning) { - pwmStop(&PWMD2); - pwmRunning = FALSE; - } - palSetPad(IOPORT2, PIOB_LCD_BL); - } else if (percent == 0) { - /* Turn the pin off - No PWM */ - if (pwmRunning) { - pwmStop(&PWMD2); - pwmRunning = FALSE; - } - palClearPad(IOPORT2, PIOB_LCD_BL); - } else { - /* Use the PWM */ - if (!pwmRunning) { - pwmStart(&PWMD2, &pwmcfg); - pwmRunning = TRUE; - } - pwmEnableChannel(&PWMD2, 0, PWM_VALUE(percent)); - } -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do for this board as the LCD is the only device on the SPI port */ -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - // Nothing to do for this board as the LCD is the only device on the SPI port -} - -/** - * @brief Send an 8 bit command to the lcd. - * - * @param[in] cmd The command to send - * - * @notapi - */ -static inline void write_cmd(uint16_t cmd) { - // wait for the previous transfer to complete - while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); - // send the command - pSPI->SPI_TDR = cmd & 0xFF; -} - -/** - * @brief Send an 8 bit data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - // wait for the previous transfer to complete - while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); - // send the data - pSPI->SPI_TDR = data | 0x0100; -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * - * @notapi - */ -static inline uint16_t read_data(void) { - #error "gdispNokia6610GE8: GDISP_HARDWARE_READPIXEL and GDISP_HARDWARE_SCROLL are not supported on this board" - return pSPI->SPI_RDR; -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h deleted file mode 100644 index 43cc4830..00000000 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/Nokia6610GE8/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board interface for the Nokia6610 GE8 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/* - * Set various display properties. These properties mostly depend on the exact controller chip you get. - * The defaults should work for most controllers. - */ -//#define GDISP_GE8_BROKEN_CONTROLLER FALSE // Uncomment this out if you have a controller thats not window wrap broken. -//#define GDISP_SCREEN_HEIGHT 130 // The visible display height -//#define GDISP_SCREEN_WIDTH 130 // The visible display width -//#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area -//#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area -//#define GDISP_SLEEP_SIZE 32 // The size of the sleep mode partial display -//#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display -//#define GDISP_INITIAL_CONTRAST 38 // The initial contrast percentage -//#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage - -/** - * @brief Initialise the board for the display. - * @notes Performs the following functions: - * 1. initialise the spi port used by your display - * 2. initialise the reset pin (initial state not-in-reset) - * 3. initialise the chip select pin (initial state not-active) - * 4. initialise the backlight pin (initial state back-light off) - * - * @notapi - */ -static inline void init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * @note For now 0% turns the backlight off, anything else the backlight is on. - * While the hardware supports PWM backlight control, we are not using it - * yet. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Send an 8 bit command to the lcd. - * - * @param[in] cmd The command to send - * - * @notapi - */ -static inline void write_cmd(uint16_t cmd) { - -} - -/** - * @brief Send an 8 bit data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h index a9e11e03..70a57d12 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h @@ -22,9 +22,11 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "Nokia6610GE8" -#define GDISP_DRIVER_STRUCT GDISP_Nokia6610GE8 - +/* This driver has problems with other orientations and requires significantly + * extra code to handle them. By default we turn this on (only if the GDISP_NEED_CONTROL + * is turned on). If you are worried about code size and don't need orientation support + * define GDISP_NOKIA_ORIENTATION as false. + */ #ifndef GDISP_NOKIA_ORIENTATION #define GDISP_NOKIA_ORIENTATION TRUE #endif @@ -40,11 +42,6 @@ #endif #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 -/* This driver supports both packed and unpacked pixel formats and line formats. - * By default we leave these as FALSE. - */ -#define GDISP_PACKED_PIXELS FALSE -#define GDISP_PACKED_LINES FALSE #endif /* GFX_USE_GDISP */ From 6ac1710dc5a73c62d2cb4a36cf99525b4ce63c65 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 19 Oct 2013 16:45:01 +1000 Subject: [PATCH 070/160] Converted TestStub driver to new format. --- drivers/gdisp/TestStub/gdisp_lld.c | 108 +++++----------------- drivers/gdisp/TestStub/gdisp_lld.mk | 5 +- drivers/gdisp/TestStub/gdisp_lld_config.h | 8 +- 3 files changed, 27 insertions(+), 94 deletions(-) diff --git a/drivers/gdisp/TestStub/gdisp_lld.c b/drivers/gdisp/TestStub/gdisp_lld.c index e5167989..f9c421f5 100644 --- a/drivers/gdisp/TestStub/gdisp_lld.c +++ b/drivers/gdisp/TestStub/gdisp_lld.c @@ -8,17 +8,15 @@ /** * @file drivers/gdisp/TestStub/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source (stub). - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" +#define GDISP_DRIVER_VMT GDISPVMT_TestStub +#include "../drivers/gdisp/TestStub/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" #ifndef GDISP_SCREEN_HEIGHT #define GDISP_SCREEN_HEIGHT 128 @@ -26,93 +24,35 @@ #ifndef GDISP_SCREEN_WIDTH #define GDISP_SCREEN_WIDTH 128 #endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ - -/** - * @brief Low level GDISP driver initialization. - * - * @notapi - */ -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Initialise the GDISP structure */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOff; - GDISP.Backlight = 100; - GDISP.Contrast = 50; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - (void)x; - (void)y; - (void)color; -} - -/* ---- Optional Routines ---- */ - -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) - /** - * @brief Get the color of a particular pixel. - * @note Optional. - * @note If x,y is off the screen, the result is undefined. - * - * @param[in] x, y The start of the text - * - * @notapi - */ - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - (void)x; - (void)y; +#if GDISP_HARDWARE_DRAWPIXEL + void gdisp_lld_draw_pixel(GDisplay *g) { + (void) g; + } +#endif +#if GDISP_HARDWARE_PIXELREAD + color_t gdisp_lld_get_pixel_color(GDisplay *g) { + (void) g; return 0; } #endif -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @note Optional. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - (void)x; - (void)y; - (void)cx; - (void)cy; - (void)lines; - (void)bgcolor; - } -#endif - #endif /* GFX_USE_GDISP */ -/** @} */ diff --git a/drivers/gdisp/TestStub/gdisp_lld.mk b/drivers/gdisp/TestStub/gdisp_lld.mk index 5f35be9d..9394ee9d 100644 --- a/drivers/gdisp/TestStub/gdisp_lld.mk +++ b/drivers/gdisp/TestStub/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/TestStub/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/TestStub +GFXSRC += $(GFXLIB)/drivers/gdisp/TestStub/gdisp_lld.c diff --git a/drivers/gdisp/TestStub/gdisp_lld_config.h b/drivers/gdisp/TestStub/gdisp_lld_config.h index 38c55992..adb6c8b4 100644 --- a/drivers/gdisp/TestStub/gdisp_lld_config.h +++ b/drivers/gdisp/TestStub/gdisp_lld_config.h @@ -22,14 +22,10 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "TestStub" - -#define GDISP_HARDWARE_SCROLL GDISP_NEED_SCROLL -#define GDISP_HARDWARE_PIXELREAD GDISP_NEED_PIXELREAD +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 -#define GDISP_PACKED_PIXELS FALSE -#define GDISP_PACKED_LINES FALSE #endif /* GFX_USE_GDISP */ From 9a8b5b416358bbc95ffdd5b287190f0369908c1a Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 19 Oct 2013 17:58:18 +1000 Subject: [PATCH 071/160] Fix White spacing --- drivers/gdisp/SSD1289/gdisp_lld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index b376083c..840a1753 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -178,7 +178,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Turn on the back-light */ set_backlight(g, GDISP_INITIAL_BACKLIGHT); - /* Initialise the GDISP structure */ + /* Initialise the GDISP structure */ g->g.Width = GDISP_SCREEN_WIDTH; g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Orientation = GDISP_ROTATE_0; From 929dbabf689ff2ad688dc3a3748faeb3bd351698 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 19 Oct 2013 17:58:57 +1000 Subject: [PATCH 072/160] Convert S6D1121 driver to new format --- .../gdisp/S6D1121/board_S6D1121_olimex_e407.h | 91 +++ .../gdisp/S6D1121/board_S6D1121_template.h | 154 +++++ drivers/gdisp/S6D1121/gdisp_lld.c | 629 ++++++------------ drivers/gdisp/S6D1121/gdisp_lld.mk | 5 +- .../S6D1121/gdisp_lld_board_olimex_e407.h | 81 --- .../gdisp/S6D1121/gdisp_lld_board_template.h | 106 --- drivers/gdisp/S6D1121/gdisp_lld_config.h | 10 +- 7 files changed, 449 insertions(+), 627 deletions(-) create mode 100644 drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h create mode 100644 drivers/gdisp/S6D1121/board_S6D1121_template.h delete mode 100644 drivers/gdisp/S6D1121/gdisp_lld_board_olimex_e407.h delete mode 100644 drivers/gdisp/S6D1121/gdisp_lld_board_template.h diff --git a/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h b/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h new file mode 100644 index 00000000..ec367183 --- /dev/null +++ b/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h @@ -0,0 +1,91 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h + * @brief GDISP Graphic Driver subsystem board interface for the S6D1121 display + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->priv to that structure. +#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ +#define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ + +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->priv to NULL as we don't use it. + g->priv = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + /* STM32F4 FSMC init */ + rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); + + /* set pins to FSMC mode */ + IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8) | + (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; + + IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | + (1 << 13) | (1 << 14) | (1 << 15), 0}; + + palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); + palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); + + /* FSMC timing */ + FSMC_Bank1->BTCR[0+1] = (6) | (10 << 8) | (10 << 16); + + /* Bank1 NOR/SRAM control register configuration */ + FSMC_Bank1->BTCR[0] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + break; + } +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + GDISP_REG = index; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + GDISP_RAM = data; +} + +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return GDISP_RAM; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/S6D1121/board_S6D1121_template.h b/drivers/gdisp/S6D1121/board_S6D1121_template.h new file mode 100644 index 00000000..41c8b199 --- /dev/null +++ b/drivers/gdisp/S6D1121/board_S6D1121_template.h @@ -0,0 +1,154 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/S6D1121/board_S6D1121_template.h + * @brief GDISP Graphic Driver subsystem board interface for the S6D1121 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * + * @note Set the g->priv member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Set the lcd back-light level. + * + * @param[in] g The GDisplay structure + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; +} + +/** + * @brief Set the bus in read mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +/** + * @brief Set the bus back into write mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +/** + * @brief Read data from the lcd. + * @return The data from the lcd + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return 0; +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/S6D1121/gdisp_lld.c b/drivers/gdisp/S6D1121/gdisp_lld.c index e570c1e8..8b6a956c 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld.c +++ b/drivers/gdisp/S6D1121/gdisp_lld.c @@ -17,13 +17,6 @@ #if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." #undef GISP_SCREEN_HEIGHT @@ -33,525 +26,303 @@ #undef GDISP_SCREEN_WIDTH #endif -#define GDISP_SCREEN_HEIGHT 320 -#define GDISP_SCREEN_WIDTH 240 +#define GDISP_DRIVER_VMT GDISPVMT_S6D1121 +#include "../drivers/gdisp/S6D1121/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" -#define GDISP_INITIAL_CONTRAST 50 -#define GDISP_INITIAL_BACKLIGHT 100 +#include "board_S6D1121.h" /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ -#include "gdisp_lld_board.h" +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 320 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ /* Some common routines and macros */ -#define write_reg(reg, data) { write_index(reg); write_data(data); } -#define stream_start() write_index(0x0022); -#define stream_stop() +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } #define delay(us) gfxSleepMicroseconds(us) #define delayms(ms) gfxSleepMilliseconds(ms) -static inline void set_cursor(coord_t x, coord_t y) { +static inline void set_cursor(GDisplay *g) { /* R20h - 8 bit * R21h - 9 bit */ - switch(GDISP.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: - write_reg(0x0020, x & 0x00FF); - write_reg(0x0021, y & 0x01FF); + write_reg(g, 0x20, g->p.x & 0x00FF); + write_reg(g, 0x21, g->p.y & 0x01FF); break; case GDISP_ROTATE_90: - /* Note X has already been mirrored, so we do it directly */ - write_reg(0x0020, y & 0x00FF); - write_reg(0x0021, x & 0x01FF); + write_reg(g, 0x20, g->p.y & 0x00FF); + write_reg(g, 0x21, (GDISP_SCREEN_HEIGHT - 1 - g->p.x) & 0x01FF); break; case GDISP_ROTATE_180: - write_reg(0x0020, (GDISP_SCREEN_WIDTH - 1 - x) & 0x00FF); - write_reg(0x0021, (GDISP_SCREEN_HEIGHT - 1 - y) & 0x01FF); + write_reg(g, 0x20, (GDISP_SCREEN_WIDTH - 1 - g->p.x) & 0x00FF); + write_reg(g, 0x21, (GDISP_SCREEN_HEIGHT - 1 - g->p.y) & 0x01FF); break; case GDISP_ROTATE_270: - write_reg(0x0020, (GDISP_SCREEN_WIDTH - 1 - y) & 0x00FF); - write_reg(0x0021, (GDISP_SCREEN_HEIGHT - 1 - x) & 0x01FF); + write_reg(g, 0x20, (GDISP_SCREEN_WIDTH - 1 - g->p.y) & 0x00FF); + write_reg(g, 0x21, g->p.x & 0x01FF); break; - } + } + write_index(g, 0x22); } -static inline void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { +static inline void set_viewport(GDisplay *g) { /* HSA / HEA are 8 bit * VSA / VEA are 9 bit * use masks 0x00FF and 0x01FF to enforce this */ - switch(GDISP.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: - write_reg(0x46, (((x + cx - 1) << 8) & 0xFF00 ) | - (x & 0x00FF)); - - write_reg(0x48, y & 0x01FF); - write_reg(0x47, (y + cy - 1) & 0x01FF); + write_reg(g, 0x46, (((g->p.x + g->p.cx - 1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); + write_reg(g, 0x48, g->p.y & 0x01FF); + write_reg(g, 0x47, (g->p.y + g->p.cy - 1) & 0x01FF); break; case GDISP_ROTATE_90: - write_reg(0x46, (((y + cy - 1) << 8) & 0xFF00) | - (y & 0x00FF)); - - write_reg(0x48, x & 0x01FF); - write_reg(0x47, (x + cx - 1) & 0x01FF); + write_reg(g, 0x46, (((g->p.y + g->p.cy - 1) << 8) & 0xFF00) | (g->p.y & 0x00FF)); + write_reg(g, 0x48, (GDISP_SCREEN_HEIGHT - (g->p.x + g->p.cx)) & 0x01FF); + write_reg(g, 0x47, (GDISP_SCREEN_HEIGHT-1 - g->p.x) & 0x01FF); break; case GDISP_ROTATE_180: - write_reg(0x46, (((GDISP_SCREEN_WIDTH - x - 1) & 0x00FF) << 8) | - ((GDISP_SCREEN_WIDTH - (x + cx)) & 0x00FF)); - write_reg(0x48, (GDISP_SCREEN_HEIGHT - (y + cy)) & 0x01FF); - write_reg(0x47, (GDISP_SCREEN_HEIGHT- y - 1) & 0x01FF); + write_reg(g, 0x46, (((GDISP_SCREEN_WIDTH-1 - g->p.x) & 0x00FF) << 8) | + ((GDISP_SCREEN_WIDTH - (g->p.x + g->p.cx)) & 0x00FF)); + write_reg(g, 0x48, (GDISP_SCREEN_HEIGHT - (g->p.y + g->p.cy)) & 0x01FF); + write_reg(g, 0x47, (GDISP_SCREEN_HEIGHT-1 - g->p.y) & 0x01FF); break; case GDISP_ROTATE_270: - write_reg(0x46, (((GDISP_SCREEN_WIDTH - y - 1) & 0x00FF) << 8) | - ((GDISP_SCREEN_WIDTH - (y + cy)) & 0x00FF)); - write_reg(0x48, (GDISP_SCREEN_HEIGHT - (x + cx)) & 0x01FF); - write_reg(0x47, (GDISP_SCREEN_HEIGHT - x - 1) & 0x01FF); + write_reg(g, 0x46, (((GDISP_SCREEN_WIDTH-1 - g->p.y) & 0x00FF) << 8) | + ((GDISP_SCREEN_WIDTH - (g->p.y + g->p.cy)) & 0x00FF)); + write_reg(g, 0x48, g->p.x & 0x01FF); + write_reg(g, 0x47, (g->p.x + g->p.cx - 1) & 0x01FF); break; } - - set_cursor(x, y); } -static inline void reset_viewport(void) { - switch(GDISP.Orientation) { - case GDISP_ROTATE_0: - case GDISP_ROTATE_180: - set_viewport(0, 0, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT); - break; - case GDISP_ROTATE_90: - case GDISP_ROTATE_270: - set_viewport(0, 0, GDISP_SCREEN_HEIGHT, GDISP_SCREEN_WIDTH); - break; - } -} - -bool_t gdisp_lld_init(void) { +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* initialize the hardware */ - init_board(); + init_board(g); /* Hardware reset */ - setpin_reset(TRUE); + setpin_reset(g, TRUE); delayms(20); - setpin_reset(TRUE); + setpin_reset(g, TRUE); delayms(20); /* Get the bus for the following initialisation commands */ - acquire_bus(); + acquire_bus(g); - write_reg(0x11,0x2004); - write_reg(0x13,0xCC00); - write_reg(0x15,0x2600); - write_reg(0x14,0x252A); - write_reg(0x12,0x0033); - write_reg(0x13,0xCC04); + write_reg(g, 0x11, 0x2004); + write_reg(g, 0x13, 0xCC00); + write_reg(g, 0x15, 0x2600); + write_reg(g, 0x14, 0x252A); + write_reg(g, 0x12, 0x0033); + write_reg(g, 0x13, 0xCC04); delayms(1); - write_reg(0x13,0xCC06); + write_reg(g, 0x13, 0xCC06); delayms(1); - write_reg(0x13,0xCC4F); + write_reg(g, 0x13, 0xCC4F); delayms(1); - write_reg(0x13,0x674F); - write_reg(0x11,0x2003); + write_reg(g, 0x13, 0x674F); + write_reg(g, 0x11, 0x2003); delayms(1); // Gamma Setting - write_reg(0x30,0x2609); - write_reg(0x31,0x242C); - write_reg(0x32,0x1F23); - write_reg(0x33,0x2425); - write_reg(0x34,0x2226); - write_reg(0x35,0x2523); - write_reg(0x36,0x1C1A); - write_reg(0x37,0x131D); - write_reg(0x38,0x0B11); - write_reg(0x39,0x1210); - write_reg(0x3A,0x1315); - write_reg(0x3B,0x3619); - write_reg(0x3C,0x0D00); - write_reg(0x3D,0x000D); + write_reg(g, 0x30, 0x2609); + write_reg(g, 0x31, 0x242C); + write_reg(g, 0x32, 0x1F23); + write_reg(g, 0x33, 0x2425); + write_reg(g, 0x34, 0x2226); + write_reg(g, 0x35, 0x2523); + write_reg(g, 0x36, 0x1C1A); + write_reg(g, 0x37, 0x131D); + write_reg(g, 0x38, 0x0B11); + write_reg(g, 0x39, 0x1210); + write_reg(g, 0x3A, 0x1315); + write_reg(g, 0x3B, 0x3619); + write_reg(g, 0x3C, 0x0D00); + write_reg(g, 0x3D, 0x000D); - write_reg(0x16,0x0007); - write_reg(0x02,0x0013); - write_reg(0x03,0x0003); - write_reg(0x01,0x0127); + write_reg(g, 0x16, 0x0007); + write_reg(g, 0x02, 0x0013); + write_reg(g, 0x03, 0x0003); + write_reg(g, 0x01, 0x0127); delayms(1); - write_reg(0x08,0x0303); - write_reg(0x0A,0x000B); - write_reg(0x0B,0x0003); - write_reg(0x0C,0x0000); - write_reg(0x41,0x0000); - write_reg(0x50,0x0000); - write_reg(0x60,0x0005); - write_reg(0x70,0x000B); - write_reg(0x71,0x0000); - write_reg(0x78,0x0000); - write_reg(0x7A,0x0000); - write_reg(0x79,0x0007); - write_reg(0x07,0x0051); + write_reg(g, 0x08, 0x0303); + write_reg(g, 0x0A, 0x000B); + write_reg(g, 0x0B, 0x0003); + write_reg(g, 0x0C, 0x0000); + write_reg(g, 0x41, 0x0000); + write_reg(g, 0x50, 0x0000); + write_reg(g, 0x60, 0x0005); + write_reg(g, 0x70, 0x000B); + write_reg(g, 0x71, 0x0000); + write_reg(g, 0x78, 0x0000); + write_reg(g, 0x7A, 0x0000); + write_reg(g, 0x79, 0x0007); + write_reg(g, 0x07, 0x0051); delayms(1); - write_reg(0x07,0x0053); - write_reg(0x79,0x0000); + write_reg(g, 0x07,0x0053); + write_reg(g, 0x79,0x0000); - reset_viewport(); - set_backlight(GDISP_INITIAL_BACKLIGHT); + // Finish Init + post_init_board(g); - /* Now initialise the GDISP structure */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = 100; - GDISP.Contrast = 50; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + // Release the bus + release_bus(g); + + /* Turn on the back-light */ + set_backlight(g, GDISP_INITIAL_BACKLIGHT); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - acquire_bus(); - set_cursor(x, y); - write_reg(0x0022, color); - release_bus(); -} - -/* ---- Optional Routines ---- */ - -#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) - /** - * @brief Clear the display. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] color The color of the pixel - * - * @notapi - */ - void gdisp_lld_clear(color_t color) { - unsigned i; - - acquire_bus(); - set_cursor(0, 0); - stream_start(); - - for(i = 0; i < GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT; i++) - write_data(color); - - stream_stop(); - release_bus(); +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + } + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, g->p.color); + } + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); + } + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { + set_cursor(g); } #endif -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - unsigned i, area; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - area = cx*cy; - acquire_bus(); - set_viewport(x, y, cx, cy); - stream_start(); - for(i = 0; i < area; i++) - write_data(color); - stream_stop(); - reset_viewport(); - release_bus(); +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + set_cursor(g); + setreadmode(g); + dummy_read(g); + } + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { + return read_data(g); + } + LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { + setwritemode(g); + release_bus(g); } #endif -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a bitmap. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - coord_t endx, endy; - unsigned lg; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - acquire_bus(); - set_viewport(x, y, cx, cy); - stream_start(); - - endx = srcx + cx; - endy = y + cy; - lg = srccx - cx; - buffer += srcx + srcy * srccx; - for(; y < endy; y++, buffer += lg) - for(x=srcx; x < endx; x++) - write_data(*buffer++); - stream_stop(); - reset_viewport(); - release_bus(); - } -#endif - -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) - /** - * @brief Get the color of a particular pixel. - * @note Optional. - * @note If x,y is off the screen, the result is undefined. - * - * @param[in] x, y The start of the text - * - * @notapi - */ - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - /* This routine is marked "DO NOT USE" in the original - * GLCD driver. We just keep our GDISP_HARDWARE_READPIXEL - * turned off for now. - */ - color_t color; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; - #endif - - aquire_bus(); - set_cursor(x, y); - stream_start(); - - color = lld_lcdReadData(); - color = lld_lcdReadData(); - - stream_stop(); - release_bus(); - - return color; - } -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @note Optional. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - /* This is marked as "TODO: Test this" in the original GLCD driver. - * For now we just leave the GDISP_HARDWARE_SCROLL off. - */ - static color_t buf[((GDISP_SCREEN_HEIGHT > GDISP_SCREEN_WIDTH ) ? GDISP_SCREEN_HEIGHT : GDISP_SCREEN_WIDTH)]; - coord_t row0, row1; - unsigned i, gap, abslines; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - abslines = lines < 0 ? -lines : lines; - - acquire_bus(); - if (abslines >= cy) { - abslines = cy; - gap = 0; - } else { - gap = cy - abslines; - for(i = 0; i < gap; i++) { - if(lines > 0) { - row0 = y + i + lines; - row1 = y + i; - } else { - row0 = (y - i - 1) + lines; - row1 = (y - i - 1); - } - - /* read row0 into the buffer and then write at row1*/ - set_viewport(x, row0, cx, 1); - lld_lcdReadStreamStart(); - lld_lcdReadStream(buf, cx); - lld_lcdReadStreamStop(); - - set_viewport(x, row1, cx, 1); - stream_start(); - write_data(buf, cx); - stream_stop(); - } - } - - /* fill the remaining gap */ - set_viewport(x, lines > 0 ? (y+gap) : y, cx, abslines); - stream_start(); - gap = cx*abslines; - for(i = 0; i < gap; i++) write_data(bgcolor); - stream_stop(); - reset_viewport(); - release_bus(); - } -#endif - -#if GDISP_HARDWARE_CONTROL || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. - * GDISP_CONTROL_LLD - Low level driver control constants start at - * this value. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { - switch(what) { - case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) - return; - switch((gdisp_powermode_t)value) { +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + #if 0 + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { case powerOff: - /* Code here */ - /* break; */ + acquire_bus(g); + // TODO + release_bus(g); + break; case powerOn: - /* Code here */ - /* You may need this --- - if (GDISP.Powermode != powerSleep) - gdisp_lld_init(); - */ - /* break; */ + acquire_bus(g); + // TODO + release_bus(g); + break; case powerSleep: - /* Code here */ - /* break; */ + acquire_bus(g); + // TODO + release_bus(g); + break; default: return; - } - GDISP.Powermode = (gdisp_powermode_t)value; - return; - case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) + } + g->g.Powermode = (powermode_t)g->p.ptr; return; - switch((gdisp_orientation_t)value) { - case GDISP_ROTATE_0: - acquire_bus(); - write_reg(0x0001,0x0127); - write_reg(0x03, 0b0011); - release_bus(); + #endif - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(g); + write_reg(g, 0x03, 0b0011); + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_90: - acquire_bus(); - write_reg(0x0001,0x0027); - write_reg(0x0003, 0b1011); - release_bus(); - - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; + acquire_bus(g); + write_reg(g, 0x03, 0b1001); + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: - acquire_bus(); - write_reg(0x0001,0x0127); - write_reg(0x0003, 0b0000); - release_bus(); - - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; + acquire_bus(g); + write_reg(g, 0x03, 0b0000); + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: - acquire_bus(); - write_reg(0x0001,0x0027); - write_reg(0x0003, 0b1000); - release_bus(); - - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; + acquire_bus(g); + write_reg(g, 0x03, 0b1010); + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; break; default: return; } - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; + g->g.Orientation = (orientation_t)value; return; -/* - case GDISP_CONTROL_BACKLIGHT: - case GDISP_CONTROL_CONTRAST: -*/ + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + //case GDISP_CONTROL_CONTRAST: + default: + return; } } #endif diff --git a/drivers/gdisp/S6D1121/gdisp_lld.mk b/drivers/gdisp/S6D1121/gdisp_lld.mk index 07f9c380..f5f067b7 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld.mk +++ b/drivers/gdisp/S6D1121/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/S6D1121/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/S6D1121 +GFXSRC += $(GFXLIB)/drivers/gdisp/S6D1121/gdisp_lld.c diff --git a/drivers/gdisp/S6D1121/gdisp_lld_board_olimex_e407.h b/drivers/gdisp/S6D1121/gdisp_lld_board_olimex_e407.h deleted file mode 100644 index 0ce843b4..00000000 --- a/drivers/gdisp/S6D1121/gdisp_lld_board_olimex_e407.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/S6D1121/gdisp_lld_board_olimex_e407.h - * @brief GDISP Graphic Driver subsystem board interface for the S6D1121 display - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ -#define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ - -static inline void init_board(void) { - int FSMC_Bank = 0; - - /* STM32F4 FSMC init */ - rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); - - /* set pins to FSMC mode */ - IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8) | - (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; - - IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | - (1 << 13) | (1 << 14) | (1 << 15), 0}; - - palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); - palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); - - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = (6) | (10 << 8) | (10 << 16); - - /* Bank1 NOR/SRAM control register configuration */ - FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; -} - -static inline void setpin_reset(bool_t state) { - (void)state; - - /* Nothing to do here */ -} - -static inline void set_backlight(uint8_t percent) { - (void)percent; - - /* Nothing to do here */ -} - -static inline void acquire_bus(void) { - /* Nothing to do here */ -} - -static inline void release_bus(void) { - /* Nothing to do here */ -} - -static inline void write_index(uint16_t index) { - GDISP_REG = index; -} - -static inline void write_data(uint16_t data) { - GDISP_RAM = data; -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -static inline uint16_t read_data(void) { - return GDISP_RAM; -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/S6D1121/gdisp_lld_board_template.h b/drivers/gdisp/S6D1121/gdisp_lld_board_template.h deleted file mode 100644 index f123bd06..00000000 --- a/drivers/gdisp/S6D1121/gdisp_lld_board_template.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/S6D1121/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board interface for the S6D1121 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief Initialise the board for the display. - * - * @notapi - */ -static inline void init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/S6D1121/gdisp_lld_config.h b/drivers/gdisp/S6D1121/gdisp_lld_config.h index bace096c..839bbf9d 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld_config.h +++ b/drivers/gdisp/S6D1121/gdisp_lld_config.h @@ -22,13 +22,9 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "S6D1121" - -#define GDISP_HARDWARE_CLEARS TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -#define GDISP_HARDWARE_SCROLL TRUE -#define GDISP_HARDWARE_PIXELREAD FALSE +#define GDISP_HARDWARE_STREAM_WRITE TRUE +#define GDISP_HARDWARE_STREAM_READ TRUE +#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 From 258c97d67dffe79f4e4bd43618b766c7c9ebbcce Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sun, 20 Oct 2013 17:27:42 +0200 Subject: [PATCH 073/160] fixed wrong macro --- src/gtimer/gtimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gtimer/gtimer.c b/src/gtimer/gtimer.c index 25b7d804..7425f65d 100644 --- a/src/gtimer/gtimer.c +++ b/src/gtimer/gtimer.c @@ -132,7 +132,7 @@ void gtimerStart(GTimer *pt, GTimerFunction fn, void *param, bool_t periodic, de // Start our thread if not already going if (!hThread) { - hThread = gfxThreadCreate(waTimerThread, sizeof(waTimerThread), GTIMER_PRIORITY, GTimerThreadHandler, NULL); + hThread = gfxThreadCreate(waTimerThread, sizeof(waTimerThread), GTIMER_THREAD_PRIORITY, GTimerThreadHandler, NULL); if (hThread) gfxThreadClose(hThread); // We never really need the handle again } From 2811e94cfe4c454d916617e5faa3367a41795ddc Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sun, 20 Oct 2013 21:47:34 +0200 Subject: [PATCH 074/160] removed ChibiOS/RT path reference (Thanks to Steffanx) --- gfx.mk | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gfx.mk b/gfx.mk index 7cd19d28..58387993 100644 --- a/gfx.mk +++ b/gfx.mk @@ -1,8 +1,3 @@ -# don't re-define GFXLIB if it has been set elsewhere, e.g in Makefile -ifeq ($(GFXLIB),) - GFXLIB = $(CHIBIOS)/ext/gfx -endif - GFXINC += $(GFXLIB)/include GFXSRC += $(GFXLIB)/src/gfx.c From 2bd47585698b5977ab873d63af4de4dc36f9ec5f Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sun, 20 Oct 2013 21:58:52 +0200 Subject: [PATCH 075/160] compiler warnings --- src/gdisp/image_gif.c | 2 +- src/gwin/gimage.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gdisp/image_gif.c b/src/gdisp/image_gif.c index 502fa3ad..d067bd0f 100644 --- a/src/gdisp/image_gif.c +++ b/src/gdisp/image_gif.c @@ -823,7 +823,7 @@ baddatacleanup: gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { gdispImagePrivate * priv; imgdecode * decode; - uint8_t * q; + uint8_t * q = 0; coord_t mx, my, fx, fy; uint16_t cnt, gcnt; uint8_t col; diff --git a/src/gwin/gimage.c b/src/gwin/gimage.c index 35ca1c6d..8eed3ac7 100644 --- a/src/gwin/gimage.c +++ b/src/gwin/gimage.c @@ -41,6 +41,8 @@ static void _redraw(GHandle gh) { #endif // The default display area + dx = 0; + dy = 0; x = gh->x; y = gh->y; w = gh->width; From 25f769ba09bef54e5cccf40bb7ed9d7f3dcca8a1 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 21 Oct 2013 00:28:50 +0200 Subject: [PATCH 076/160] doxygen fix --- include/gwin/list.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/gwin/list.h b/include/gwin/list.h index b01dbf3f..fc189658 100644 --- a/include/gwin/list.h +++ b/include/gwin/list.h @@ -205,10 +205,12 @@ bool_t gwinListItemIsSelected(GHandle gh, int item); */ int gwinListGetSelected(GHandle gh); -#if GWIN_NEED_LIST_IMAGES +#if GWIN_NEED_LIST_IMAGES || defined(__DOXYGEN__) /** * @brief Set the image for a list item * + * @pre GWIN_NEED_LIST_IMAGES must be set to true in your gfxconf.h + * * @param[in] gh The widget handle (must be a list handle) * @param[in] item The item ID * @param[in] pimg The image to be displayed or NULL to turn off the image for this list item. From 51f4435cd10cdf4b629d524c425923b293263268 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 21 Oct 2013 01:38:44 +0200 Subject: [PATCH 077/160] increased default stack size of the GTimer thread --- gfxconf.example.h | 2 +- include/gtimer/options.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gfxconf.example.h b/gfxconf.example.h index 8414dbe0..44a8ecd2 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -173,7 +173,7 @@ #define GEVENT_MAXIMUM_SIZE 32 #define GEVENT_MAX_SOURCE_LISTENERS 32 #define GTIMER_THREAD_PRIORITY HIGH_PRIORITY - #define GTIMER_THREAD_WORKAREA_SIZE 512 + #define GTIMER_THREAD_WORKAREA_SIZE 1024 #define GADC_MAX_LOWSPEED_DEVICES 4 #define GWIN_BUTTON_LAZY_RELEASE FALSE #define GWIN_CONSOLE_USE_BASESTREAM FALSE diff --git a/include/gtimer/options.h b/include/gtimer/options.h index 17358abe..8058ef1e 100644 --- a/include/gtimer/options.h +++ b/include/gtimer/options.h @@ -38,7 +38,7 @@ * @details Defaults to 512 bytes */ #ifndef GTIMER_THREAD_WORKAREA_SIZE - #define GTIMER_THREAD_WORKAREA_SIZE 512 + #define GTIMER_THREAD_WORKAREA_SIZE 1024 #endif /** @} */ From 0b9db701a1d52c8a6d63ca692619b0dde47805d1 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 21 Oct 2013 13:34:55 +1000 Subject: [PATCH 078/160] Fix missing case in gdispStreamStop(). Add support for controllers that need flushing. Add both automatic and manual flushing (via the gdispFlush() method) --- demos/modules/gdisp/gdisp_streaming/gfxconf.h | 1 + demos/modules/gdisp/gdisp_streaming/main.c | 3 + drivers/multiple/Win32/gdisp_lld.c | 9 + drivers/multiple/Win32/gdisp_lld_config.h | 4 + gfxconf.example.h | 1 + include/gdisp/gdisp.h | 21 ++ include/gdisp/lld/gdisp_lld.h | 84 ++++--- include/gdisp/options.h | 14 ++ src/gdisp/gdisp.c | 205 +++++++----------- 9 files changed, 194 insertions(+), 148 deletions(-) diff --git a/demos/modules/gdisp/gdisp_streaming/gfxconf.h b/demos/modules/gdisp/gdisp_streaming/gfxconf.h index 72bb0618..4db07fb9 100644 --- a/demos/modules/gdisp/gdisp_streaming/gfxconf.h +++ b/demos/modules/gdisp/gdisp_streaming/gfxconf.h @@ -19,6 +19,7 @@ #define GFX_USE_GMISC TRUE /* Features for the GDISP sub-system. */ +#define GDISP_NEED_AUTOFLUSH FALSE #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP FALSE #define GDISP_NEED_TEXT FALSE diff --git a/demos/modules/gdisp/gdisp_streaming/main.c b/demos/modules/gdisp/gdisp_streaming/main.c index 41b900c3..774ee833 100644 --- a/demos/modules/gdisp/gdisp_streaming/main.c +++ b/demos/modules/gdisp/gdisp_streaming/main.c @@ -106,6 +106,9 @@ int main(void) { } gdispStreamStop(); + // Force a display update if the controller supports it + gdispFlush(); + // Calculate the new frame size (note this is a drawing optimisation only) minx = ballx - radius; miny = bally - radius; maxx = minx + ballcx; maxy = miny + ballcy; diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 6c2e7f33..011f8e74 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -457,6 +457,15 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { return TRUE; } +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay *g) { + winPriv * priv; + + priv = g->priv; + UpdateWindow(priv->hwnd); + } +#endif + #if GDISP_HARDWARE_DRAWPIXEL LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { winPriv * priv; diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h index 5720eaed..f6544eb4 100644 --- a/drivers/multiple/Win32/gdisp_lld_config.h +++ b/drivers/multiple/Win32/gdisp_lld_config.h @@ -22,6 +22,10 @@ /* Driver hardware support. */ /*===========================================================================*/ +// Calling gdispGFlush() is optional for this driver but can be used by the +// application to force a display update. eg after streaming. + +#define GDISP_HARDWARE_FLUSH TRUE #define GDISP_HARDWARE_DRAWPIXEL TRUE #define GDISP_HARDWARE_FILLS TRUE #define GDISP_HARDWARE_PIXELREAD TRUE diff --git a/gfxconf.example.h b/gfxconf.example.h index 44a8ecd2..958d35da 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -34,6 +34,7 @@ #define GFX_USE_GMISC FALSE /* Features for the GDISP subsystem */ +#define GDISP_NEED_AUTOFLUSH FALSE #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index 0c8310bb..006fa08b 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -395,6 +395,27 @@ void gdispSetDisplay(GDisplay *g); /* Drawing Functions */ +/** + * @brief Flush current drawing operations to the display + * @note Some low level drivers do not update the display until + * the display is flushed. For others it is optional but can + * help prevent tearing effects. For some it is ignored. + * Calling it at the end of a logic set of drawing operations + * in your application will ensure controller portability. If you + * know your controller does not need to be flushed there is no + * need to call it (which is in reality most controllers). + * @note Even for displays that require flushing, there is no need to + * call this function if GDISP_NEED_AUTOFLUSH is TRUE. + * Calling it again won't hurt though. + * + * + * @param[in] display The display number (0..n) + * + * @api + */ +void gdispGFlush(GDisplay *g); +#define gdispFlush() gdispGFlush(GDISP) + /** * @brief Clear the display to the specified color. * diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index 442e9b6d..b5d9c699 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -34,6 +34,17 @@ * @name GDISP hardware accelerated support * @{ */ + /** + * @brief The display hardware can benefit from being flushed. + * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT + * + * @note HARDWARE_AUTODETECT is only meaningful when GDISP_TOTAL_CONTROLLERS > 1 + * @note Some controllers ** require ** the application to flush + */ + #ifndef GDISP_HARDWARE_FLUSH + #define GDISP_HARDWARE_FLUSH HARDWARE_DEFAULT + #endif + /** * @brief Hardware streaming writing is supported. * @details Can be set to TRUE, FALSE or HARDWARE_AUTODETECT @@ -247,6 +258,18 @@ struct GDisplay { */ LLDSPEC bool_t gdisp_lld_init(GDisplay *g); + #if GDISP_HARDWARE_FLUSH || defined(__DOXYGEN__) + /** + * @brief Flush the current drawing operations to the display + * @pre GDISP_HARDWARE_FLUSH is TRUE + * + * @param[in] g The driver structure + * + * @note The parameter variables must not be altered by the driver. + */ + LLDSPEC void gdisp_lld_flush(GDisplay *g); + #endif + #if GDISP_HARDWARE_STREAM_WRITE || defined(__DOXYGEN__) /** * @brief Start a streamed write operation @@ -495,6 +518,7 @@ struct GDisplay { void (*control)(GDisplay *g); // Uses p.x (=what) p.ptr (=value) void *(*query)(GDisplay *g); // Uses p.x (=what); void (*setclip)(GDisplay *g); // Uses p.x,p.y p.cx,p.cy + void (*flush)(GDisplay *g); // Uses no parameters } GDISPVMT; #if defined(GDISP_DRIVER_VMT) @@ -503,6 +527,11 @@ struct GDisplay { #endif const GDISPVMT const GDISP_DRIVER_VMT[1] = {{ gdisp_lld_init, + #if GDISP_HARDWARE_FLUSH + gdisp_lld_flush, + #else + 0, + #endif #if GDISP_HARDWARE_STREAM_WRITE gdisp_lld_write_start, #if GDISP_HARDWARE_STREAM_POS @@ -571,6 +600,7 @@ struct GDisplay { #else #define gdisp_lld_init(g) g->vmt->init(g) + #define gdisp_lld_flush(g) g->vmt->flush(g) #define gdisp_lld_write_start(g) g->vmt->writestart(g) #define gdisp_lld_write_pos(g) g->vmt->writepos(g) #define gdisp_lld_write_color(g) g->vmt->writecolor(g) @@ -591,34 +621,34 @@ struct GDisplay { #endif // GDISP_TOTAL_CONTROLLERS > 1 - /* Verify information for packed pixels and define a non-packed pixel macro */ - #if !GDISP_PACKED_PIXELS - #define gdispPackPixels(buf,cx,x,y,c) { ((color_t *)(buf))[(y)*(cx)+(x)] = (c); } - #elif !GDISP_HARDWARE_BITFILLS - #error "GDISP: packed pixel formats are only supported for hardware accelerated drivers." - #elif GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 \ - && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB444 \ - && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB666 \ - && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_CUSTOM - #error "GDISP: A packed pixel format has been specified for an unsupported pixel format." - #endif +/* Verify information for packed pixels and define a non-packed pixel macro */ +#if !GDISP_PACKED_PIXELS + #define gdispPackPixels(buf,cx,x,y,c) { ((color_t *)(buf))[(y)*(cx)+(x)] = (c); } +#elif !GDISP_HARDWARE_BITFILLS + #error "GDISP: packed pixel formats are only supported for hardware accelerated drivers." +#elif GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 \ + && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB444 \ + && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB666 \ + && GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_CUSTOM + #error "GDISP: A packed pixel format has been specified for an unsupported pixel format." +#endif - /* Support routine for packed pixel formats */ - #if !defined(gdispPackPixels) || defined(__DOXYGEN__) - /** - * @brief Pack a pixel into a pixel buffer. - * @note This function performs no buffer boundary checking - * regardless of whether GDISP_NEED_CLIP has been specified. - * - * @param[in] buf The buffer to put the pixel in - * @param[in] cx The width of a pixel line - * @param[in] x, y The location of the pixel to place - * @param[in] color The color to put into the buffer - * - * @api - */ - void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color); - #endif +/* Support routine for packed pixel formats */ +#if !defined(gdispPackPixels) || defined(__DOXYGEN__) + /** + * @brief Pack a pixel into a pixel buffer. + * @note This function performs no buffer boundary checking + * regardless of whether GDISP_NEED_CLIP has been specified. + * + * @param[in] buf The buffer to put the pixel in + * @param[in] cx The width of a pixel line + * @param[in] x, y The location of the pixel to place + * @param[in] color The color to put into the buffer + * + * @api + */ + void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color); +#endif #endif /* GFX_USE_GDISP */ diff --git a/include/gdisp/options.h b/include/gdisp/options.h index 9af7788f..72fe2038 100644 --- a/include/gdisp/options.h +++ b/include/gdisp/options.h @@ -20,6 +20,20 @@ * @name GDISP Functionality to be included * @{ */ + /** + * @brief Should drawing operations be automatically flushed. + * @details Defaults to FALSE + * @note If set to FALSE and the controller requires flushing + * then the application must manually call @p gdispGFlush(). + * Setting this to TRUE causes GDISP to automatically flush + * after each drawing operation. Note this may be slow but enables + * an application to avoid having to manually call the flush routine. + * @note Most controllers don't need flushing which is why this is set to + * FALSE by default. + */ + #ifndef GDISP_NEED_AUTOFLUSH + #define GDISP_NEED_AUTOFLUSH FALSE + #endif /** * @brief Should all operations be clipped to the screen and colors validated. * @details Defaults to TRUE. diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 66cd59fd..172cddcc 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -94,6 +94,27 @@ GDisplay *GDISP = GDisplayArray; } #endif +#if GDISP_NEED_AUTOFLUSH && GDISP_HARDWARE_FLUSH == HARDWARE_AUTODETECT + #define autoflush_stopdone(g) if (g->vmt->flush) gdisp_lld_flush(g) +#elif GDISP_NEED_AUTOFLUSH && GDISP_HARDWARE_FLUSH + #define autoflush_stopdone(g) gdisp_lld_flush(g) +#else + #define autoflush_stopdone(g) +#endif + +#if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE + #define autoflush(g) \ + { \ + if ((g->flags & GDISP_FLG_SCRSTREAM)) { \ + gdisp_lld_write_stop(g); \ + g->flags &= ~GDISP_FLG_SCRSTREAM; \ + } + autoflush_stopdone(g); + } +#else + #define autoflush(g) autoflush_stopdone(g) +#endif + // drawpixel(g) // Parameters: x,y // Alters: cx, cy (if using streaming) @@ -551,11 +572,18 @@ void _gdispInit(void) { #if GDISP_STARTUP_LOGO_TIMEOUT > 0 StatupLogoDisplay(g); #endif + #if !GDISP_NEED_AUTOFLUSH && GDISP_HARDWARE_FLUSH + gdispGFlush(g); + #endif } #if GDISP_STARTUP_LOGO_TIMEOUT > 0 gfxSleepMilliseconds(GDISP_STARTUP_LOGO_TIMEOUT); - for(g = GDisplayArray, i = 0; i < GDISP_TOTAL_DISPLAYS; g++, i++) + for(g = GDisplayArray, i = 0; i < GDISP_TOTAL_DISPLAYS; g++, i++) { gdispGClear(g, GDISP_STARTUP_COLOR); + #if !GDISP_NEED_AUTOFLUSH && GDISP_HARDWARE_FLUSH + gdispGFlush(g); + #endif + } #endif } @@ -569,6 +597,21 @@ void gdispSetDisplay(GDisplay *g) { if (g) GDISP = g; } +void gdispGFlush(GDisplay *g) { + #if GDISP_HARDWARE_FLUSH + #if GDISP_HARDWARE_FLUSH == HARDWARE_AUTODETECT + if (g->vmt->flush) + #endif + { + MUTEX_ENTER(g); + gdisp_lld_flush(g); + MUTEX_EXIT(g); + } + #else + (void) g; + #endif +} + #if GDISP_NEED_STREAMING void gdispGStreamStart(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy) { MUTEX_ENTER(g); @@ -766,6 +809,7 @@ void gdispSetDisplay(GDisplay *g) { #endif { gdisp_lld_write_stop(g); + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -782,6 +826,7 @@ void gdispSetDisplay(GDisplay *g) { g->p.ptr = (void *)g->linebuf; gdisp_lld_blit_area(g); } + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -799,10 +844,18 @@ void gdispSetDisplay(GDisplay *g) { else gdisp_lld_fill_area(g); } + autoflush_stopdone(g); MUTEX_EXIT(g); return; } #endif + + #if GDISP_HARDWARE_STREAM_WRITE != TRUE && (GDISP_LINEBUF_SIZE == 0 || GDISP_HARDWARE_BITFILLS != TRUE) && GDISP_HARDWARE_FILLS != TRUE + { + autoflush_stopdone(g); + MUTEX_EXIT(g); + } + #endif } #endif @@ -812,12 +865,7 @@ void gdispGDrawPixel(GDisplay *g, coord_t x, coord_t y, color_t color) { g->p.y = y; g->p.color = color; drawpixel_clip(g); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -829,12 +877,7 @@ void gdispGDrawLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, g->p.y1 = y1; g->p.color = color; line_clip(g); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -850,6 +893,7 @@ void gdispGClear(GDisplay *g, color_t color) { { g->p.color = color; gdisp_lld_clear(g); + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -866,6 +910,7 @@ void gdispGClear(GDisplay *g, color_t color) { g->p.cy = g->g.Height; g->p.color = color; gdisp_lld_fill_area(g); + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -895,6 +940,7 @@ void gdispGClear(GDisplay *g, color_t color) { for(; area; area--) gdisp_lld_write_color(g); gdisp_lld_write_stop(g); + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -911,6 +957,7 @@ void gdispGClear(GDisplay *g, color_t color) { for(g->p.y = 0; g->p.y < g->g.Height; g->p.y++) for(g->p.x = 0; g->p.x < g->g.Width; g->p.x++) gdisp_lld_draw_pixel(g); + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -927,6 +974,7 @@ void gdispGFillArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c TEST_CLIP_AREA(g) { fillarea(g); } + autoflush_stopdone(g); MUTEX_EXIT(g); } @@ -963,6 +1011,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c g->p.x2 = srccx; g->p.ptr = (void *)buffer; gdisp_lld_blit_area(g); + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -998,6 +1047,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c } } gdisp_lld_write_stop(g); + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -1032,6 +1082,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c } } } + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -1056,6 +1107,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c gdisp_lld_draw_pixel(g); } } + autoflush_stopdone(g); MUTEX_EXIT(g); return; } @@ -1136,12 +1188,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c g->p.x = x - a; g->p.y = y + b; drawpixel_clip(g); g->p.x = x - a; g->p.y = y - b; drawpixel_clip(g); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } #endif @@ -1177,12 +1224,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c g->p.y = y+a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); g->p.y = y-a; g->p.x = x-b; g->p.x1 = x+b; hline_clip(g); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } #endif @@ -1221,12 +1263,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c } } while(dy >= 0); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } #endif @@ -1263,12 +1300,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c } } while(dy >= 0); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } #endif @@ -1336,12 +1368,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c if (full & 0x03) { g->p.x = x+a; g->p.y = y-b; drawpixel_clip(g); } if (full & 0x30) { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } if (full == 0xFF) { - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT; return; } @@ -1458,12 +1485,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c { g->p.x = x-a; g->p.y = y+b; drawpixel_clip(g); } } - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } #endif @@ -1961,12 +1983,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c break; } - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -2246,6 +2263,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c g->p.cy = abslines; g->p.color = bgcolor; fillarea(g); + autoflush_stopdone(g); MUTEX_EXIT(g); } #endif @@ -2354,12 +2372,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co } } - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -2376,12 +2389,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co } g->p.x=tx+p->x; g->p.y=ty+p->y; g->p.x1=tx+pntarray->x; g->p.y1=ty+pntarray->y; line_clip(g); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -2441,12 +2449,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co } if (!cnt) { - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); return; } @@ -2456,12 +2459,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co if (ymax == lpnt->y) { for (lpnt = lpnt <= pntarray ? epnts : lpnt-1; lpnt->y == y; cnt--) { if (!cnt) { - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); return; } @@ -2472,12 +2470,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co } else { for (rpnt = rpnt >= epnts ? pntarray : rpnt+1; rpnt->y == y; cnt--) { if (!cnt) { - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); return; } @@ -2561,12 +2554,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co g->t.clipy1 = y + font->height; g->t.color = color; mf_render_character(font, x, y, c, drawcharline, g); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -2586,12 +2574,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co fillarea(g); mf_render_character(font, x, y, c, fillcharline, g); } - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -2605,12 +2588,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co g->t.color = color; mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, drawcharglyph, g); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -2631,12 +2609,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co mf_render_aligned(font, x+font->baseline_x, y, MF_ALIGN_LEFT, str, 0, fillcharglyph, g); } - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -2665,12 +2638,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, g); - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } @@ -2709,12 +2677,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, g); } - #if GDISP_HARDWARE_STREAM_POS && GDISP_HARDWARE_STREAM_WRITE - if ((g->flags & GDISP_FLG_SCRSTREAM)) { - gdisp_lld_write_stop(g); - g->flags &= ~GDISP_FLG_SCRSTREAM; - } - #endif + autoflush(g); MUTEX_EXIT(g); } From 0535c67eab412e72223bc06a528c5bf7cd4aeb22 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 21 Oct 2013 15:13:10 +1000 Subject: [PATCH 079/160] Add support for a driver private area (as well as a board private area) --- .../HX8347D/board_HX8347D_stm32f4discovery.h | 4 +-- drivers/gdisp/HX8347D/gdisp_lld.c | 5 ++- .../board_ILI9320_olimex_pic32mx_lcd.h | 4 +-- .../ILI9320/board_ILI9320_olimex_stm32_lcd.h | 4 +-- drivers/gdisp/ILI9320/gdisp_lld.c | 5 ++- .../ILI9325/board_ILI9325_hy_stm32_100p.h | 4 +-- drivers/gdisp/ILI9325/gdisp_lld.c | 5 ++- .../ILI9481/board_ILI9481_firebullstm32f103.h | 4 +-- drivers/gdisp/ILI9481/gdisp_lld.c | 5 ++- .../board_Nokia6610GE12_olimexsam7ex256.h | 4 +-- drivers/gdisp/Nokia6610GE12/gdisp_lld.c | 17 +++++---- .../board_Nokia6610GE8_olimexsam7ex256.h | 4 +-- drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 35 ++++++++++++------- drivers/gdisp/RA8875/board_RA8875_marlin.h | 4 +-- drivers/gdisp/RA8875/gdisp_lld.c | 5 ++- .../gdisp/S6D1121/board_S6D1121_olimex_e407.h | 4 +-- drivers/gdisp/S6D1121/gdisp_lld.c | 5 ++- .../SSD1289/board_SSD1289_firebullstm32f103.h | 4 +-- .../SSD1289/board_SSD1289_stm32f4discovery.h | 4 +-- drivers/gdisp/SSD1289/gdisp_lld.c | 5 ++- drivers/gdisp/TestStub/gdisp_lld.c | 3 ++ drivers/multiple/Win32/gdisp_lld.c | 1 + drivers/multiple/X/gdisp_lld.c | 1 + include/gdisp/gdisp.h | 2 +- include/gdisp/lld/gdisp_lld.h | 1 + 25 files changed, 90 insertions(+), 49 deletions(-) diff --git a/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h index daabe75d..708e1a06 100644 --- a/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h +++ b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h @@ -66,8 +66,8 @@ static const SPIConfig spi1cfg_16bit = { static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/HX8347D/gdisp_lld.c b/drivers/gdisp/HX8347D/gdisp_lld.c index 8cdbb781..3851c8e1 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld.c +++ b/drivers/gdisp/HX8347D/gdisp_lld.c @@ -62,7 +62,10 @@ static inline void set_viewport(GDisplay* g) { /*===========================================================================*/ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - /* Initialise your display */ + // No private area for this controller + g->priv = 0; + + // Initialise the board interface init_board(g); // Hardware reset diff --git a/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h b/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h index cf101aaf..5315127b 100644 --- a/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h +++ b/drivers/gdisp/ILI9320/board_ILI9320_olimex_pic32mx_lcd.h @@ -19,8 +19,8 @@ static void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h b/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h index 4738db61..8e79009a 100644 --- a/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h +++ b/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h @@ -20,8 +20,8 @@ static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index d4639617..bf82a88a 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -98,7 +98,10 @@ static void set_viewport(GDisplay *g) { LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { uint16_t cver; - /* Initialise your display */ + // No private area for this controller + g->priv = 0; + + // Initialise the board interface init_board(g); /* Hardware reset */ diff --git a/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h index ae9e96fc..02949605 100644 --- a/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h +++ b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h @@ -33,8 +33,8 @@ static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/ILI9325/gdisp_lld.c b/drivers/gdisp/ILI9325/gdisp_lld.c index 8a4b8603..6bb649b1 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld.c +++ b/drivers/gdisp/ILI9325/gdisp_lld.c @@ -99,7 +99,10 @@ static void set_viewport(GDisplay* g) { LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { uint16_t cver; - /* Initialise your display */ + // No private area for this controller + g->priv = 0; + + // Initialise the board interface init_board(g); /* Hardware reset */ diff --git a/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h b/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h index 9933d17b..52d8afda 100644 --- a/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h +++ b/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h @@ -27,8 +27,8 @@ static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/ILI9481/gdisp_lld.c b/drivers/gdisp/ILI9481/gdisp_lld.c index fc00be10..5af12986 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld.c +++ b/drivers/gdisp/ILI9481/gdisp_lld.c @@ -71,7 +71,10 @@ static void set_viewport(GDisplay* g) { /*===========================================================================*/ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - /* Initialise your display */ + // No private area for this controller + g->priv = 0; + + // Initialise the board interface init_board(g); /* Hardware reset */ diff --git a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h index 7aad94d3..05a48e47 100644 --- a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h +++ b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h @@ -59,8 +59,8 @@ static bool_t pwmRunning = FALSE; static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c index 9aa5ac53..25f26c69 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c @@ -69,7 +69,9 @@ /* Driver local variables. */ /*===========================================================================*/ -static color_t savecolor[GDISP_TOTAL_DISPLAYS]; +// Use the priv pointer itself to save our color. This save allocating ram for it +// and works provided sizeof(color_t) <= sizeof(void *) +#define savecolor(g) ((color_t)g->priv) #define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0) @@ -96,7 +98,10 @@ static inline void set_viewport(GDisplay* g) { /*===========================================================================*/ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - /* Initialise your display */ + // No private area for this controller + g->priv = 0; + + // Initialise the board interface init_board(g); // Hardware reset @@ -140,18 +145,18 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { LLDSPEC void gdisp_lld_write_color(GDisplay *g) { if ((g->flags & GDISP_FLG_ODDBYTE)) { // Write the pair of pixels to the display - write_data3(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), - (((savecolor[g->controllerdisplay] << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), + write_data3(g, ((savecolor(g) >> 4) & 0xFF), + (((savecolor(g) << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); g->flags &= ~GDISP_FLG_ODDBYTE; } else { - savecolor[g->controllerdisplay] = g->p.color; + savecolor(g) = g->p.color; g->flags |= GDISP_FLG_ODDBYTE; } } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { if ((g->flags & GDISP_FLG_ODDBYTE)) { - write_data2(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), ((savecolor[g->controllerdisplay] << 4) & 0xF0)); + write_data2(g, ((savecolor(g) >> 4) & 0xFF), ((savecolor(g) << 4) & 0xF0)); write_index(g, NOP); } release_bus(g); diff --git a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h index ebd038d5..6cbcc5ab 100644 --- a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h +++ b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h @@ -71,8 +71,8 @@ static bool_t pwmRunning = FALSE; */ static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index 4906ee78..1bc7282a 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -110,10 +110,13 @@ /*===========================================================================*/ #if GDISP_HARDWARE_STREAM_WRITE - static color_t savecolor[GDISP_TOTAL_DISPLAYS]; - #if GDISP_GE8_BROKEN_CONTROLLER - static color_t firstcolor[GDISP_TOTAL_DISPLAYS]; - #endif + typedef struct dvrPriv { + color_t savecolor; + #if GDISP_GE8_BROKEN_CONTROLLER + color_t firstcolor; + #endif + } dvrPriv; + #define PRIV ((dvrPriv *)g->priv) #endif #define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0) @@ -164,7 +167,13 @@ static inline void set_viewport(GDisplay* g) { /*===========================================================================*/ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - /* Initialise your display */ + #if GDISP_HARDWARE_STREAM_WRITE + g->priv = gfxAlloc(sizeof(dvrPriv)); + #else + g->priv = 0; + #endif + + // Initialise the board interface init_board(g); // Hardware reset @@ -224,18 +233,18 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { LLDSPEC void gdisp_lld_write_color(GDisplay *g) { #if GDISP_GE8_BROKEN_CONTROLLER if (!(g->flags & GDISP_FLG_RUNBYTE)) { - firstcolor[g->controllerdisplay] = g->p.color; + PRIV->firstcolor = g->p.color; g->flags |= GDISP_FLG_RUNBYTE; } #endif if ((g->flags & GDISP_FLG_ODDBYTE)) { // Write the pair of pixels to the display - write_data3(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), - (((savecolor[g->controllerdisplay] << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), + write_data3(g, ((PRIV->savecolor >> 4) & 0xFF), + (((PRIV->savecolor << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); g->flags &= ~GDISP_FLG_ODDBYTE; } else { - savecolor[g->controllerdisplay] = g->p.color; + PRIV->savecolor = g->p.color; g->flags |= GDISP_FLG_ODDBYTE; } } @@ -260,11 +269,11 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { * user application uses the streaming calls and then terminates the stream early or after buffer wrap. * Since this is such an unlikely situation we just don't handle it. */ - write_data3(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), - (((savecolor[g->controllerdisplay] << 4) & 0xF0)|((firstcolor[g->controllerdisplay] >> 8) & 0x0F)), - (firstcolor[g->controllerdisplay] & 0xFF)); + write_data3(g, ((PRIV->savecolor >> 4) & 0xFF), + (((PRIV->savecolor << 4) & 0xF0)|((PRIV->firstcolor >> 8) & 0x0F)), + (PRIV->firstcolor & 0xFF)); #else - write_data2(g, ((savecolor[g->controllerdisplay] >> 4) & 0xFF), ((savecolor[g->controllerdisplay] << 4) & 0xF0)); + write_data2(g, ((PRIV->savecolor >> 4) & 0xFF), ((PRIV->savecolor << 4) & 0xF0)); write_index(g, NOP); #endif } diff --git a/drivers/gdisp/RA8875/board_RA8875_marlin.h b/drivers/gdisp/RA8875/board_RA8875_marlin.h index 88523060..da90d8f3 100644 --- a/drivers/gdisp/RA8875/board_RA8875_marlin.h +++ b/drivers/gdisp/RA8875/board_RA8875_marlin.h @@ -22,8 +22,8 @@ static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/RA8875/gdisp_lld.c b/drivers/gdisp/RA8875/gdisp_lld.c index 6697d9fd..7916ef3b 100644 --- a/drivers/gdisp/RA8875/gdisp_lld.c +++ b/drivers/gdisp/RA8875/gdisp_lld.c @@ -107,7 +107,10 @@ static inline void set_backlight(GDisplay* g, uint8_t percent) { /*===========================================================================*/ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - /* Initialise your display */ + // No private area for this controller + g->priv = 0; + + // Initialise the board interface init_board(g); // Hardware reset diff --git a/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h b/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h index ec367183..4f8d2f58 100644 --- a/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h +++ b/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h @@ -20,8 +20,8 @@ static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/S6D1121/gdisp_lld.c b/drivers/gdisp/S6D1121/gdisp_lld.c index 8b6a956c..f7e12591 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld.c +++ b/drivers/gdisp/S6D1121/gdisp_lld.c @@ -117,7 +117,10 @@ static inline void set_viewport(GDisplay *g) { } LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - /* initialize the hardware */ + // No private area for this controller + g->priv = 0; + + // Initialise the board interface init_board(g); /* Hardware reset */ diff --git a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h index 338d9799..3277a902 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h @@ -26,8 +26,8 @@ static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h index d1e23c4a..81ce0512 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h @@ -36,8 +36,8 @@ static const PWMConfig pwmcfg = { static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->priv to NULL as we don't use it. - g->priv = 0; + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; switch(g->controllerdisplay) { case 0: // Set up for Display 0 diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 840a1753..698d3cfc 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -115,7 +115,10 @@ static void set_viewport(GDisplay* g) { /*===========================================================================*/ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - /* Initialise your display */ + // No private area for this controller + g->priv = 0; + + // Initialise the board interface init_board(g); // Hardware reset diff --git a/drivers/gdisp/TestStub/gdisp_lld.c b/drivers/gdisp/TestStub/gdisp_lld.c index f9c421f5..1a5ad81f 100644 --- a/drivers/gdisp/TestStub/gdisp_lld.c +++ b/drivers/gdisp/TestStub/gdisp_lld.c @@ -32,6 +32,9 @@ #endif LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + /* No board interface and no private driver area */ + g->priv = g->board = 0; + /* Initialise the GDISP structure */ g->g.Width = GDISP_SCREEN_WIDTH; g->g.Height = GDISP_SCREEN_HEIGHT; diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 011f8e74..3ce50633 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -441,6 +441,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { assert(priv != NULL); memset(priv, 0, sizeof(winPriv)); g->priv = priv; + g->board = 0; // no board interface for this controller // Create the window in the message thread PostThreadMessage(winThreadId, WM_USER, (WPARAM)g->controllerdisplay, (LPARAM)g); diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld.c index 188724ed..c9beb821 100644 --- a/drivers/multiple/X/gdisp_lld.c +++ b/drivers/multiple/X/gdisp_lld.c @@ -193,6 +193,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { g->priv = gfxAlloc(sizeof(xPriv)); priv = (xPriv *)g->priv; + g->board = 0; // No board interface for this driver xa.colormap = cmap; xa.border_pixel = 0xFFFFFF; diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index 006fa08b..1b17fabe 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -271,7 +271,7 @@ extern GDisplay *GDISP; #elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_MONO typedef uint8_t color_t; #define COLOR(c) ((color_t)(c)) - #define MASKCOLOR FALSE + #define MASKCOLOR TRUE #define RGB2COLOR(r,g,b) ((r|g|b) ? 1 : 0) #define HTML2COLOR(h) (h ? 1 : 0) #define RED_OF(c) (c ? 255 : 0) diff --git a/include/gdisp/lld/gdisp_lld.h b/include/gdisp/lld/gdisp_lld.h index b5d9c699..6f3a5e5f 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -191,6 +191,7 @@ struct GDisplay { #endif void * priv; // A private area just for the drivers use. + void * board; // A private area just for the board interfaces use. uint8_t systemdisplay; uint8_t controllerdisplay; From 0698fd28c03e20704376cf6c97f373ba9c5e8c4b Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 21 Oct 2013 17:11:07 +1000 Subject: [PATCH 080/160] Comment fixes. --- drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h | 2 +- drivers/gdisp/HX8347D/board_HX8347D_template.h | 2 +- drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h | 2 +- drivers/gdisp/ILI9320/board_ILI9320_template.h | 2 +- drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h | 2 +- drivers/gdisp/ILI9325/board_ILI9325_template.h | 2 +- drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h | 2 +- drivers/gdisp/ILI9481/board_ILI9481_template.h | 2 +- .../gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h | 2 +- drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_template.h | 2 +- drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h | 2 +- drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h | 2 +- drivers/gdisp/RA8875/board_RA8875_marlin.h | 2 +- drivers/gdisp/RA8875/board_RA8875_template.h | 2 +- drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h | 2 +- drivers/gdisp/S6D1121/board_S6D1121_template.h | 2 +- drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h | 2 +- drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h | 2 +- drivers/gdisp/SSD1289/board_SSD1289_template.h | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h index 708e1a06..df287477 100644 --- a/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h +++ b/drivers/gdisp/HX8347D/board_HX8347D_stm32f4discovery.h @@ -14,7 +14,7 @@ #define _GDISP_LLD_BOARD_H // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. /* Pin assignments */ #define SET_RST palSetPad(GPIOB, 8) diff --git a/drivers/gdisp/HX8347D/board_HX8347D_template.h b/drivers/gdisp/HX8347D/board_HX8347D_template.h index 58fd9338..57ec75f6 100644 --- a/drivers/gdisp/HX8347D/board_HX8347D_template.h +++ b/drivers/gdisp/HX8347D/board_HX8347D_template.h @@ -21,7 +21,7 @@ * * @param[in] g The GDisplay structure * - * @note Set the g->priv member to whatever is appropriate. For multiple + * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi diff --git a/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h b/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h index 8e79009a..bca5caf8 100644 --- a/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h +++ b/drivers/gdisp/ILI9320/board_ILI9320_olimex_stm32_lcd.h @@ -14,7 +14,7 @@ #define GDISP_LLD_BOARD_H // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. #define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ #define GDISP_RAM (*((volatile uint16_t *) 0x60100000)) /* RS = 1 */ diff --git a/drivers/gdisp/ILI9320/board_ILI9320_template.h b/drivers/gdisp/ILI9320/board_ILI9320_template.h index 4725e1eb..6f5ad16d 100644 --- a/drivers/gdisp/ILI9320/board_ILI9320_template.h +++ b/drivers/gdisp/ILI9320/board_ILI9320_template.h @@ -21,7 +21,7 @@ * * @param[in] g The GDisplay structure * - * @note Set the g->priv member to whatever is appropriate. For multiple + * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi diff --git a/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h index 02949605..60508c1a 100644 --- a/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h +++ b/drivers/gdisp/ILI9325/board_ILI9325_hy_stm32_100p.h @@ -27,7 +27,7 @@ #define GDISP_LLD_BOARD_H // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. #define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ #define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ diff --git a/drivers/gdisp/ILI9325/board_ILI9325_template.h b/drivers/gdisp/ILI9325/board_ILI9325_template.h index 65ab5704..07c2fdee 100644 --- a/drivers/gdisp/ILI9325/board_ILI9325_template.h +++ b/drivers/gdisp/ILI9325/board_ILI9325_template.h @@ -21,7 +21,7 @@ * * @param[in] g The GDisplay structure * - * @note Set the g->priv member to whatever is appropriate. For multiple + * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi diff --git a/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h b/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h index 52d8afda..17bc554d 100644 --- a/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h +++ b/drivers/gdisp/ILI9481/board_ILI9481_firebullstm32f103.h @@ -15,7 +15,7 @@ #define _GDISP_LLD_BOARD_H // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. #define SET_CS palSetPad(GPIOD, 12); #define CLR_CS palClearPad(GPIOD, 12); #define SET_RS palSetPad(GPIOD, 13); diff --git a/drivers/gdisp/ILI9481/board_ILI9481_template.h b/drivers/gdisp/ILI9481/board_ILI9481_template.h index 8dcee19c..7824c936 100644 --- a/drivers/gdisp/ILI9481/board_ILI9481_template.h +++ b/drivers/gdisp/ILI9481/board_ILI9481_template.h @@ -22,7 +22,7 @@ * * @param[in] g The GDisplay structure * - * @note Set the g->priv member to whatever is appropriate. For multiple + * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi diff --git a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h index 05a48e47..5b9ff6f6 100644 --- a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h +++ b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h @@ -26,7 +26,7 @@ //#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. // ****************************************************** // Pointers to AT91SAM7X256 peripheral data structures diff --git a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_template.h b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_template.h index b4d39918..160c9278 100644 --- a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_template.h +++ b/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_template.h @@ -33,7 +33,7 @@ * * @param[in] g The GDisplay structure * - * @note Set the g->priv member to whatever is appropriate. For multiple + * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi diff --git a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h index 6cbcc5ab..12dbc9a5 100644 --- a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h +++ b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h @@ -28,7 +28,7 @@ //#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. // ****************************************************** // Pointers to AT91SAM7X256 peripheral data structures diff --git a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h index 93689abc..28fc9f70 100644 --- a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h +++ b/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_template.h @@ -33,7 +33,7 @@ * * @param[in] g The GDisplay structure * - * @note Set the g->priv member to whatever is appropriate. For multiple + * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi diff --git a/drivers/gdisp/RA8875/board_RA8875_marlin.h b/drivers/gdisp/RA8875/board_RA8875_marlin.h index da90d8f3..e6c19d34 100644 --- a/drivers/gdisp/RA8875/board_RA8875_marlin.h +++ b/drivers/gdisp/RA8875/board_RA8875_marlin.h @@ -14,7 +14,7 @@ #define _GDISP_LLD_BOARD_H // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. #define GDISP_RAM (*((volatile uint16_t *) 0x68000000)) /* RS = 0 */ #define GDISP_REG (*((volatile uint16_t *) 0x68020000)) /* RS = 1 */ #define FSMC_BANK 4 diff --git a/drivers/gdisp/RA8875/board_RA8875_template.h b/drivers/gdisp/RA8875/board_RA8875_template.h index 32d12de5..fce05129 100644 --- a/drivers/gdisp/RA8875/board_RA8875_template.h +++ b/drivers/gdisp/RA8875/board_RA8875_template.h @@ -21,7 +21,7 @@ * * @param[in] g The GDisplay structure * - * @note Set the g->priv member to whatever is appropriate. For multiple + * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi diff --git a/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h b/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h index 4f8d2f58..e0bb8e26 100644 --- a/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h +++ b/drivers/gdisp/S6D1121/board_S6D1121_olimex_e407.h @@ -14,7 +14,7 @@ #define _GDISP_LLD_BOARD_H // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. #define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ #define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ diff --git a/drivers/gdisp/S6D1121/board_S6D1121_template.h b/drivers/gdisp/S6D1121/board_S6D1121_template.h index 41c8b199..04742f56 100644 --- a/drivers/gdisp/S6D1121/board_S6D1121_template.h +++ b/drivers/gdisp/S6D1121/board_S6D1121_template.h @@ -21,7 +21,7 @@ * * @param[in] g The GDisplay structure * - * @note Set the g->priv member to whatever is appropriate. For multiple + * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi diff --git a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h index 3277a902..2a7ffe1e 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h @@ -14,7 +14,7 @@ #define _GDISP_LLD_BOARD_H // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. #define SET_CS palSetPad(GPIOD, 12); #define CLR_CS palClearPad(GPIOD, 12); #define SET_RS palSetPad(GPIOD, 13); diff --git a/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h index 81ce0512..866311dc 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_stm32f4discovery.h @@ -14,7 +14,7 @@ #define _GDISP_LLD_BOARD_H // For a multiple display configuration we would put all this in a structure and then -// set g->priv to that structure. +// set g->board to that structure. #define GDISP_REG ((volatile uint16_t *) 0x60000000)[0] /* RS = 0 */ #define GDISP_RAM ((volatile uint16_t *) 0x60020000)[0] /* RS = 1 */ #define GDISP_DMA_STREAM STM32_DMA2_STREAM6 diff --git a/drivers/gdisp/SSD1289/board_SSD1289_template.h b/drivers/gdisp/SSD1289/board_SSD1289_template.h index 8bef95b9..7c9cd757 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_template.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_template.h @@ -21,7 +21,7 @@ * * @param[in] g The GDisplay structure * - * @note Set the g->priv member to whatever is appropriate. For multiple + * @note Set the g->board member to whatever is appropriate. For multiple * displays this might be a pointer to the appropriate register set. * * @notapi From 1b3297aeaebdfec5bf8c507ed88445585a0952de Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 21 Oct 2013 17:11:46 +1000 Subject: [PATCH 081/160] Fix a bug in Contrast handling in the Nokia drivers --- drivers/gdisp/Nokia6610GE12/gdisp_lld.c | 4 ++-- drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c index 25f26c69..ef8cd043 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c @@ -115,7 +115,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { write_index(g, SLEEPOUT); // Sleep out write_reg(g, COLMOD, 0x03); // Color Interface Pixel Format - 0x03 = 12 bits-per-pixel write_reg(g, MADCTL, 0x00); // Memory access controller - write_reg(g, SETCON, 127*GDISP_INITIAL_CONTRAST/100-64); // Write contrast + write_reg(g, SETCON, 128*GDISP_INITIAL_CONTRAST/101-64); // Write contrast delayms(20); // Finish Init @@ -248,7 +248,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { case GDISP_CONTROL_CONTRAST: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; acquire_bus(g); - write_reg(g, CONTRAST,(unsigned)127*g->p.ptr/100-64); + write_reg(g, CONTRAST,(unsigned)128*g->p.ptr/101-64); release_bus(g); g->g.Contrast = (unsigned)g->p.ptr; return; diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index 1bc7282a..f724ee42 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -199,7 +199,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { // P1: 0x00 = page address normal, column address normal, address scan in column direction // P2: 0x00 = RGB sequence (default value) // P3: 0x02 = 4 bits per colour (Type A) - write_cmd2(g, VOLCTR, 63*GDISP_INITIAL_CONTRAST/100, 0x03); // Voltage control (contrast setting) + write_cmd2(g, VOLCTR, 64*GDISP_INITIAL_CONTRAST/101, 0x03); // Voltage control (contrast setting) // P1 = Contrast (0..63) // P2 = 3 resistance ratio (only value that works) delayms(100); // Allow power supply to stabilise @@ -543,7 +543,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { case GDISP_CONTROL_CONTRAST: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; acquire_bus(g); - write_cmd2(g, VOLCTR, 63*(unsigned)g->p.ptr/100, 0x03); + write_cmd2(g, VOLCTR, 64*(unsigned)g->p.ptr/101, 0x03); release_bus(g); g->g.Contrast = (unsigned)g->p.ptr; return; From f4b9f0bcfeb5a71cf5b46073cc30f6e496c23dc2 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 21 Oct 2013 17:12:48 +1000 Subject: [PATCH 082/160] Convert SSD1306 driver to new driver format. This driver requires the new flush operation. --- drivers/gdisp/SSD1306/board_SSD1306_i2c.h | 121 +++ drivers/gdisp/SSD1306/board_SSD1306_spi.h | 122 +++ .../gdisp/SSD1306/board_SSD1306_template.h | 116 +++ drivers/gdisp/SSD1306/gdisp_lld.c | 715 ++++-------------- drivers/gdisp/SSD1306/gdisp_lld.mk | 5 +- .../SSD1306/gdisp_lld_board_example_i2c.h | 137 ---- .../SSD1306/gdisp_lld_board_example_spi.h | 139 ---- .../gdisp/SSD1306/gdisp_lld_board_template.h | 74 -- drivers/gdisp/SSD1306/gdisp_lld_config.h | 14 +- 9 files changed, 513 insertions(+), 930 deletions(-) create mode 100644 drivers/gdisp/SSD1306/board_SSD1306_i2c.h create mode 100644 drivers/gdisp/SSD1306/board_SSD1306_spi.h create mode 100644 drivers/gdisp/SSD1306/board_SSD1306_template.h delete mode 100644 drivers/gdisp/SSD1306/gdisp_lld_board_example_i2c.h delete mode 100644 drivers/gdisp/SSD1306/gdisp_lld_board_example_spi.h delete mode 100644 drivers/gdisp/SSD1306/gdisp_lld_board_template.h diff --git a/drivers/gdisp/SSD1306/board_SSD1306_i2c.h b/drivers/gdisp/SSD1306/board_SSD1306_i2c.h new file mode 100644 index 00000000..c89562e0 --- /dev/null +++ b/drivers/gdisp/SSD1306/board_SSD1306_i2c.h @@ -0,0 +1,121 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1306/board_SSD1306_i2c.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1306 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +#define GDISP_BUS_MAX_TRANSFER_SIZE 64 + +// For a multiple display configuration we would put all this in a structure and then +// set g->board to that structure. +#define SSD1306_RESET_PORT GPIOB +#define SSD1306_RESET_PIN 5 + +/** + * The default slave address is 0x3D, (talking about + * only the real address part here) and the slave + * address can be changed to 0x3C by soldering the + * SA0 pads on the bottom side of the module. + * + * b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 + * -------------------------------------- + * 0 | 1 | 1 | 1 | 1 | 0 |SA0 | R/W + */ +#define SSD1306_I2C_ADDRESS 0x3D +#define SSD1306_SDA_PORT GPIOB +#define SSD1306_SDA_PIN 7 +#define SSD1306_SCL_PORT GPIOB +#define SSD1306_SCL_PIN 6 +#define SET_RST palSetPad(SSD1306_RESET_PORT, SSD1306_RESET_PIN); +#define CLR_RST palClearPad(SSD1306_RESET_PORT, SSD1306_RESET_PIN); + +// I2C configuration structure. +static I2CConfig i2cconfig; + +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + // RESET pin. + palSetPadMode(SSD1306_RESET_PORT, SSD1306_RESET_PIN, PAL_MODE_OUTPUT_PUSHPULL); + + + /* + * Initializes the I2C driver 1. The I2C1 signals are routed as follows: + * PB6 - SCL. + * PB7 - SDA. + * Timing value comes from ST I2C config tool (xls): + * 0x00901D2B; // 100kHz Standard Mode + * 0x00300444; // 100kHz Fast Mode + * 0x0030020A; // 400kHz Fast Mode + * 0x00100002; // 800kHz Fast Mode + + */ + i2cconfig.timingr = 0x00100002; // 800kHz Fast Mode+ + i2cInit(); + palSetPadMode(SSD1306_SCL_PORT, SSD1306_SCL_PIN, PAL_MODE_ALTERNATE(1)); + palSetPadMode(SSD1306_SDA_PORT, SSD1306_SDA_PIN, PAL_MODE_ALTERNATE(1)); + break; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if(state) + CLR_RST + else + SET_RST +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; + i2cAcquireBus(&I2CD1); +} + +static inline void release_bus(GDisplay *g) { + (void) g; + i2cReleaseBus(&I2CD1); +} + +static inline void write_cmd(GDisplay *g, uint8_t cmd) { + uint8_t command[2]; + (void) g; + + command[0] = 0x00; // Co = 0, D/C = 0 + command[1] = cmd; + + i2cStart(&I2CD1, &i2cconfig); + i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, command, 2, NULL, 0, MS2ST(10)); + i2cStop(&I2CD1); +} + +static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { + uint8_t command[1]; + (void) g; + + command[0] = 0x40; // Co = 0, D/C = 1 + + i2cStart(&I2CD1, &i2cconfig); + i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, command, 1, NULL, 0, MS2ST(10)); + i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, command, data, NULL, length, MS2ST(10)); + i2cStop(&I2CD1); +} + +#endif /* _GDISP_LLD_BOARD_H */ + + diff --git a/drivers/gdisp/SSD1306/board_SSD1306_spi.h b/drivers/gdisp/SSD1306/board_SSD1306_spi.h new file mode 100644 index 00000000..e206a517 --- /dev/null +++ b/drivers/gdisp/SSD1306/board_SSD1306_spi.h @@ -0,0 +1,122 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1306/board_SSD1306_spi.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1306 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +#define GDISP_BUS_MAX_TRANSFER_SIZE 64 + +// For a multiple display configuration we would put all this in a structure and then +// set g->board to that structure. +#define SSD1306_RESET_PORT GPIOB +#define SSD1306_RESET_PIN 5 +#define SSD1306_MISO_PORT GPIOB +#define SSD1306_MISO_PIN 8 +#define SSD1306_MOSI_PORT GPIOB +#define SSD1306_MOSI_PIN 7 +#define SSD1306_SCK_PORT GPIOB +#define SSD1306_SCK_PIN 6 +#define SSD1306_CS_PORT GPIOB +#define SSD1306_CS_PIN 5 +#define SET_RST palSetPad(SSD1306_RESET_PORT, SSD1306_RESET_PIN); +#define CLR_RST palClearPad(SSD1306_RESET_PORT, SSD1306_RESET_PIN); + +/* + * SPI1 configuration structure. + * Speed 42MHz, CPHA=0, CPOL=0, 8bits frames, MSb transmitted first. + * The slave select line is the pin 4 on the port GPIOA. + */ +static const SPIConfig spi1config = { + NULL, + /* HW dependent part.*/ + SSD1306_MISO_PORT, + SSD1306_MISO_PIN, + 0 + //SPI_CR1_BR_0 +}; + +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + // RESET pin. + palSetPadMode(SSD1306_RESET_PORT, SSD1306_RESET_PIN, PAL_MODE_OUTPUT_PUSHPULL); + + spiInit(); + palSetPadMode(SSD1306_MISO_PORT, SSD1306_MISO_PIN, PAL_MODE_ALTERNATE(1)| + PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SSD1306_MOSI_PORT, SSD1306_MOSI_PIN, PAL_MODE_ALTERNATE(1)| + PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(SSD1306_SCK_PORT, SSD1306_SCK_PIN, PAL_MODE_ALTERNATE(1)| + PAL_STM32_OSPEED_HIGHEST); + palSetPad(SSD1306_CS_PORT, SSD1306_CS_PIN); + palSetPadMode(SSD1306_CS_PORT, SSD1306_CS_PIN, PAL_MODE_ALTERNATE(1)| + PAL_STM32_OSPEED_HIGHEST); + break; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if(state) + CLR_RST + else + SET_RST +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; + spiAcquireBus(&SPID1); +} + +static inline void release_bus(GDisplay *g) { + (void) g; + spiReleaseBus(&SPID1); +} + +static inline void write_cmd(GDisplay *g, uint8_t cmd) { + uint8_t command[2]; + + command[0] = 0x00; // Co = 0, D/C = 0 + command[1] = cmd; + + spiStart(&SPID1, &spi1config); + spiSelect(&SPID1); + spiStartSend(&SPID1, 2, command); + spiUnselect(&SPID1); + spiStop(&SPID1); +} + +static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { + uint8_t command[1]; + (void) g; + + command[0] = 0x40; // Co = 0, D/C = 1 + + spiStart(&SPID1, &spi1config); + spiSelect(&SPID1); + spiStartSend(&SPID1, 1, command); + spiStartSend(&SPID1, length, data); + spiUnselect(&SPID1); + spiStop(&SPID1); +} + + +#endif /* _GDISP_LLD_BOARD_H */ + diff --git a/drivers/gdisp/SSD1306/board_SSD1306_template.h b/drivers/gdisp/SSD1306/board_SSD1306_template.h new file mode 100644 index 00000000..ec7f44f5 --- /dev/null +++ b/drivers/gdisp/SSD1306/board_SSD1306_template.h @@ -0,0 +1,116 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1306/board_SSD1306_template.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1306 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief How many bytes to write in one operation when updating the display. + * @note The screen size (in bytes) must evenly divide by this number. + * + * @notapi + */ +#define GDISP_BUS_MAX_TRANSFER_SIZE 64 + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * + * @note Set the g->board member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send a command to the controller. + * + * @param[in] g The GDisplay structure + * @param[in] cmd The command to send * + * + * @notapi + */ +static inline void write_cmd(GDisplay *g, uint8_t cmd) { + (void) g; + (void) cmd; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { + (void) g; + (void) data; + (void) length; +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ + diff --git a/drivers/gdisp/SSD1306/gdisp_lld.c b/drivers/gdisp/SSD1306/gdisp_lld.c index 5f337b54..36ba9686 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld.c +++ b/drivers/gdisp/SSD1306/gdisp_lld.c @@ -5,642 +5,219 @@ * http://ugfx.org/license.html */ -#include "gfx.h" +/** + * @file drivers/gdisp/SSD1306/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the SSD1306 display. + */ -#include "SSD1306.h" +#include "gfx.h" #if GFX_USE_GDISP || defined(__DOXYGEN__) -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" +#define GDISP_DRIVER_VMT GDISPVMT_SSD1306 +#include "../drivers/gdisp/SSD1306/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" + +#include "board_SSD1306.h" /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ #ifndef GDISP_SCREEN_HEIGHT - #define GDISP_SCREEN_HEIGHT 64 + #define GDISP_SCREEN_HEIGHT 64 // This controller should support 32 (untested) or 64 #endif #ifndef GDISP_SCREEN_WIDTH #define GDISP_SCREEN_WIDTH 128 #endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 100 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif -#define GDISP_INITIAL_CONTRAST 0xFF +#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0) + +#include "SSD1306.h" /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -// Include wiring specific header -#include "gdisp_lld_board_example_i2c.h" +// Some common routines and macros +#define RAM(g) ((uint8_t *)g->priv) +#define write_cmd2(g, cmd1, cmd2) { write_cmd(g, cmd1); write_cmd(g, cmd2); } +#define write_cmd3(g, cmd1, cmd2, cmd3) { write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); } // Some common routines and macros #define delay(us) gfxSleepMicroseconds(us) #define delayms(ms) gfxSleepMilliseconds(ms) -// The memory buffer for the display -static uint8_t gdisp_buffer[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8]; - -/** Set the display to normal or inverse. - * @param[in] value 0 for normal mode, or 1 for inverse mode. - * @notapi - */ -static void invert_display(uint8_t i) { - write_cmd(i ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY); -} - -/** Turn the whole display off. - * Sends the display to sleep, but leaves RAM intact. - * @notapi - */ -static void display_off(){ - write_cmd(SSD1306_DISPLAYOFF); -} - -/** Turn the whole display on. - * Wakes up this display following a sleep() call. - * @notapi - */ -static void display_on() { - write_cmd(SSD1306_DISPLAYON); -} - -/** Set the vertical shift by COM. - * @param[in] value The number of rows to shift, from 0 - 63. - * @notapi -*/ -static void set_display_offset(unsigned char value) { - write_cmd(SSD1306_SETDISPLAYOFFSET); - write_cmd(value & 0x3F); -} - -/** Set the display contrast. - * @param[in] value The contrast, from 1 to 256. - * @notapi - */ -static void set_contrast(unsigned char value) { - write_cmd(SSD1306_SETCONTRAST); - write_cmd(value); -} - -/** Set the display start line. This is the line at which the display will start rendering. - * @param[in] value A value from 0 to 63 denoting the line to start at. - * @notapi - */ -static void set_display_start_line(unsigned char value) { - write_cmd(SSD1306_SETSTARTLINE | value); -} - -/** Set the segment remap state. This allows the module to be addressed as if flipped horizontally. - * NOTE: Changing this setting has no effect on data already in the module's GDDRAM. - * @param[in] value 0 = column address 0 = segment 0 (the default), 1 = column address 127 = segment 0 (flipped). - * @notapi - */ -static void set_segment_remap(unsigned char value) { - write_cmd(value ? SSD1306_SEGREMAP+1 : SSD1306_SEGREMAP); -} - -/** Set the multiplex ratio. - * @param[in] value MUX will be set to (value+1). Valid values range from 15 to 63 - MUX 16 to 64. - * @notapi - */ -static void set_multiplex_ratio(unsigned char value) { - write_cmd(SSD1306_SETMULTIPLEX); - write_cmd(value & 0x3F); -} - -/** Set COM output scan direction. If the display is active, this will immediately vertically - * flip the display. - * @param[in] value 0 = Scan from COM0 (default), 1 = reversed (scan from COM[N-1]). - * @notapi - */ -static void set_com_output_scan_direction(unsigned char value) { - write_cmd(value ? SSD1306_COMSCANDEC : SSD1306_COMSCANINC); -} - -static void set_com_pins_hardware_configuration(unsigned char sequential, unsigned char lr_remap) { - write_cmd(SSD1306_SETCOMPINS); - write_cmd(0x02 | ((sequential & 1) << 4) | ((lr_remap & 1) << 5)); -} - -/** Flip display content horizontally. - * NOTE: This only flips display content, but doesn't turn the char writing around. - * You have to unmirror everything manually. - * @param[in] value 0 = column address 0 = segment 0 (the default), 1 = column address 127 = segment 0 (flipped). - * @notapi - */ -static void flip_display(unsigned char enable) { - if( enable && GDISP.Orientation == GDISP_ROTATE_0) { - set_com_output_scan_direction(0); - set_segment_remap(0); - GDISP.Orientation = GDISP_ROTATE_0; - } - if( !enable && GDISP.Orientation == GDISP_ROTATE_180) { - set_com_output_scan_direction(1); - set_segment_remap(1); - GDISP.Orientation = GDISP_ROTATE_180; - } - else - return; -} - -/** Perform a "no operation". - * @notapi - */ -static void nop() { - write_cmd(0xE3); -} - -/** Page Addressing Mode: Set the column start address register for - * page addressing mode. - * @param[in] address The address (full byte). - * @notapi - */ -static void set_start_address_pam(unsigned char address) -{ - // "Set Lower Column Start Address for Page Addressing Mode" - write_cmd(address & 0x0F); - - // "Set Higher Column Start Address for Page Addressing Mode" - write_cmd((address << 4) & 0x0F); -} - -/** Set memory addressing mode to the given value. - * @param[in] mode 0 for Horizontal addressing mode,\n 1 for Vertical addressing mode,\n or 2 for Page addressing mode (PAM). 2 is the default. - * @notapi - */ -static void set_memory_addressing_mode(unsigned char mode) -{ - write_cmd(SSD1306_MEMORYMODE); - write_cmd(mode & 0x3); -} - -/** Set column address range for horizontal/vertical addressing mode. - * @param[in] start Column start address, 0 - 127. - * @param[in] end Column end address, 0 - 127. - * @notapi - */ -static void set_column_address_hvam(unsigned char start, unsigned char end) -{ - write_cmd(SSD1306_HV_COLUMN_ADDRESS); - write_cmd(start & 0x7F); - write_cmd(end & 0x7F); -} - -/** Set page start and end address for horizontal/vertical addressing mode. - * @param[in] start The start page, 0 - 7. - * @param[in] end The end page, 0 - 7. - * @notapi - */ -static void set_page_address_hvam(unsigned char start, unsigned char end) -{ - write_cmd(SSD1306_HV_PAGE_ADDRESS); - write_cmd(start & 0x07); - write_cmd(end & 0x07); -} - -/** Set the GDDRAM page start address for page addressing mode. - * @param[in] address The start page, 0 - 7. - * @notapi - */ -static void set_page_start_pam(unsigned char address) -{ - write_cmd(SSD1306_PAM_PAGE_START | (address & 0x07)); -} - -/** Set the display clock divide ratio and the oscillator frequency. - * @param[in] ratio The divide ratio, default is 0. - * @param[in] frequency The oscillator frequency, 0 - 127. Default is 8. - * @notapi - */ -static void set_display_clock_ratio_and_frequency(unsigned char ratio, unsigned char frequency) -{ - write_cmd(SSD1306_SETDISPLAYCLOCKDIV); - write_cmd((ratio & 0x0F) | ((frequency & 0x0F) << 4)); -} - -/** Set the precharge period. - * @param[in] phase1 Phase 1 period in DCLK clocks. 1 - 15, default is 2. - * @param[in] phase2 Phase 2 period in DCLK clocks. 1 - 15, default is 2. - * @notapi - */ -static void set_precharge_period(unsigned char phase1, unsigned char phase2) -{ - write_cmd(SSD1306_SETPRECHARGE); - write_cmd((phase1 & 0x0F) | ((phase2 & 0x0F ) << 4)); -} - -/** Set the Vcomh deselect level. - * @param[in] level @p 0 = 0.65 x Vcc, @p 1 = 0.77 x Vcc (default), @p 2 = 0.83 x Vcc. - * @notapi - */ -static void set_vcomh_deselect_level(unsigned char level) -{ - write_cmd(SSD1306_SETVCOMDETECT); - write_cmd((level & 0x03) << 4); -} - -/** Enable/disable charge pump. - * @param[in] enable 0 to disable, 1 to enable the internal charge pump. - * @notapi - */ -static void set_charge_pump(unsigned char enable) -{ - write_cmd(SSD1306_ENABLE_CHARGE_PUMP); - write_cmd(enable ? 0x14 : 0x10); -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ - /** - * @brief Low level GDISP driver initialization. - * - * @notapi + * As this controller can't update on a pixel boundary we need to maintain the + * the entire display surface in memory so that we can do the necessary bit + * operations. Fortunately it is a small display in monochrome. + * 64 * 128 / 8 = 1024 bytes. */ -bool_t gdisp_lld_init(void) { - // Initialize your display - init_board(); - // Hardware reset. - setpin_reset(TRUE); - delayms(1); - setpin_reset(FALSE); - delayms(10); - setpin_reset(TRUE); +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // The private area is the display surface. + g->priv = gfxAlloc(GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8); - // Get the bus for the following initialization commands. - acquire_bus(); + // Initialise the board interface + init_board(g); - display_off(); - set_display_clock_ratio_and_frequency(0, 8); + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(20); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(20); + + acquire_bus(g); + + write_cmd(g, SSD1306_DISPLAYOFF); + write_cmd2(g, SSD1306_SETDISPLAYCLOCKDIV, 0x80); + write_cmd2(g, SSD1306_SETMULTIPLEX, GDISP_SCREEN_HEIGHT-1); + write_cmd2(g, SSD1306_SETPRECHARGE, 0x1F); + write_cmd2(g, SSD1306_SETDISPLAYOFFSET, 0); + write_cmd(g, SSD1306_SETSTARTLINE | 0); + write_cmd2(g, SSD1306_ENABLE_CHARGE_PUMP, 0x14); + write_cmd2(g, SSD1306_MEMORYMODE, 0); + write_cmd(g, SSD1306_SEGREMAP+1); + write_cmd(g, SSD1306_COMSCANDEC); #if GDISP_SCREEN_HEIGHT == 64 - set_multiplex_ratio(0x3F); // 1/64 duty + write_cmd2(g, SSD1306_SETCOMPINS, 0x12); + #else + write_cmd2(g, SSD1306_SETCOMPINS, 0x22); #endif - #if GDISP_SCREEN_HEIGHT == 32 - set_multiplex_ratio(0x1F); // 1/32 duty - #endif - set_precharge_period(0xF, 0x01); // - set_display_offset(0); // - set_display_start_line(0); // - set_charge_pump(1); // Enable internal charge pump. - set_memory_addressing_mode(0); // horizontal addressing mode; across then down //act like ks0108 (horizontal addressing mode) - set_segment_remap(1); // - set_com_output_scan_direction(1); // - #if GDISP_SCREEN_HEIGHT == 64 - set_com_pins_hardware_configuration(1, 0); - #endif - #if GDISP_SCREEN_HEIGHT == 32 - set_com_pins_hardware_configuration(0, 1); - #endif - set_contrast(GDISP_INITIAL_CONTRAST); // Set initial contrast. - set_vcomh_deselect_level(1); // - display_on(); // Turn on OLED panel. - invert_display(0); // Disable Inversion of display. - set_column_address_hvam(0, 127); // - set_page_address_hvam(0, 7); // + write_cmd2(g, SSD1306_SETCONTRAST, (uint8_t)(GDISP_INITIAL_CONTRAST*256/101)); // Set initial contrast. + write_cmd2(g, SSD1306_SETVCOMDETECT, 0x10); + write_cmd(g, SSD1306_DISPLAYON); + write_cmd(g, SSD1306_NORMALDISPLAY); + write_cmd3(g, SSD1306_HV_COLUMN_ADDRESS, 0, GDISP_SCREEN_WIDTH-1); + write_cmd3(g, SSD1306_HV_PAGE_ADDRESS, 0, GDISP_SCREEN_HEIGHT/8-1); - release_bus(); + // Finish Init + post_init_board(g); - gdisp_lld_display(); + // Release the bus + release_bus(g); - // Initialize the GDISP structure - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Contrast = GDISP_INITIAL_CONTRAST; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay *g) { + unsigned i; - if (color == SSD1306_WHITE) - gdisp_buffer[x+ (y/8)*GDISP_SCREEN_WIDTH] |= (1<flags & GDISP_FLG_NEEDFLUSH)) + return; -void gdisp_lld_display() { - set_display_start_line(0); + write_cmd(g, SSD1306_SETSTARTLINE | 0); - /* We're sending half a line in one X-mission.*/ - uint8_t command[GDISP_SCREEN_WIDTH/2], - cmdLength = sizeof(command)/sizeof(command[0]), - parts = GDISP_SCREEN_WIDTH/cmdLength; - - for(int i=0; i= cy, it is equivalent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - /* See datasheet table T10-1 for this*/ - uint8_t fHeight = (uint8_t)gdispGetFontMetric(gwinGetDefaultFont(), fontLineSpacing); - set_multiplex_ratio(GDISP_SCREEN_HEIGHT - fHeight+1); - set_display_offset(fHeight-2); - - /* Scrolling animation.*/ - for(int i=0; i> fHeight % 8; - gdisp_buffer[i] |= gdisp_buffer[i+GDISP_SCREEN_WIDTH*(fHeight/8 + 1)] << (8 - fHeight%8); - } - - /* Clear last page.*/ - memset( &gdisp_buffer[GDISP_SCREEN_HEIGHT*GDISP_SCREEN_WIDTH/8 - GDISP_SCREEN_WIDTH*2], SSD1306_BLACK, GDISP_SCREEN_WIDTH*2); - - /* Update display.*/ - gdisp_lld_display(); +#if GDISP_HARDWARE_DRAWPIXEL + LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + if (g->p.color != Black) + RAM(g)[g->p.x + (g->p.y>>3)*GDISP_SCREEN_WIDTH] |= (1<<(g->p.y&7)); + else + RAM(g)[g->p.x + (g->p.y>>3)*GDISP_SCREEN_WIDTH] &= ~(1<<(g->p.y&7)); + g->flags |= GDISP_FLG_NEEDFLUSH; } +#endif - /** - * @warning Implementation only fully supports left and right...some command issues here. - * Activate a scroll for rows start through stop. - * Hint, the display is 16 rows tall. To scroll the whole display, run: - * @code - * display.scrollright(0x00, 0x0F) - * @endcode - * @param[in] start The start of the area to be scrolled - * @param[in] stop The size of the area to be scrolled - * @param[in] dir direction of scrolling - * [left, right, up, down, up_right, up_left, down_left, down_right] - * @note Optional. * - * - * @notapi - */ - void gdisp_lld_start_scroll(uint8_t dir, uint8_t start, uint8_t stop, uint8_t interval){ -// if(dir == GDISP_SCROLL_RIGHT || GDISP_SCROLL_LEFT || GDISP_SCROLL_UP) { -// switch (dir) { -// case GDISP_SCROLL_RIGHT: -// write_cmd(SSD1306_SCROLL_HORIZONTAL_RIGHT); -// break; -// case GDISP_SCROLL_LEFT: -// write_cmd(SSD1306_SCROLL_HORIZONTAL_LEFT); -// break; -// } -// write_cmd(0X00); // Dummy byte. -// write_cmd(start & 0x07); // Define start page address. -// switch (interval) { // Set time interval between each scroll step (5 frames) -// case 2: write_cmd(0x07); break; // 111b -// case 3: write_cmd(0x04); break; // 100b -// case 4: write_cmd(0x05); break; // 101b -// case 5: write_cmd(0x00); break; // 000b -// case 25: write_cmd(0x06); break; // 110b -// case 64: write_cmd(0x01); break; // 001b -// case 128: write_cmd(0x02); break; // 010b -// case 256: write_cmd(0x03); break; // 011b -// default: -// // default to 2 frame interval -// write_cmd(0x07); break; -// } -// write_cmd(stop & 0x07); // Define stop page address -// write_cmd(0X01); // Set vertical scrolling offset as no row. -// write_cmd(0XFF); // Undocumented but needed. -// write_cmd(SSD1306_SCROLL_ACTIVATE); -// } -// else if(dir == GDISP_SCROLL_UP || GDISP_SCROLL_DOWN) { -// switch (dir) { -// case GDISP_SCROLL_UP: -// gdisp_lld_set_vertical_scroll_area(0x00, GDISP_SCREEN_HEIGHT); -// write_cmd(SSD1306_SCROLL_VERTICAL_AND_HORIZONTAL_RIGHT); -// break; -// -// case GDISP_SCROLL_DOWN: -// gdisp_lld_set_vertical_scroll_area(0x00, GDISP_SCREEN_HEIGHT); -// write_cmd(SSD1306_SCROLL_VERTICAL_AND_HORIZONTAL_LEFT); -// break; -// } -// write_cmd(0X00); // Dummy byte. -// write_cmd(start); // Define start page address. -// write_cmd(0X00); // Set time interval between each scroll step (5 frames) -// write_cmd(stop); // Define stop page address -// write_cmd(0X01); // Set vertical scrolling offset as no row. -// write_cmd(SSD1306_SCROLL_ACTIVATE); -// gdisp_lld_set_vertical_scroll_area(0x00, GDISP_SCREEN_HEIGHT-10); -// write_cmd(SSD1306_SCROLL_VERTICAL_AND_HORIZONTAL_RIGHT); -// write_cmd(0X00); // Dummy byte. -// write_cmd(start); // Define start page address. -// write_cmd(0X00); // Set time interval between each scroll step (5 frames) -// write_cmd(stop); // Define stop page address -// write_cmd(0X03); // Set vertical scrolling offset as no row. -// write_cmd(SSD1306_SCROLL_ACTIVATE); -// } +#if GDISP_HARDWARE_PIXELREAD + LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { + return (RAM(g)[g->p.x + (g->p.y>>3)*GDISP_SCREEN_WIDTH] & (1<<(g->p.y&7))) ? White : Black; } +#endif - /** - * Sets vertical scroll area of display. - * @param[in] start The start of the area to be scrolled [y coordinate] - * @param[in] stop The size of the area to be scrolled [y coordinate] - * @note Optional. * - * - * @notapi - */ - void gdisp_lld_set_vertical_scroll_area(uint8_t start, uint8_t stop){ - write_cmd(SSD1306_SCROLL_SET_VERTICAL_SCROLL_AREA); - write_cmd(start); - write_cmd(stop); - } - - /** Deactivate the continuous scroll set up with start_horizontal_scroll() or - * start_vertical_and_horizontal_scroll(). - * @see set_horizontal_scroll, set_vertical_and_horizontal_scroll - * @notapi - */ - void gdisp_lld_stop_scroll(void){ - write_cmd(SSD1306_SCROLL_DEACTIVATE); - } -#endif // GDISP_NEED_SCROLL - -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - for(int i=x; ip.x) { case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) + if (g->g.Powermode == (powermode_t)g->p.ptr) return; - switch((gdisp_powermode_t)value) { + switch((powermode_t)g->p.ptr) { case powerOff: - display_off(); case powerSleep: - display_off(); case powerDeepSleep: - display_off(); + acquire_bus(g); + write_cmd(g, SSD1306_DISPLAYOFF); + release_bus(g); + break; case powerOn: - display_on(); + acquire_bus(g); + write_cmd(g, SSD1306_DISPLAYON); + release_bus(g); default: return; } - GDISP.Powermode = (gdisp_powermode_t)value; + g->g.Powermode = (powermode_t)g->p.ptr; return; + case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) - return; - switch((gdisp_orientation_t)value) { - case GDISP_ROTATE_0: - flip_display(0); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_180: - flip_display(1); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - default: - return; - } - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; + if (g->g.Orientation == (orientation_t)g->p.ptr) return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(g); + write_cmd(g, SSD1306_COMSCANDEC); + write_cmd(g, SSD1306_SEGREMAP+1); + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Width = GDISP_SCREEN_WIDTH; + release_bus(g); + break; + case GDISP_ROTATE_180: + acquire_bus(g); + write_cmd(g, SSD1306_COMSCANINC); + write_cmd(g, SSD1306_SEGREMAP); + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Width = GDISP_SCREEN_WIDTH; + release_bus(g); + break; + default: + return; + } + g->g.Orientation = (orientation_t)value; + return; + case GDISP_CONTROL_CONTRAST: - if ((unsigned)value > 100) - value = (void *)100; - if (GDISP.Contrast == (uint8_t)((float)((uint8_t)value) * 256.0/100.0) ) - return; - set_contrast((uint8_t)((float)((uint8_t)value) * 256.0/100.0) ); - GDISP.Contrast = (unsigned)value; - return; + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + acquire_bus(g); + write_cmd2(g, SSD1306_SETCONTRAST, (((uint16_t)value)<<8)/101); + release_bus(g); + g->g.Contrast = (unsigned)g->p.ptr; + return; + + // Our own special controller code to inverse the display + // 0 = normal, 1 = inverse + case GDISP_CONTROL_INVERT: + acquire_bus(g); + write_cmd(g, g->p.ptr ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY); + release_bus(g); + return; } } #endif // GDISP_NEED_CONTROL -/** - * Let the display blink several times by means of invert and invert back. - * @param num number of blink cycles to do - * @param speed milliseconds to wait between toggling inversion - * @param wait milliseconds to wait before start of all blink cycles and after finishing blink cycles - * @notapi - */ - void gdisp_lld_display_blink(uint8_t num, uint16_t speed, uint16_t wait){ - uint8_t inv = 0; - - gfxSleepMilliseconds(wait); - for(int i=0; i<2*num; i++) { - inv ^= 1; - invert_display(inv); - gfxSleepMilliseconds(speed); - } - gfxSleepMilliseconds(wait); -} - #endif // GFX_USE_GDISP -/** @} */ diff --git a/drivers/gdisp/SSD1306/gdisp_lld.mk b/drivers/gdisp/SSD1306/gdisp_lld.mk index 2a2e1364..ad320292 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld.mk +++ b/drivers/gdisp/SSD1306/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1306/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/SSD1306 +GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1306/gdisp_lld.c diff --git a/drivers/gdisp/SSD1306/gdisp_lld_board_example_i2c.h b/drivers/gdisp/SSD1306/gdisp_lld_board_example_i2c.h deleted file mode 100644 index 0e7e153a..00000000 --- a/drivers/gdisp/SSD1306/gdisp_lld_board_example_i2c.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -#define SSD1306_RESET_PORT GPIOB -#define SSD1306_RESET_PIN 5 - -/** - * The default slave address is 0x3D, (talking about - * only the real address part here) and the slave - * address can be changed to 0x3C by soldering the - * SA0 pads on the bottom side of the module. - * - * b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 - * -------------------------------------- - * 0 | 1 | 1 | 1 | 1 | 0 |SA0 | R/W - */ -#define SSD1306_I2C_ADDRESS 0x3D -#define SSD1306_SDA_PORT GPIOB -#define SSD1306_SDA_PIN 7 -#define SSD1306_SCL_PORT GPIOB -#define SSD1306_SCL_PIN 6 -#define SET_RST palSetPad(SSD1306_RESET_PORT, SSD1306_RESET_PIN); -#define CLR_RST palClearPad(SSD1306_RESET_PORT, SSD1306_RESET_PIN); -int8_t vccstate; -int32_t row_offset = 0; - -// I2C configuration structure. -static I2CConfig i2cconfig; - - -/** - * @brief Initialize the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins - * @notapi - */ -static inline void init_board(void) { - - // RESET pin. - palSetPadMode(SSD1306_RESET_PORT, SSD1306_RESET_PIN, PAL_MODE_OUTPUT_PUSHPULL); - - - /* - * Initializes the I2C driver 1. The I2C1 signals are routed as follows: - * PB6 - SCL. - * PB7 - SDA. - * Timing value comes from ST I2C config tool (xls): - * 0x00901D2B; // 100kHz Standard Mode - * 0x00300444; // 100kHz Fast Mode - * 0x0030020A; // 400kHz Fast Mode - * 0x00100002; // 800kHz Fast Mode + - */ - i2cconfig.timingr = 0x00100002; // 800kHz Fast Mode+ - i2cInit(); - palSetPadMode(SSD1306_SCL_PORT, SSD1306_SCL_PIN, PAL_MODE_ALTERNATE(1)); - palSetPadMode(SSD1306_SDA_PORT, SSD1306_SDA_PIN, PAL_MODE_ALTERNATE(1)); - vccstate = SSD1306_SWITCHCAPVCC; -} - -/** - * @brief Set or clear the lcd reset pin. - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * @notapi - */ -static inline void setpin_reset(bool_t state) { - if(state) - SET_RST - else - CLR_RST -} - -/** - * @brief Set the lcd back-light level. - * @param[in] percent 0 to 100% - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - // Since we are on OLED no backlight needed -} - -/** - * @brief Take exclusive control of the bus - * @notapi - */ -static inline void acquire_bus(void) { - i2cAcquireBus(&I2CD1); -} - -/** - * @brief Release exclusive control of the bus - * @notapi - */ -static inline void release_bus(void) { - i2cReleaseBus(&I2CD1); -} - -/** - * @brief Send command to the display. - * @param[in] cmd The command to send * - * @notapi - */ -static inline void write_cmd(uint8_t cmd) { - uint8_t command[] = { 0x00, // Co = 0, D/C = 0 - cmd }, - txLength = sizeof(command)/sizeof(command[0]), - rxLength = 0; - i2cStart(&I2CD1, &i2cconfig); - i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, command, txLength, NULL, rxLength, MS2ST(10)); - i2cStop(&I2CD1); -} - -/** - * @brief Send data to the display. - * @param[in] data The data to send - * @notapi - */ -static inline void write_data(uint8_t* data, uint16_t length) { - uint8_t command[length+1], - txLength = length+1, - rxLength = 0; - command[0] = 0x40; // Co = 0, D/C = 1 - memmove(&command[1], data, length); - - i2cStart(&I2CD1, &i2cconfig); - i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, command, txLength, NULL, rxLength, MS2ST(10)); - i2cStop(&I2CD1); -} - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/SSD1306/gdisp_lld_board_example_spi.h b/drivers/gdisp/SSD1306/gdisp_lld_board_example_spi.h deleted file mode 100644 index 232cd58c..00000000 --- a/drivers/gdisp/SSD1306/gdisp_lld_board_example_spi.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -#define SSD1306_RESET_PORT GPIOB -#define SSD1306_RESET_PIN 5 -#define SSD1306_MISO_PORT GPIOB -#define SSD1306_MISO_PIN 8 -#define SSD1306_MOSI_PORT GPIOB -#define SSD1306_MOSI_PIN 7 -#define SSD1306_SCK_PORT GPIOB -#define SSD1306_SCK_PIN 6 -#define SSD1306_CS_PORT GPIOB -#define SSD1306_CS_PIN 5 -#define SET_RST palSetPad(SSD1306_RESET_PORT, SSD1306_RESET_PIN); -#define CLR_RST palClearPad(SSD1306_RESET_PORT, SSD1306_RESET_PIN); -int8_t vccstate; -int32_t row_offset = 0; - -/* - * SPI1 configuration structure. - * Speed 42MHz, CPHA=0, CPOL=0, 8bits frames, MSb transmitted first. - * The slave select line is the pin 4 on the port GPIOA. - */ -static const SPIConfig spi1config = { - NULL, - /* HW dependent part.*/ - SSD1306_MISO_PORT, - SSD1306_MISO_PIN, - 0 - //SPI_CR1_BR_0 -}; - -/** - * @brief Initialize the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins - * @notapi - */ -static inline void init_board(void) { - - // RESET pin. - palSetPadMode(SSD1306_RESET_PORT, SSD1306_RESET_PIN, PAL_MODE_OUTPUT_PUSHPULL); - - spiInit(); - palSetPadMode(SSD1306_MISO_PORT, SSD1306_MISO_PIN, PAL_MODE_ALTERNATE(1)| - PAL_STM32_OSPEED_HIGHEST); - palSetPadMode(SSD1306_MOSI_PORT, SSD1306_MOSI_PIN, PAL_MODE_ALTERNATE(1)| - PAL_STM32_OSPEED_HIGHEST); - palSetPadMode(SSD1306_SCK_PORT, SSD1306_SCK_PIN, PAL_MODE_ALTERNATE(1)| - PAL_STM32_OSPEED_HIGHEST); - palSetPad(SSD1306_CS_PORT, SSD1306_CS_PIN); - palSetPadMode(SSD1306_CS_PORT, SSD1306_CS_PIN, PAL_MODE_ALTERNATE(1)| - PAL_STM32_OSPEED_HIGHEST); - vccstate = SSD1306_SWITCHCAPVCC; -} - -/** - * @brief Set or clear the lcd reset pin. - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * @notapi - */ -static inline void setpin_reset(bool_t state) { - if(state) - SET_RST - else - CLR_RST -} - -/** - * @brief Set the lcd back-light level. - * @param[in] percent 0 to 100% - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - // Since we are on OLED no backlight needed -} - -/** - * @brief Take exclusive control of the bus - * @notapi - */ -static inline void acquire_bus(void) { - spiAcquireBus(&SPID1); -} - -/** - * @brief Release exclusive control of the bus - * @notapi - */ -static inline void release_bus(void) { - spiReleaseBus(&SPID1); -} - -/** - * @brief Send command to the display. - * @param[in] cmd The command to send * - * @notapi - */ -static inline void write_cmd(uint8_t cmd) { - uint8_t command[] = { 0x00, // Co = 0, D/C = 0 - cmd }, - txLength = sizeof(command)/sizeof(command[0]), - rxLength = 0; - - spiStart(&SPID1, &spi1config); - spiSelect(&SPID1); - spiStartSend(&SPID1, txLength, command); - spiUnselect(&SPID1); - spiStop(&SPID1); -} - -/** - * @brief Send data to the display. - * @param[in] data The data to send - * @notapi - */ -static inline void write_data(uint8_t* data, uint16_t length) { - uint8_t command[length+1], - txLength = length+1; - command[0] = 0x40; // Co = 0, D/C = 1 - memmove(&command[1], data, length); - - spiStart(&SPID1, &spi1config); - spiSelect(&SPID1); - spiStartSend(&SPID1, txLength, command); - spiUnselect(&SPID1); - spiStop(&SPID1); -} - - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/SSD1306/gdisp_lld_board_template.h b/drivers/gdisp/SSD1306/gdisp_lld_board_template.h deleted file mode 100644 index 48028e83..00000000 --- a/drivers/gdisp/SSD1306/gdisp_lld_board_template.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief Initialize the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins - * @notapi - */ -static inline void init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * @param[in] percent 0 to 100% - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - // Since we are on OLED no backlight needed -} - -/** - * @brief Take exclusive control of the bus - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Send command to the display. - * @param[in] cmd The command to send * - * @notapi - */ -static inline void write_cmd(uint8_t cmd) { - -} - -/** - * @brief Send data to the display. - * @param[in] data The data to send - * @notapi - */ -static inline void write_data(uint8_t* data, uint16_t length) { - -} - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/SSD1306/gdisp_lld_config.h b/drivers/gdisp/SSD1306/gdisp_lld_config.h index f0efc18e..8580f933 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1306/gdisp_lld_config.h @@ -14,17 +14,17 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "SSD1306" - -#define GDISP_HARDWARE_CLEARS FALSE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS FALSE -#define GDISP_HARDWARE_SCROLL TRUE -#define GDISP_HARDWARE_PIXELREAD FALSE +#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_MONO +// This controller supports a special gdispControl() to inverse the display. +// Pass a parameter of 1 for inverse and 0 for normal. +#define GDISP_CONTROL_INVERSE (GDISP_CONTROL_LLD+0) + #endif /* GFX_USE_GDISP */ #endif /* _GDISP_LLD_CONFIG_H */ From 4e8d2569d638c232cb4c15926cf72e2fb42404d5 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 21 Oct 2013 19:38:15 +1000 Subject: [PATCH 083/160] Convert SSD1963 driver to new format. Intergrate the old panel include file into the board file. --- drivers/gdisp/SSD1963/board_SSD1963_fsmc.h | 105 ++++ drivers/gdisp/SSD1963/board_SSD1963_gpio.h | 102 +++ .../gdisp/SSD1963/board_SSD1963_template.h | 148 +++++ drivers/gdisp/SSD1963/gdisp_lld.c | 588 +++++++----------- drivers/gdisp/SSD1963/gdisp_lld.mk | 6 +- .../SSD1963/gdisp_lld_board_example_fsmc.h | 177 ------ .../SSD1963/gdisp_lld_board_example_gpio.h | 191 ------ .../gdisp/SSD1963/gdisp_lld_board_template.h | 115 ---- drivers/gdisp/SSD1963/gdisp_lld_config.h | 10 +- .../gdisp/SSD1963/gdisp_lld_panel_example.h | 74 --- drivers/gdisp/SSD1963/ssd1963.h | 5 - 11 files changed, 581 insertions(+), 940 deletions(-) create mode 100644 drivers/gdisp/SSD1963/board_SSD1963_fsmc.h create mode 100644 drivers/gdisp/SSD1963/board_SSD1963_gpio.h create mode 100644 drivers/gdisp/SSD1963/board_SSD1963_template.h delete mode 100644 drivers/gdisp/SSD1963/gdisp_lld_board_example_fsmc.h delete mode 100644 drivers/gdisp/SSD1963/gdisp_lld_board_example_gpio.h delete mode 100644 drivers/gdisp/SSD1963/gdisp_lld_board_template.h delete mode 100644 drivers/gdisp/SSD1963/gdisp_lld_panel_example.h diff --git a/drivers/gdisp/SSD1963/board_SSD1963_fsmc.h b/drivers/gdisp/SSD1963/board_SSD1963_fsmc.h new file mode 100644 index 00000000..6c7119a4 --- /dev/null +++ b/drivers/gdisp/SSD1963/board_SSD1963_fsmc.h @@ -0,0 +1,105 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://chibios-gfx.com/license.html + */ + +/** + * @file drivers/gdisp/SSD1963/board_SSD1963_fsmc.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1963 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +static const LCD_Parameters DisplayTimings[] = { + // You need one of these array elements per display + { + 480, 272, // Panel width and height + 2, 2, 41, // Horizontal Timings (back porch, front porch, pulse) + CALC_PERIOD(480,2,2,41), // Total Horizontal Period (calculated from above line) + 2, 2, 10, // Vertical Timings (back porch, front porch, pulse) + CALC_PERIOD(272,2,2,10), // Total Vertical Period (calculated from above line) + CALC_FPR(480,272,2,2,41,2,2,10,60ULL) // FPR - the 60ULL is the frames per second. Note the ULL! + }, +}; + +// For a multiple display configuration we would put all this in a structure and then +// set g->board to that structure. + +/* Using FSMC A16 as RS */ +#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ +#define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ + +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + #if defined(STM32F1XX) || defined(STM32F3XX) + /* FSMC setup for F1/F3 */ + rccEnableAHB(RCC_AHBENR_FSMCEN, 0); + #elif defined(STM32F4XX) || defined(STM32F2XX) + /* STM32F2-F4 FSMC init */ + rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); + #else + #error "FSMC not implemented for this device" + #endif + + /* set pins to FSMC mode */ + IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8) | + (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; + + IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | + (1 << 13) | (1 << 14) | (1 << 15), 0}; + + palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); + palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); + + /* FSMC timing */ + FSMC_Bank1->BTCR[0+1] = (FSMC_BTR1_ADDSET_1 | FSMC_BTR1_ADDSET_3) \ + | (FSMC_BTR1_DATAST_1 | FSMC_BTR1_DATAST_3) \ + | (FSMC_BTR1_BUSTURN_1 | FSMC_BTR1_BUSTURN_3) ; + + /* Bank1 NOR/SRAM control register configuration + * This is actually not needed as already set by default after reset */ + FSMC_Bank1->BTCR[0] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + break; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; + /* FSMC delay reduced as the controller now runs at full speed */ + FSMC_Bank1->BTCR[0+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ; + FSMC_Bank1->BTCR[0] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + GDISP_REG = index; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + GDISP_RAM = data; +} + +#endif /* _GDISP_LLD_BOARD_H */ + diff --git a/drivers/gdisp/SSD1963/board_SSD1963_gpio.h b/drivers/gdisp/SSD1963/board_SSD1963_gpio.h new file mode 100644 index 00000000..0b9c0135 --- /dev/null +++ b/drivers/gdisp/SSD1963/board_SSD1963_gpio.h @@ -0,0 +1,102 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://chibios-gfx.com/license.html + */ + +/** + * @file drivers/gdisp/SSD1963/board_SSD1963_gpio.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1963 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +static const LCD_Parameters DisplayTimings[] = { + // You need one of these array elements per display + { + 480, 272, // Panel width and height + 2, 2, 41, // Horizontal Timings (back porch, front porch, pulse) + CALC_PERIOD(480,2,2,41), // Total Horizontal Period (calculated from above line) + 2, 2, 10, // Vertical Timings (back porch, front porch, pulse) + CALC_PERIOD(272,2,2,10), // Total Vertical Period (calculated from above line) + CALC_FPR(480,272,2,2,41,2,2,10,60ULL) // FPR - the 60ULL is the frames per second. Note the ULL! + }, +}; + +// For a multiple display configuration we would put all this in a structure and then +// set g->board to that structure. + +/** + * @brief The GPIO pin config + * + * @details This block of defines tell your driver how you wired your display + * controller to your MCU. Please change them accordingly. + */ +#define GDISP_CMD_PORT GPIOC +#define GDISP_DATA_PORT GPIOD +#define GDISP_CS 0 +#define GDISP_RS 1 +#define GDISP_WR 2 +#define GDISP_RD 3 + +#define Set_CS palSetPad(GDISP_CMD_PORT, GDISP_CS); +#define Clr_CS palClearPad(GDISP_CMD_PORT, GDISP_CS); +#define Set_RS palSetPad(GDISP_CMD_PORT, GDISP_RS); +#define Clr_RS palClearPad(GDISP_CMD_PORT, GDISP_RS); +#define Set_WR palSetPad(GDISP_CMD_PORT, GDISP_WR); +#define Clr_WR palClearPad(GDISP_CMD_PORT, GDISP_WR); +#define Set_RD palSetPad(GDISP_CMD_PORT, GDISP_RD); +#define Clr_RD palClearPad(GDISP_CMD_PORT, GDISP_RD); + +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + IOBus busCMD = {GDISP_CMD_PORT, (1 << GDISP_CS) | (1 << GDISP_RS) | (1 << GDISP_WR) | (1 << GDISP_RD), 0}; + IOBus busDATA = {GDISP_CMD_PORT, 0xFFFFF, 0}; + palSetBusMode(&busCMD, PAL_MODE_OUTPUT_PUSHPULL); + palSetBusMode(&busDATA, PAL_MODE_OUTPUT_PUSHPULL); + break; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; + Set_CS; +} + +static inline void release_bus(GDisplay *g) { + (void) g; + Clr_CS; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + Set_RS; Clr_RD; Set_WR; + palWritePort(GDISP_DATA_PORT, index); + Clr_WR; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + Clr_RS; Clr_RD; Set_WR; + palWritePort(GDISP_DATA_PORT, data); + Clr_WR; +} + +#endif /* _GDISP_LLD_BOARD_H */ + diff --git a/drivers/gdisp/SSD1963/board_SSD1963_template.h b/drivers/gdisp/SSD1963/board_SSD1963_template.h new file mode 100644 index 00000000..5e1999b8 --- /dev/null +++ b/drivers/gdisp/SSD1963/board_SSD1963_template.h @@ -0,0 +1,148 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1963/board_SSD1963_template.h + * @brief GDISP Graphic Driver subsystem board interface for the SSD1963 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief LCD panel specs + * + * @note The timings need to follow the datasheet for your particular TFT/LCD screen + * (the actual screen, not the controller). + * @note Datasheets normally use a specific set of timings and acronyms, their value refers + * to the number of pixel clocks. Non-display periods refer to pulses/timings that occur + * before or after the timings that actually put pixels on the screen. Display periods + * refer to pulses/timings that directly put pixels on the screen. + * @note HDP: Horizontal Display Period, normally the width - 1
+ * HT: Horizontal Total period (display + non-display)
+ * HPS: non-display period between the start of the horizontal sync (LLINE) signal + * and the first display data
+ * LPS: horizontal sync pulse (LLINE) start location in pixel clocks
+ * HPW: Horizontal sync Pulse Width
+ * VDP: Vertical Display period, normally height - 1
+ * VT: Vertical Total period (display + non-display)
+ * VPS: non-display period in lines between the start of the frame and the first display + * data in number of lines
+ * FPS: vertical sync pulse (LFRAME) start location in lines.
+ * VPW: Vertical sync Pulse Width + * @note Here's how to convert them:
+ * SCREEN_HSYNC_FRONT_PORCH = ( HT - HPS ) - GDISP_SCREEN_WIDTH
+ * SCREEN_HSYNC_PULSE = HPW
+ * SCREEN_HSYNC_BACK_PORCH = HPS - HPW
+ * SCREEN_VSYNC_FRONT_PORCH = ( VT - VPS ) - GDISP_SCREEN_HEIGHT
+ * SCREEN_VSYNC_PULSE = VPW
+ * SCREEN_VSYNC_BACK_PORCH = VPS - LPS
+ */ + +static const LCD_Parameters DisplayTimings[] = { + // You need one of these array elements per display + { + 480, 272, // Panel width and height + 2, 2, 41, // Horizontal Timings (back porch, front porch, pulse) + CALC_PERIOD(480,2,2,41), // Total Horizontal Period (calculated from above line) + 2, 2, 10, // Vertical Timings (back porch, front porch, pulse) + CALC_PERIOD(272,2,2,10), // Total Vertical Period (calculated from above line) + CALC_FPR(480,272,2,2,41,2,2,10,60ULL) // FPR - the 60ULL is the frames per second. Note the ULL! + }, +}; + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * + * @note Set the g->board member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/SSD1963/gdisp_lld.c b/drivers/gdisp/SSD1963/gdisp_lld.c index 39889731..11240568 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld.c +++ b/drivers/gdisp/SSD1963/gdisp_lld.c @@ -8,24 +8,81 @@ /** * @file drivers/gdisp/SSD1963/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source. - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" +#define GDISP_DRIVER_VMT GDISPVMT_SSD1963 +#include "../drivers/gdisp/SSD1963/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" + +#define CALC_PERIOD(w,b,f,p) (p+b+w+f) +#define CALC_FPR(w,h,hb,hf,hp,vb,vf,vp,fps) ((fps * CALC_PERIOD(w,hb,hf,hp) * CALC_PERIOD(h,vb,vf,vp) * 1048576)/100000000) + +typedef struct LCD_Parameters { + coord_t width, height; // Panel width and height + uint16_t hbporch; // Horizontal Back Porch + uint16_t hfporch; // Horizontal Front Porch + uint16_t hpulse; // Horizontal Pulse + uint16_t hperiod; // Horizontal Period (Total) + uint16_t vbporch; // Vertical Back Porch + uint16_t vfporch; // Vertical Front Porch + uint16_t vpulse; // Vertical Pulse + uint16_t vperiod; // Vertical Period (Total) + uint32_t fpr; // Calculated FPR +} LCD_Parameters; + +#include "board_SSD1963.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 90 +#endif + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ #include "ssd1963.h" -/* All the board specific code should go in these include file so the driver - * can be ported to another board just by creating a suitable file. +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } +#define write_data16(g, data) { write_data(g, (data)>>8); write_data(g, (data) & 0xFF); } + +static inline void set_viewport(GDisplay* g) { + write_index(g, SSD1963_SET_PAGE_ADDRESS); + write_data16(g, g->p.y); + write_data16(g, g->p.y+g->p.cy-1); + write_index(g, SSD1963_SET_COLUMN_ADDRESS); + write_data16(g, g->p.x); + write_data16(g, g->p.x+g->p.cx-1); + write_index(g, SSD1963_WRITE_MEMORY_START); +} + +/** + * The backlight is controlled by the controller. */ -#include "gdisp_lld_board.h" +static inline void set_backlight(GDisplay *g, uint8_t percent) { + //duty_cycle is 00..FF + //Work in progress: the SSD1963 has a built-in PWM, its output can + //be used by a Dynamic Background Control or by a host (user) + //Check your LCD's hardware, the PWM connection is default left open and instead + //connected to a LED connection on the breakout board + write_index(g, SSD1963_SET_PWM_CONF); //set PWM for BackLight + write_data(g, 0x01); + write_data(g, (55+percent*2) & 0x00FF); + write_data(g, 0x01); //controlled by host (not DBC), enabled + write_data(g, 0xFF); + write_data(g, 0x60); //don't let it go too dark, avoid a useless LCD + write_data(g, 0x0F); //prescaler ??? +} /*===========================================================================*/ /* Driver interrupt handlers. */ @@ -35,393 +92,194 @@ /* Driver exported functions. */ /*===========================================================================*/ +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + LCD_Parameters * lcdp; -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ + // The private area for this controller is the LCD timings + lcdp = (void *)&DisplayTimings[g->controllerdisplay]; + g->priv = lcdp; -/** - * @brief Low level GDISP driver initialisation. - * @return TRUE if successful, FALSE on error. - * - * @notapi - */ -bool_t gdisp_lld_init(void) { - /* Initialise the display */ + // Initialise the board interface + init_board(g); - init_board(); + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(20); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(20); + + // Get the bus for the following initialisation commands + acquire_bus(g); - write_index(SSD1963_SOFT_RESET); - gfxSleepMicroseconds(100); + write_index(g, SSD1963_SOFT_RESET); + gfxSleepMilliseconds(5); /* Driver PLL config */ - write_index(SSD1963_SET_PLL_MN); - write_data(35); // PLLclk = REFclk (10Mhz) * 36 (360Mhz) - write_data(2); // SYSclk = PLLclk / 3 (120MHz) - write_data(4); // Apply calculation bit, else it is ignored - - write_index(SSD1963_SET_PLL); // Enable PLL - write_data(0x01); - gfxSleepMicroseconds(200); - - write_index(SSD1963_SET_PLL); // Use PLL - write_data(0x03); - gfxSleepMicroseconds(200); - - write_index(SSD1963_SOFT_RESET); - gfxSleepMicroseconds(100); + write_index(g, SSD1963_SET_PLL_MN); + write_data(g, 35); // PLLclk = REFclk (10Mhz) * 36 (360Mhz) + write_data(g, 2); // SYSclk = PLLclk / 3 (120MHz) + write_data(g, 4); // Apply calculation bit, else it is ignored + write_reg(g, SSD1963_SET_PLL, 0x01); // Enable PLL + gfxSleepMilliseconds(5); + write_reg(g, SSD1963_SET_PLL, 0x03); // Use PLL + gfxSleepMilliseconds(5); + write_index(g, SSD1963_SOFT_RESET); + gfxSleepMilliseconds(5); /* Screen size */ - write_index(SSD1963_SET_GDISP_MODE); -// write_data(0x0000); - write_data(0b00011000); //Enabled dithering - write_data(0x0000); - write_data(mHIGH((GDISP_SCREEN_WIDTH+1))); - write_data((GDISP_SCREEN_WIDTH+1)); - write_data(mHIGH((GDISP_SCREEN_HEIGHT+1))); - write_data((GDISP_SCREEN_HEIGHT+1)); - write_data(0x0000); + write_index(g, SSD1963_SET_GDISP_MODE); + write_data(g, 0x18); //Enabled dithering + write_data(g, 0x00); + write_data16(g, lcdp->width-1); + write_data16(g, lcdp->height-1); + write_data(g, 0x00); // RGB - write_index(SSD1963_SET_PIXEL_DATA_INTERFACE); - write_data(SSD1963_PDI_16BIT565); + write_reg(g, SSD1963_SET_PIXEL_DATA_INTERFACE, SSD1963_PDI_16BIT565); /* LCD Clock specs */ - write_index(SSD1963_SET_LSHIFT_FREQ); - write_data((GDISP_FPR >> 16) & 0xFF); - write_data((GDISP_FPR >> 8) & 0xFF); - write_data(GDISP_FPR & 0xFF); + write_index(g, SSD1963_SET_LSHIFT_FREQ); + write_data(g, (lcdp->fpr >> 16) & 0xFF); + write_data(g, (lcdp->fpr >> 8) & 0xFF); + write_data(g, lcdp->fpr & 0xFF); - write_index(SSD1963_SET_HORI_PERIOD); - write_data(mHIGH(SCREEN_HSYNC_PERIOD)); - write_data(mLOW(SCREEN_HSYNC_PERIOD)); - write_data(mHIGH((SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH))); - write_data(mLOW((SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH))); - write_data(SCREEN_HSYNC_PULSE); - write_data(0x00); - write_data(0x00); - write_data(0x00); + write_index(g, SSD1963_SET_HORI_PERIOD); + write_data16(g, lcdp->hperiod); + write_data16(g, lcdp->hpulse + lcdp->hbporch); + write_data(g, lcdp->hpulse); + write_data(g, 0x00); + write_data(g, 0x00); + write_data(g, 0x00); - write_index(SSD1963_SET_VERT_PERIOD); - write_data(mHIGH(SCREEN_VSYNC_PERIOD)); - write_data(mLOW(SCREEN_VSYNC_PERIOD)); - write_data(mHIGH((SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH))); - write_data(mLOW((SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH))); - write_data(SCREEN_VSYNC_PULSE); - write_data(0x00); - write_data(0x00); + write_index(g, SSD1963_SET_VERT_PERIOD); + write_data16(g, lcdp->vperiod); + write_data16(g, lcdp->vpulse + lcdp->vbporch); + write_data(g, lcdp->vpulse); + write_data(g, 0x00); + write_data(g, 0x00); /* Tear effect indicator ON. This is used to tell the host MCU when the driver is not refreshing the panel (during front/back porch) */ - write_index(SSD1963_SET_TEAR_ON); - write_data(0x0000); + write_reg(g, SSD1963_SET_TEAR_ON, 0x00); /* Turn on */ - write_index(SSD1963_SET_DISPLAY_ON); + write_index(g, SSD1963_SET_DISPLAY_ON); - set_backlight(0xE5);//set to 90% brightness - - post_init_board(); + /* Turn on the back-light */ + set_backlight(g, GDISP_INITIAL_BACKLIGHT); - /* Initialise the GDISP structure to match */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = 100; - GDISP.Contrast = 50; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + // Finish Init + post_init_board(g); + // Release the bus + release_bus(g); + + /* Initialise the GDISP structure */ + g->g.Width = lcdp->width; + g->g.Height = lcdp->height; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; return TRUE; } -void gdisp_lld_setwindow(coord_t x0, coord_t y0, coord_t x1, coord_t y1) { - /* We don't need to validate here as the LLD routines will validate first. - * - * #if GDISP_NEED_VALIDATION - * if (x0 >= GDISP.Width || y0 >= GDISP.Height || x0 < 0 || y0 < 0) return; - * else if (x1 >= GDISP.Width || y1 >= GDISP.Height || y1 < 0 || y2 < 0) return; - * #endif - */ - write_index(SSD1963_SET_PAGE_ADDRESS); - write_data((y0 >> 8) & 0xFF); - write_data((y0 >> 0) & 0xFF); - write_data((y1 >> 8) & 0xFF); - write_data((y1 >> 0) & 0xFF); - write_index(SSD1963_SET_COLUMN_ADDRESS); - write_data((x0 >> 8) & 0xFF); - write_data((x0 >> 0) & 0xFF); - write_data((x1 >> 8) & 0xFF); - write_data((x1 >> 0) & 0xFF); -} +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + } + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, g->p.color); + } + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); + } +#endif -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - gdisp_lld_setwindow(x, y, x, y); - write_index(SSD1963_WRITE_MEMORY_START); - write_data(color); -} - -/* ---- Optional Routines ---- */ - -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - uint32_t area; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - area = cx*cy; - - gdisp_lld_setwindow(x, y, x+cx-1, y+cy-1); - write_index(SSD1963_WRITE_MEMORY_START); - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, &color); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area/65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); +// Not implemented yet. +#if 0 && GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + acquire_bus(g); + write_index(g, SSD1963_EXIT_SLEEP_MODE); // leave sleep mode + gfxSleepMilliseconds(5); + write_index(g, SSD1963_SET_DISPLAY_OFF); + write_index(g, SSD1963_SET_DEEP_SLEEP); // enter deep sleep mode + release_bus(g); + break; + case powerOn: + acquire_bus(g); + read_reg(0x0000); gfxSleepMilliseconds(5); // 2x Dummy reads to wake up from deep sleep + read_reg(0x0000); gfxSleepMilliseconds(5); + write_index(g, SSD1963_SET_DISPLAY_ON); + release_bus(g); + break; + case powerSleep: + acquire_bus(g); + write_index(g, SSD1963_SET_DISPLAY_OFF); + write_index(g, SSD1963_ENTER_SLEEP_MODE); // enter sleep mode + release_bus(g); + break; + default: + return; } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - uint32_t index; - for(index = 0; index < area; index++) - write_data(color); - #endif //#ifdef GDISP_USE_DMA -} -#endif + g->g.Powermode = (powermode_t)g->p.ptr; + return; -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a bitmap. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - gdisp_lld_setwindow(x, y, x+cx-1, y+cy-1); - write_index(SSD1963_WRITE_MEMORY_START); - - buffer += srcx + srcy * srccx; - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint32_t area = cx*cy; - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PINC | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area/65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area%65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - coord_t endx, endy; - uint32_t lg; - endx = srcx + cx; - endy = y + cy; - lg = srccx - cx; - for(; y < endy; y++, buffer += lg) - for(x=srcx; x < endx; x++) - write_data(*buffer++); - #endif //#ifdef GDISP_USE_DMA - } -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @note Optional. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - /* NOT IMPLEMENTED YET */ - - /* - uint16_t size = x1 - x0 ; - - write_index(SSD1963_SET_SCROLL_AREA); - write_data((x0 >> 8) & 0xFF); - write_data((x0 >> 0) & 0xFF); - write_data((size >> 8) & 0xFF); - write_data((size >> 0) & 0xFF); - write_data(((lcd_height-x1) >> 8) & 0xFF); - write_data(((lcd_height-x1) >> 0) & 0xFF); - - write_index(SSD1963_SET_SCROLL_START); - write_data((lines >> 8) & 0xFF); - write_data((lines >> 0) & 0xFF); - */ - } - -#endif - -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. - * GDISP_CONTROL_LLD - Low level driver control constants start at - * this value. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { - /* NOT IMPLEMENTED YET */ - switch(what) { - case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) - return; - switch((gdisp_powermode_t)value) { - case powerOff: - write_index(SSD1963_EXIT_SLEEP_MODE); // leave sleep mode - gfxSleepMilliseconds(5); - write_index(SSD1963_SET_DISPLAY_OFF); - write_index(SSD1963_SET_DEEP_SLEEP); // enter deep sleep mode - break; - case powerOn: - read_reg(0x0000); gfxSleepMilliseconds(5); // 2x Dummy reads to wake up from deep sleep - read_reg(0x0000); gfxSleepMilliseconds(5); - if (GDISP.Powermode != powerSleep) - gdisp_lld_init(); - write_index(SSD1963_SET_DISPLAY_ON); - - break; - case powerSleep: - write_index(SSD1963_SET_DISPLAY_OFF); - write_index(SSD1963_ENTER_SLEEP_MODE); // enter sleep mode - gfxSleepMilliseconds(5); - break; - default: - return; - } - GDISP.Powermode = (gdisp_powermode_t)value; + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) return; - case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) - return; - switch((gdisp_orientation_t)value) { - case GDISP_ROTATE_0: - /* Code here */ - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_90: - /* Code here */ - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - case GDISP_ROTATE_180: - /* Code here */ - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_270: - /* Code here */ - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - default: - return; - } - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - GDISP.Orientation = (gdisp_orientation_t)value; + case GDISP_ROTATE_0: + acquire_bus(g); + /* Code here */ + release_bus(g); + g->g.Height = ((LCD_Parameters *)g->priv)->height; + g->g.Width = ((LCD_Parameters *)g->priv)->width; + break; + case GDISP_ROTATE_90: + acquire_bus(g); + /* Code here */ + release_bus(g); + g->g.Height = ((LCD_Parameters *)g->priv)->width; + g->g.Width = ((LCD_Parameters *)g->priv)->height; + break; + case GDISP_ROTATE_180: + acquire_bus(g); + /* Code here */ + release_bus(g); + g->g.Height = ((LCD_Parameters *)g->priv)->height; + g->g.Width = ((LCD_Parameters *)g->priv)->width; + break; + case GDISP_ROTATE_270: + acquire_bus(g); + /* Code here */ + release_bus(g); + g->g.Height = ((LCD_Parameters *)g->priv)->width; + g->g.Width = ((LCD_Parameters *)g->priv)->height; + break; + default: return; - case GDISP_CONTROL_BACKLIGHT: - gdisp_lld_bg_dimmer(54 + ((uint8_t)value) << 1);//turn 0..100% in 54..255 - return; -/* - case GDISP_CONTROL_CONTRAST: -*/ + } + g->g.Orientation = (orientation_t)value; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + //case GDISP_CONTROL_CONTRAST: + default: + return; } } #endif #endif /* GFX_USE_GDISP */ -/** @} */ diff --git a/drivers/gdisp/SSD1963/gdisp_lld.mk b/drivers/gdisp/SSD1963/gdisp_lld.mk index c2ce22b6..ad406898 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld.mk +++ b/drivers/gdisp/SSD1963/gdisp_lld.mk @@ -1,6 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1963/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/SSD1963 - +GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1963/gdisp_lld.c diff --git a/drivers/gdisp/SSD1963/gdisp_lld_board_example_fsmc.h b/drivers/gdisp/SSD1963/gdisp_lld_board_example_fsmc.h deleted file mode 100644 index a2c296b9..00000000 --- a/drivers/gdisp/SSD1963/gdisp_lld_board_example_fsmc.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://chibios-gfx.com/license.html - */ - -/** - * @file drivers/gdisp/SSD1963/gdisp_lld_board_example_fsmc.h - * @brief GDISP Graphic Driver subsystem board interface for the SSD1963 display. - * - * @details This file demonstrates how to interface an SSD1963 based display to an - * STM32 microcontroller using ChibiOS/RT. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/* Using FSMC A16 as RS */ -#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* RS = 0 */ -#define GDISP_RAM (*((volatile uint16_t *) 0x60020000)) /* RS = 1 */ - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - GDISP_REG = index; -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - GDISP_RAM = data; -} - -/** - * @brief Initialise the board for the display. - * @notes Performs the following functions: - * 1. initialise the io port used by your display - * 2. initialise the reset pin (initial state not-in-reset) - * 3. initialise the chip select pin (initial state not-active) - * 4. initialise the backlight pin (initial state back-light off) - * - * @notapi - */ -static inline void init_board(void) { - const unsigned char FSMC_Bank = 0; - - #if defined(STM32F1XX) || defined(STM32F3XX) - /* FSMC setup for F1/F3 */ - rccEnableAHB(RCC_AHBENR_FSMCEN, 0); - - #if defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - #error "DMA not implemented for F1/F3 Devices" - #endif - #elif defined(STM32F4XX) || defined(STM32F2XX) - /* STM32F2-F4 FSMC init */ - rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); - - #if defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - if (dmaStreamAllocate(GDISP_DMA_STREAM, 0, NULL, NULL)) gfxExit(); - dmaStreamSetMemory0(GDISP_DMA_STREAM, &GDISP_RAM); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - #endif - #else - #error "FSMC not implemented for this device" - #endif - -< /* set pins to FSMC mode */ - IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8) | - (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; - - IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | - (1 << 13) | (1 << 14) | (1 << 15), 0}; - - palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); - palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); - - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = (FSMC_BTR1_ADDSET_1 | FSMC_BTR1_ADDSET_3) \ - | (FSMC_BTR1_DATAST_1 | FSMC_BTR1_DATAST_3) \ - | (FSMC_BTR1_BUSTURN_1 | FSMC_BTR1_BUSTURN_3) ; - - /* Bank1 NOR/SRAM control register configuration - * This is actually not needed as already set by default after reset */ - FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; -} - -static inline void post_init_board(void) { - const unsigned char FSMC_Bank = 0; - /* FSMC delay reduced as the controller now runs at full speed */ - FSMC_Bank1->BTCR[FSMC_Bank+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ; - FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - (void) state; - /* Nothing to do here */ -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - //duty_cycle is 00..FF - //Work in progress: the SSD1963 has a built-in PWM, its output can - //be used by a Dynamic Background Control or by a host (user) - //Check your LCD's hardware, the PWM connection is default left open and instead - //connected to a LED connection on the breakout board - write_index(SSD1963_SET_PWM_CONF);//set PWM for BackLight - write_data(0x0001); - write_data(percent & 0x00FF); - write_data(0x0001);//controlled by host (not DBC), enabled - write_data(0x00FF); - write_data(0x0060);//don't let it go too dark, avoid a useless LCD - write_data(0x000F);//prescaler ??? -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do here */ -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - /* Nothing to do here */ -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - return GDISP_RAM; -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/SSD1963/gdisp_lld_board_example_gpio.h b/drivers/gdisp/SSD1963/gdisp_lld_board_example_gpio.h deleted file mode 100644 index 38f5b2a5..00000000 --- a/drivers/gdisp/SSD1963/gdisp_lld_board_example_gpio.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://chibios-gfx.com/license.html - */ - -/** - * @file drivers/gdisp/SSD1963/gdisp_lld_board_example_gpio.h - * @brief GDISP Graphic Driver subsystem board interface for the SSD1963 display. - * - * @brief This file demonstrates how to interface an SSD1963 based display using - * a GPIO interface of an STM32 out of ChibiOS/RT. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief The GPIO pin config - * - * @details This block of defines tell your driver how you wired your display - * controller to your MCU. Please change them accordingly. - */ -#define GDISP_CMD_PORT GPIOC -#define GDISP_DATA_PORT GPIOD -#define GDISP_CS 0 -#define GDISP_RS 1 -#define GDISP_WR 2 -#define GDISP_RD 3 - -#define Set_CS palSetPad(GDISP_CMD_PORT, GDISP_CS); -#define Clr_CS palClearPad(GDISP_CMD_PORT, GDISP_CS); -#define Set_RS palSetPad(GDISP_CMD_PORT, GDISP_RS); -#define Clr_RS palClearPad(GDISP_CMD_PORT, GDISP_RS); -#define Set_WR palSetPad(GDISP_CMD_PORT, GDISP_WR); -#define Clr_WR palClearPad(GDISP_CMD_PORT, GDISP_WR); -#define Set_RD palSetPad(GDISP_CMD_PORT, GDISP_RD); -#define Clr_RD palClearPad(GDISP_CMD_PORT, GDISP_RD); - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - Set_CS; Set_RS; Set_WR; Clr_RD; - - palWritePort(GDISP_DATA_PORT, index); - - Clr_CS; -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - Set_CS; Clr_RS; Set_WR; Clr_RD; - - palWritePort(GDISP_DATA_PORT, data); - - Clr_CS; -} - -/** - * @brief Initialise the board for the display. - * - * @notapi - */ -static inline void init_board(void) { - IOBus busCMD = {GDISP_CMD_PORT, (1 << GDISP_CS) | (1 << GDISP_RS) | (1 << GDISP_WR) | (1 << GDISP_RD), 0}; - IOBus busDATA = {GDISP_CMD_PORT, 0xFFFFF, 0}; - palSetBusMode(&busCMD, PAL_MODE_OUTPUT_PUSHPULL); - palSetBusMode(&busDATA, PAL_MODE_OUTPUT_PUSHPULL); -} - -static inline void post_init_board(void) { - /* Nothing to do here */ -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - /* optional */ -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - //duty_cycle is 00..FF - //Work in progress: the SSD1963 has a built-in PWM, its output can - //be used by a Dynamic Background Control or by a host (user) - //Check your LCD's hardware, the PWM connection is default left open and instead - //connected to a LED connection on the breakout board - write_index(SSD1963_SET_PWM_CONF);//set PWM for BackLight - write_data(0x0001); - write_data(percent & 0x00FF); - write_data(0x0001);//controlled by host (not DBC), enabled - write_data(0x00FF); - write_data(0x0060);//don't let it go too dark, avoid a useless LCD - write_data(0x000F);//prescaler ??? -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do here */ -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - /* Nothing to do here */ -} - -__inline void write_stream(uint16_t *buffer, uint16_t size) { - uint16_t i; - - Set_CS; Clr_RS; Set_WR; Clr_RD; - - for (i = 0; i < size; i++) { - Set_WR; - palWritePort(GDISP_DATA_PORT, buffer[i]); - Clr_WR; - } - - Clr_CS; -} - -__inline void read_stream(uint16_t *buffer, size_t size) { - uint16_t i; - - Set_CS; Clr_RS; Clr_WR; Set_RD; - - for (i = 0; i < size; i++) { - Set_RD; - buffer[i] = palReadPort(GDISP_DATA_PORT); - Clr_RD; - } -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - uint16_t data; - - Set_CS; Clr_RS; Clr_WR; Set_RD; - - data = palReadPort(GDISP_DATA_PORT); - - Clr_CS; - - return data; -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/SSD1963/gdisp_lld_board_template.h b/drivers/gdisp/SSD1963/gdisp_lld_board_template.h deleted file mode 100644 index 44cd3712..00000000 --- a/drivers/gdisp/SSD1963/gdisp_lld_board_template.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD1963/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board interface for the SSD1963 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - -} - -/** - * @brief Initialise the board for the display. - * @notes Performs the following functions: - * 1. initialise the io port used by your display - * 2. initialise the reset pin (initial state not-in-reset) - * 3. initialise the chip select pin (initial state not-active) - * 4. initialise the backlight pin (initial state back-light off) - * - * @notapi - */ -static inline void init_board(void) { - -} - -static inline void post_init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * - * @notapi - */ -static inline void release_bus(void) { - -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/SSD1963/gdisp_lld_config.h b/drivers/gdisp/SSD1963/gdisp_lld_config.h index 70eec579..054d72b8 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1963/gdisp_lld_config.h @@ -22,14 +22,8 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "SSD1963" -#define GDISP_LLD(x) gdisp_lld_##x##_SSD1963 - -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -/* Maybe someday soon */ -#define GDISP_HARDWARE_SCROLL FALSE -#define GDISP_HARDWARE_CONTROL FALSE +#define GDISP_HARDWARE_STREAM_WRITE TRUE +//#define GDISP_HARDWARE_CONTROL TRUE // Not Yet. #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 diff --git a/drivers/gdisp/SSD1963/gdisp_lld_panel_example.h b/drivers/gdisp/SSD1963/gdisp_lld_panel_example.h deleted file mode 100644 index 72095495..00000000 --- a/drivers/gdisp/SSD1963/gdisp_lld_panel_example.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD1963/gdisp_lld_panel_example.h - * @brief TFT LCD panel properties. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_PANEL_H -#define _GDISP_LLD_PANEL_H - -/* LCD panel specs */ - -/* The timings need to follow the datasheet for your particular TFT/LCD screen (the actual screen, not the controller) -*** Datasheets normally use a specific set of timings and acronyms, their value refers to the number of pixel clocks -** Non-display periods refer to pulses/timings that occur before or after the timings that actually put pixels on the screen -** Display periods refer to pulses/timings that directly put pixels on the screen -HDP: Horizontal Display Period, normally the width - 1 -HT: Horizontal Total period (display + non-display) -HPS: non-display period between the start of the horizontal sync (LLINE) signal and the first display data -LPS: horizontal sync pulse (LLINE) start location in pixel clocks -HPW: Horizontal sync Pulse Width -VDP: Vertical Display period, normally height - 1 -VT: Vertical Total period (display + non-display) -VPS: non-display period in lines between the start of the frame and the first display data in number of lines -FPS: vertical sync pulse (LFRAME) start location in lines. -VPW: Vertical sync Pulse Width - -*** Here's how to convert them: -HPS = SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH -HT - HPS = GDISP_SCREEN_WIDTH + SCREEN_HSYNC_FRONT_PORCH -=> SCREEN_HSYNC_FRONT_PORCH = ( HT - HPS ) - GDISP_SCREEN_WIDTH - SCREEN_HSYNC_PULSE = HPW - SCREEN_HSYNC_BACK_PORCH = HPS - HPW - SCREEN_HSYNC_PERIOD = HT - -VPS = SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH -VT - VPS = GDISP_SCREEN_HEIGHT + SCREEN_VSYNC_FRONT_PORCH -=> SCREEN_VSYNC_FRONT_PORCH = ( VT - VPS ) - GDISP_SCREEN_HEIGHT - SCREEN_VSYNC_PULSE = VPW - SCREEN_VSYNC_BACK_PORCH = VPS - LPS - SCREEN_VSYNC_PERIOD = VT -*/ - -#define SCREEN_FPS 60ULL - -//The following values are for a 4.3" TFT LCD - -#define GDISP_SCREEN_WIDTH 480 -#define GDISP_SCREEN_HEIGHT 272 - -#define SCREEN_HSYNC_BACK_PORCH 2 -#define SCREEN_HSYNC_FRONT_PORCH 2 -#define SCREEN_HSYNC_PULSE 41 - -#define SCREEN_VSYNC_BACK_PORCH 2 -#define SCREEN_VSYNC_FRONT_PORCH 2 -#define SCREEN_VSYNC_PULSE 10 - -#define SCREEN_HSYNC_PERIOD (SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH + GDISP_SCREEN_WIDTH + SCREEN_HSYNC_FRONT_PORCH) -#define SCREEN_VSYNC_PERIOD (SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH + GDISP_SCREEN_HEIGHT + SCREEN_VSYNC_FRONT_PORCH) - -#define SCREEN_PCLK (SCREEN_HSYNC_PERIOD * SCREEN_VSYNC_PERIOD * SCREEN_FPS) -#define GDISP_FPR ((SCREEN_PCLK * 1048576)/100000000) - -#endif -/** @} */ diff --git a/drivers/gdisp/SSD1963/ssd1963.h b/drivers/gdisp/SSD1963/ssd1963.h index 46369be6..be328775 100644 --- a/drivers/gdisp/SSD1963/ssd1963.h +++ b/drivers/gdisp/SSD1963/ssd1963.h @@ -8,11 +8,6 @@ #ifndef SSD1963_H #define SSD1963_H -#include "gdisp_lld_panel.h" - -#define mHIGH(x) (x >> 8) -#define mLOW(x) (x & 0xFF) - /* SSD1963 commands */ #define SSD1963_NOP 0x0000 From 459fbf6781bca48471ea8dc1cfbbd2a0700ee2e1 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 21 Oct 2013 13:47:59 +0200 Subject: [PATCH 084/160] fixes --- drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h | 1 - src/gdisp/gdisp.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h index 2a7ffe1e..99d37299 100644 --- a/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h +++ b/drivers/gdisp/SSD1289/board_SSD1289_firebullstm32f103.h @@ -99,7 +99,6 @@ static inline void setwritemode(GDisplay *g) { static inline uint16_t read_data(GDisplay *g) { return palReadPort(GPIOE); } -#endif #if defined(GDISP_USE_DMA) #error "GDISP - SSD1289: The GPIO interface does not support DMA" diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 172cddcc..21c6e247 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -108,8 +108,8 @@ GDisplay *GDISP = GDisplayArray; if ((g->flags & GDISP_FLG_SCRSTREAM)) { \ gdisp_lld_write_stop(g); \ g->flags &= ~GDISP_FLG_SCRSTREAM; \ - } - autoflush_stopdone(g); + } \ + autoflush_stopdone(g); \ } #else #define autoflush(g) autoflush_stopdone(g) From f285a24a9030e0119739330f4246b4141fa3ba5e Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 21 Oct 2013 14:27:29 +0200 Subject: [PATCH 085/160] SSD1289 fixes --- drivers/gdisp/SSD1289/gdisp_lld.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 698d3cfc..510f1560 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -302,7 +302,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { case GDISP_ROTATE_90: acquire_bus(g); /* ID = 01 AM = 1 */ - write_reg(0x11, 0x6058); + write_reg(g, 0x11, 0x6058); release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; @@ -310,7 +310,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { case GDISP_ROTATE_180: acquire_bus(g); /* ID = 00 AM = 0 */ - write_reg(0x11, 0x6040); + write_reg(g, 0x11, 0x6040); release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; @@ -326,7 +326,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: From 86ae017301c62d8495707d46708bcc65568539d7 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 21 Oct 2013 15:40:40 +0200 Subject: [PATCH 086/160] Porting SSD2219 driver - WORK IN PROGRES!!!! --- drivers/gdisp/SSD2119/gdisp_lld.c | 343 +++++++++++++++++------------- 1 file changed, 197 insertions(+), 146 deletions(-) diff --git a/drivers/gdisp/SSD2119/gdisp_lld.c b/drivers/gdisp/SSD2119/gdisp_lld.c index de97d805..548d2dd1 100644 --- a/drivers/gdisp/SSD2119/gdisp_lld.c +++ b/drivers/gdisp/SSD2119/gdisp_lld.c @@ -17,10 +17,12 @@ #include "ssd2119.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" +#define GDISP_DRIVER_VMT GDISPVMT_SSD2119 +#include "../drivers/gdisp/SSD2119/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" +#include "board_SSD2119.h" /*===========================================================================*/ /* Driver local definitions. */ @@ -32,51 +34,48 @@ #ifndef GDISP_SCREEN_WIDTH #define GDISP_SCREEN_WIDTH 320 #endif - -#define GDISP_INITIAL_CONTRAST 50 -#define GDISP_INITIAL_BACKLIGHT 100 +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ -#include "gdisp_lld_board.h" - // Some common routines and macros -#define write_reg(reg, data) { write_index(reg); write_data(data); } -#define stream_start() write_index(SSD2119_REG_RAM_DATA); -#define stream_stop() -#define delay(us) gfxSleepMicroseconds(us) -#define delayms(ms) gfxSleepMilliseconds(ms) +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } -static inline void set_cursor(coord_t x, coord_t y) { +static void set_cursor(GDisplay* g) { /* Reg SSD2119_REG_X_RAM_ADDR is 9 bit value * Reg SSD2119_REG_Y_RAM_ADDR is an 8 bit * Use a bit mask to make sure they are not set too high */ - switch(GDISP.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: - write_reg(SSD2119_REG_X_RAM_ADDR, x & 0x01FF); - write_reg(SSD2119_REG_Y_RAM_ADDR, y & 0x00FF); + write_reg(g, SSD2119_REG_X_RAM_ADDR, g->p.x & 0x01FF); + write_reg(g, SSD2119_REG_Y_RAM_ADDR, g->p.y & 0x00FF); break; case GDISP_ROTATE_90: - write_reg(SSD2119_REG_X_RAM_ADDR, (GDISP_SCREEN_WIDTH - y - 1) & 0x01FF); - write_reg(SSD2119_REG_Y_RAM_ADDR, (GDISP_SCREEN_HEIGHT - x - 1) & 0x00FF); + write_reg(g, SSD2119_REG_X_RAM_ADDR, (GDISP_SCREEN_WIDTH - g->p.y - 1) & 0x01FF); + write_reg(g, SSD2119_REG_Y_RAM_ADDR, (GDISP_SCREEN_HEIGHT - g->p.x - 1) & 0x00FF); break; case GDISP_ROTATE_180: - write_reg(SSD2119_REG_X_RAM_ADDR, (GDISP_SCREEN_WIDTH - 1 - x) & 0x01FF); - write_reg(SSD2119_REG_Y_RAM_ADDR, (GDISP_SCREEN_HEIGHT - 1 - y) & 0x00FF); + write_reg(g, SSD2119_REG_X_RAM_ADDR, (GDISP_SCREEN_WIDTH - 1 - g->p.x) & 0x01FF); + write_reg(g, SSD2119_REG_Y_RAM_ADDR, (GDISP_SCREEN_HEIGHT - 1 - g->p.y) & 0x00FF); break; case GDISP_ROTATE_270: - write_reg(SSD2119_REG_X_RAM_ADDR, y & 0x01FF); - write_reg(SSD2119_REG_Y_RAM_ADDR, x & 0x00FF); + write_reg(g, SSD2119_REG_X_RAM_ADDR, g->p.y & 0x01FF); + write_reg(g, SSD2119_REG_Y_RAM_ADDR, g->p.x & 0x00FF); break; } } -static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { - - set_cursor(x, y); +static void set_viewport(GDisplay* g) { + set_cursor(g->p.x, g->p.y); /* Reg 0x44 - Vertical RAM address position * Upper Byte - VEA @@ -87,34 +86,34 @@ static void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { * 0 <= HSA <= HEA <= 0x13F */ - switch(GDISP.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: - write_reg(SSD2119_REG_V_RAM_POS, (((y + cy - 1) << 8) & 0xFF00 ) | (y & 0x00FF)); - write_reg(SSD2119_REG_H_RAM_START, (x & 0x01FF)); - write_reg(SSD2119_REG_H_RAM_END, (x + cx - 1) & 0x01FF); + write_reg(g, SSD2119_REG_V_RAM_POS, (((g->p.y + g->p.cy - 1) << 8) & 0xFF00 ) | (g->p.y & 0x00FF)); + write_reg(g, SSD2119_REG_H_RAM_START, (g->p.x & 0x01FF)); + write_reg(g, SSD2119_REG_H_RAM_END, (g->p.x + g->p.cx - 1) & 0x01FF); break; case GDISP_ROTATE_90: - write_reg(SSD2119_REG_V_RAM_POS, (((GDISP_SCREEN_HEIGHT - x - 1) & 0x00FF) << 8) | ((GDISP_SCREEN_HEIGHT - (x + cx)) & 0x00FF)); - write_reg(SSD2119_REG_H_RAM_START, (GDISP_SCREEN_WIDTH - (y + cy)) & 0x01FF); - write_reg(SSD2119_REG_H_RAM_END, (GDISP_SCREEN_WIDTH - y - 1) & 0x01FF); + write_reg(g, SSD2119_REG_V_RAM_POS, (((GDISP_SCREEN_HEIGHT - g->p.x - 1) & 0x00FF) << 8) | ((GDISP_SCREEN_HEIGHT - (g->p.x + g->p.cx)) & 0x00FF)); + write_reg(g, SSD2119_REG_H_RAM_START, (GDISP_SCREEN_WIDTH - (g->p.y + g->p.cy)) & 0x01FF); + write_reg(g, SSD2119_REG_H_RAM_END, (GDISP_SCREEN_WIDTH - g->p.y - 1) & 0x01FF); break; case GDISP_ROTATE_180: - write_reg(SSD2119_REG_V_RAM_POS, (((GDISP_SCREEN_HEIGHT - y - 1) & 0x00FF) << 8) | ((GDISP_SCREEN_HEIGHT - (y + cy)) & 0x00FF)); - write_reg(SSD2119_REG_H_RAM_START, (GDISP_SCREEN_WIDTH - (x + cx)) & 0x01FF); - write_reg(SSD2119_REG_H_RAM_END, (GDISP_SCREEN_WIDTH - x - 1) & 0x01FF); + write_reg(SSD2119_REG_V_RAM_POS, (((GDISP_SCREEN_HEIGHT - g->p.y - 1) & 0x00FF) << 8) | ((GDISP_SCREEN_HEIGHT - (g->p.y + g->p.cy)) & 0x00FF)); + write_reg(SSD2119_REG_H_RAM_START, (GDISP_SCREEN_WIDTH - (g->p.x + g->p.cx)) & 0x01FF); + write_reg(SSD2119_REG_H_RAM_END, (GDISP_SCREEN_WIDTH - g->p.x - 1) & 0x01FF); break; case GDISP_ROTATE_270: - write_reg(SSD2119_REG_V_RAM_POS, (((x + cx - 1) << 8) & 0xFF00 ) | (x & 0x00FF)); - write_reg(SSD2119_REG_H_RAM_START, (y & 0x01FF)); - write_reg(SSD2119_REG_H_RAM_END, (y + cy - 1) & 0x01FF); + write_reg(SSD2119_REG_V_RAM_POS, (((g->p.x + g->p.cx - 1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); + write_reg(SSD2119_REG_H_RAM_START, (g->p.y & 0x01FF)); + write_reg(SSD2119_REG_H_RAM_END, (g->p.y + g->p.cy - 1) & 0x01FF); break; } - set_cursor(x, y); + set_cursor(g->p.x, g->p.y); } -static inline void reset_viewport(void) { - set_viewport(0, 0, GDISP.Width, GDISP.Height); +static inline void reset_viewport(GDisplay* g) { + set_viewport(0, 0, g->g.Width, g->g.Height); } /*===========================================================================*/ @@ -125,144 +124,196 @@ static inline void reset_viewport(void) { /* Driver exported functions. */ /*===========================================================================*/ -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. -*/ +LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { + // no private area for this controller + g->priv = 0; -/** - * @brief Low level GDISP driver initialization. - * - * @notapi - */ -bool_t gdisp_lld_init(void) { - /* Initialise your display */ + // initialise the board interface init_board(); // Hardware reset - setpin_reset(TRUE); - delayms(20); - setpin_reset(FALSE); - delayms(20); + setpin_reset(g, TRUE); + gfxSleepMilliseconds(20); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(20); // Get the bus for the following initialisation commands - acquire_bus(); + acquire_bus(g); // Enter sleep mode (if we are not already there). - write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0001); - delay(5); + write_reg(g, SSD2119_REG_SLEEP_MODE_1, 0x0001); + gfxSleepMicroseconds(5); // Set initial power parameters. - write_reg(SSD2119_REG_PWR_CTRL_5, 0x00B2); - delay(5); - write_reg(SSD2119_REG_VCOM_OTP_1, 0x0006); - delay(5); + write_reg(g, SSD2119_REG_PWR_CTRL_5, 0x00B2); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_VCOM_OTP_1, 0x0006); + gfxSleepMicroseconds(5); // Start the oscillator. - write_reg(SSD2119_REG_OSC_START, 0x0001); - delay(5); + write_reg(g, SSD2119_REG_OSC_START, 0x0001); + gfxSleepMicroseconds(5); // Set pixel format and basic display orientation (scanning direction). - write_reg(SSD2119_REG_OUTPUT_CTRL, 0x30EF); - delay(5); - write_reg(SSD2119_REG_LCD_DRIVE_AC_CTRL, 0x0600); - delay(5); + write_reg(g, SSD2119_REG_OUTPUT_CTRL, 0x30EF); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_LCD_DRIVE_AC_CTRL, 0x0600); + gfxSleepMicroseconds(5); // Exit sleep mode. - write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0000); - delay(5); + write_reg(g, SSD2119_REG_SLEEP_MODE_1, 0x0000); + gfxSleepMicroseconds(5); // Configure pixel color format and MCU interface parameters. - write_reg(SSD2119_REG_ENTRY_MODE, 0x6830); // ENTRY_MODE_DEFAULT - delay(5); + write_reg(g, SSD2119_REG_ENTRY_MODE, 0x6830); // ENTRY_MODE_DEFAULT + gfxSleepMicroseconds(5); // Set analog parameters. - write_reg(SSD2119_REG_SLEEP_MODE_2, 0x0999); - delay(5); - write_reg(SSD2119_REG_ANALOG_SET, 0x3800); - delay(5); + write_reg(g, SSD2119_REG_SLEEP_MODE_2, 0x0999); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_ANALOG_SET, 0x3800); + gfxSleepMicroseconds(5); // Enable the display. - write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0033); - delay(5); + write_reg(g, SSD2119_REG_DISPLAY_CTRL, 0x0033); + gfxSleepMicroseconds(5); // Set VCIX2 voltage to 6.1V. - write_reg(SSD2119_REG_PWR_CTRL_2, 0x0005); - delay(5); + write_reg(g, SSD2119_REG_PWR_CTRL_2, 0x0005); + gfxSleepMicroseconds(5); // Configure gamma correction. - write_reg(SSD2119_REG_GAMMA_CTRL_1, 0x0000); - delay(5); - write_reg(SSD2119_REG_GAMMA_CTRL_2, 0x0303); - delay(5); - write_reg(SSD2119_REG_GAMMA_CTRL_3, 0x0407); - delay(5); - write_reg(SSD2119_REG_GAMMA_CTRL_4, 0x0301); - delay(5); - write_reg(SSD2119_REG_GAMMA_CTRL_5, 0x0301); - delay(5); - write_reg(SSD2119_REG_GAMMA_CTRL_6, 0x0403); - delay(5); - write_reg(SSD2119_REG_GAMMA_CTRL_7, 0x0707); - delay(5); - write_reg(SSD2119_REG_GAMMA_CTRL_8, 0x0400); - delay(5); - write_reg(SSD2119_REG_GAMMA_CTRL_9, 0x0a00); - delay(5); - write_reg(SSD2119_REG_GAMMA_CTRL_10, 0x1000); - delay(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_1, 0x0000); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_2, 0x0303); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_3, 0x0407); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_4, 0x0301); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_5, 0x0301); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_6, 0x0403); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_7, 0x0707); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_8, 0x0400); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_9, 0x0a00); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_GAMMA_CTRL_10, 0x1000); + gfxSleepMicroseconds(5); // Configure Vlcd63 and VCOMl. - write_reg(SSD2119_REG_PWR_CTRL_3, 0x000A); - delay(5); - write_reg(SSD2119_REG_PWR_CTRL_4, 0x2E00); - delay(5); + write_reg(g, SSD2119_REG_PWR_CTRL_3, 0x000A); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_PWR_CTRL_4, 0x2E00); + gfxSleepMicroseconds(5); // Set the display size and ensure that the GRAM window is set to allow access to the full display buffer. - write_reg(SSD2119_REG_V_RAM_POS, (GDISP_SCREEN_HEIGHT - 1) << 8); - delay(5); - write_reg(SSD2119_REG_H_RAM_START, 0x0000); - delay(5); - write_reg(SSD2119_REG_H_RAM_END, GDISP_SCREEN_WIDTH - 1); - delay(5); + write_reg(g, SSD2119_REG_V_RAM_POS, (GDISP_SCREEN_HEIGHT - 1) << 8); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_H_RAM_START, 0x0000); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_H_RAM_END, GDISP_SCREEN_WIDTH - 1); + gfxSleepMicroseconds(5); - write_reg(SSD2119_REG_X_RAM_ADDR, 0x00); - delay(5); - write_reg(SSD2119_REG_Y_RAM_ADDR, 0x00); - delay(5); + write_reg(g, SSD2119_REG_X_RAM_ADDR, 0x00); + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_Y_RAM_ADDR, 0x00); + gfxSleepMicroseconds(5); // Release the bus - release_bus(); + release_bus(g); - /* Turn on the backlight */ - set_backlight(GDISP_INITIAL_BACKLIGHT); + // Turn on the backlight + set_backlight(g, GDISP_INITIAL_BACKLIGHT); + + // Initialise the GDISP structure + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; - /* Initialise the GDISP structure */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Backlight = GDISP_INITIAL_BACKLIGHT; - GDISP.Contrast = GDISP_INITIAL_CONTRAST; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay* g) { + acquire_bus(g); + set_viewport(g); + } + LLDSPEC void gdisp_lld_write_color(GDisplay* g) { + write_data(g, g->p.color); + } + LLDSPEC void gdisp_lld_write_stop(GDisplay* g) { + release_bus(g); + } + LLDSPEC void gdisp_lld_write_pos(GDisplay* g) { + set_cursor(g); + } +#endif + +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDisplay* g) { + acquire_bus(g); + set_viewport(g); + set_cursor(g); + set_readmode(g); + dummy_read(g); + } + LLDSPEC color_t gdisp_lld_read_color(GDisplay* g) { + return read_data(g); + } + LLDSPEC void gdisp_lld_read_stop(GDisplay* g) { + set_writemode(g); + release_bus(g); + } +#endif + +#if GDISP_HARDWARE_FILLS && defined(GDISP_USE_DMA) + LLDSPEC void gdisp_lld_fill_area(GDisplay* g) { + acquire_bus(g); + set_viewport(g); + set_cursor(g); + dma_with_noinc(g, &color, g->p.cx * g->p.cy); + release_bus(g); + } +#endif + +#if GDISP_HARDWARE_BITFILLS && defined(GDISP_USE_DMA) + LLDSPEC void gdisp_lld_blit_area(GDisplay* g) { + pixel_t* buffer; + coord_t ynct; + + buffer = (pixel_t*)g->p.ptr + g->p.x1 + g->p.y1 * g->p.x2; + + acquire_bus(g); + set_viewport(g); + set_cursor(g); + + if (g->p.x2 == g->p.cx) { + dma_with_inc(g, buffer, g->p.cx * g->p.cy); + } else { + for (ycnt = g->p.cy; ycnt; ycnt--, buffer += g->p.x2) + dma_with_inc(g, buffer, g->p.cy); + } + + release_bus(g); + } +#endif + +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay* g) { + // .... + } +#endif + + +//////////////////////// OLD STUFF FROM HERE //////////////////////////////////////////////////// + void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; @@ -584,14 +635,14 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0000); // Leave sleep mode write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0033); // Display on release_bus(); - delayms(170); + gfxSleepMilliseconds(170); } else if (GDISP.Powermode == powerDeepSleep) { acquire_bus(); write_reg(SSD2119_REG_SLEEP_MODE_2, 0x0999); // Disable deep sleep function write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0000); // Leave sleep mode write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0033); // Display on release_bus(); - delayms(170); + gfxSleepMilliseconds(170); } else { acquire_bus(); write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0000); // Leave sleep mode @@ -607,7 +658,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0000); // Display off release_bus(); set_backlight(0); - delayms(25); + gfxSleepMilliseconds(25); break; case powerDeepSleep: @@ -617,7 +668,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0000); // Display off release_bus(); set_backlight(0); - delayms(25); + gfxSleepMilliseconds(25); break; default: From 70b8206356a903d5af081be04689fd5639e3e251 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 22 Oct 2013 09:17:41 +1000 Subject: [PATCH 087/160] Update graph demo so it compiles multi-os direct from a makefile --- demos/modules/gwin/graph/gfxconf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demos/modules/gwin/graph/gfxconf.h b/demos/modules/gwin/graph/gfxconf.h index 57903253..51c5bdc4 100644 --- a/demos/modules/gwin/graph/gfxconf.h +++ b/demos/modules/gwin/graph/gfxconf.h @@ -31,9 +31,9 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +//#define GFX_USE_OS_CHIBIOS TRUE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_POSIX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE From 22b59b8b4f50fb543770e68f70f2d9dbe48d7221 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 22 Oct 2013 09:19:22 +1000 Subject: [PATCH 088/160] Test for SSD 1289 driver bug. --- drivers/gdisp/SSD1289/gdisp_lld.c | 11 ++++++++--- drivers/gdisp/SSD1289/gdisp_lld_config.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 510f1560..f600b305 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -195,6 +195,9 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { LLDSPEC void gdisp_lld_write_start(GDisplay *g) { acquire_bus(g); set_viewport(g); + #if !GDISP_HARDWARE_STREAM_POS + set_cursor(g); + #endif } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { write_data(g, g->p.color); @@ -202,9 +205,11 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); } - LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { - set_cursor(g); - } + #if GDISP_HARDWARE_STREAM_POS + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { + set_cursor(g); + } + #endif #endif #if GDISP_HARDWARE_STREAM_READ diff --git a/drivers/gdisp/SSD1289/gdisp_lld_config.h b/drivers/gdisp/SSD1289/gdisp_lld_config.h index 84e518d2..f8743a2b 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_config.h @@ -24,7 +24,7 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE -#define GDISP_HARDWARE_STREAM_POS TRUE +//#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE #if defined(GDISP_USE_DMA) From 27b5383c1bcec9a8b45328bf051ee0624d0d1102 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 22 Oct 2013 15:52:31 +1000 Subject: [PATCH 089/160] Fix typos in drivers --- drivers/gdisp/HX8347D/gdisp_lld.c | 3 ++- drivers/gdisp/ILI9320/gdisp_lld.c | 2 +- drivers/gdisp/ILI9325/gdisp_lld.c | 3 +-- drivers/gdisp/ILI9481/gdisp_lld.c | 2 +- drivers/gdisp/RA8875/gdisp_lld.c | 2 +- drivers/gdisp/S6D1121/gdisp_lld.c | 2 +- drivers/gdisp/SSD1306/gdisp_lld.c | 2 +- drivers/gdisp/SSD1963/gdisp_lld.c | 2 +- drivers/gdisp/SSD2119/gdisp_lld.c | 2 +- src/gdisp/gdisp.c | 1 + 10 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gdisp/HX8347D/gdisp_lld.c b/drivers/gdisp/HX8347D/gdisp_lld.c index 3851c8e1..ab976db0 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld.c +++ b/drivers/gdisp/HX8347D/gdisp_lld.c @@ -217,8 +217,9 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; + case GDISP_CONTROL_BACKLIGHT: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index bf82a88a..6d7815cb 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -354,7 +354,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: diff --git a/drivers/gdisp/ILI9325/gdisp_lld.c b/drivers/gdisp/ILI9325/gdisp_lld.c index 6bb649b1..75b4cd13 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld.c +++ b/drivers/gdisp/ILI9325/gdisp_lld.c @@ -346,7 +346,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { return; } - g->g.Orientation = (orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: @@ -360,7 +360,6 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { return; } } - #endif #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/ILI9481/gdisp_lld.c b/drivers/gdisp/ILI9481/gdisp_lld.c index 5af12986..49e28b23 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld.c +++ b/drivers/gdisp/ILI9481/gdisp_lld.c @@ -311,7 +311,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; //case GDISP_CONTROL_BACKLIGHT: //case GDISP_CONTROL_CONTRAST: diff --git a/drivers/gdisp/RA8875/gdisp_lld.c b/drivers/gdisp/RA8875/gdisp_lld.c index 7916ef3b..b0508b58 100644 --- a/drivers/gdisp/RA8875/gdisp_lld.c +++ b/drivers/gdisp/RA8875/gdisp_lld.c @@ -260,7 +260,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; #endif diff --git a/drivers/gdisp/S6D1121/gdisp_lld.c b/drivers/gdisp/S6D1121/gdisp_lld.c index f7e12591..df9f01a7 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld.c +++ b/drivers/gdisp/S6D1121/gdisp_lld.c @@ -313,7 +313,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: diff --git a/drivers/gdisp/SSD1306/gdisp_lld.c b/drivers/gdisp/SSD1306/gdisp_lld.c index 36ba9686..b0834193 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld.c +++ b/drivers/gdisp/SSD1306/gdisp_lld.c @@ -196,7 +196,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_CONTRAST: diff --git a/drivers/gdisp/SSD1963/gdisp_lld.c b/drivers/gdisp/SSD1963/gdisp_lld.c index 11240568..b94c1a40 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld.c +++ b/drivers/gdisp/SSD1963/gdisp_lld.c @@ -264,7 +264,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { default: return; } - g->g.Orientation = (orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: diff --git a/drivers/gdisp/SSD2119/gdisp_lld.c b/drivers/gdisp/SSD2119/gdisp_lld.c index 548d2dd1..e3a2329a 100644 --- a/drivers/gdisp/SSD2119/gdisp_lld.c +++ b/drivers/gdisp/SSD2119/gdisp_lld.c @@ -735,7 +735,7 @@ void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { GDISP.clipx1 = GDISP.Width; GDISP.clipy1 = GDISP.Height; #endif - GDISP.Orientation = (gdisp_orientation_t)value; + g->g.Orientation = (orientation_t)g->p.ptr; return; case GDISP_CONTROL_BACKLIGHT: diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 21c6e247..53882492 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -2313,6 +2313,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c } #else void gdispGControl(GDisplay *g, unsigned what, void *value) { + (void)g; (void)what; (void)value; /* Ignore everything */ From 5e9e1a36ab3685ba9e50fa52fe2a8c7bf02ac094 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 22 Oct 2013 18:38:56 +1000 Subject: [PATCH 090/160] Convert SSD2119 to new driver format --- .../SSD2119/board_SSD2119_embest_dmstf4bb.h | 173 +++++ .../gdisp/SSD2119/board_SSD2119_template.h | 191 ++++++ drivers/gdisp/SSD2119/gdisp_lld.c | 596 ++++-------------- drivers/gdisp/SSD2119/gdisp_lld.mk | 5 +- .../SSD2119/gdisp_lld_board_embest_dmstf4bb.h | 193 ------ .../gdisp/SSD2119/gdisp_lld_board_template.h | 109 ---- drivers/gdisp/SSD2119/gdisp_lld_config.h | 15 +- 7 files changed, 494 insertions(+), 788 deletions(-) create mode 100644 drivers/gdisp/SSD2119/board_SSD2119_embest_dmstf4bb.h create mode 100644 drivers/gdisp/SSD2119/board_SSD2119_template.h delete mode 100644 drivers/gdisp/SSD2119/gdisp_lld_board_embest_dmstf4bb.h delete mode 100644 drivers/gdisp/SSD2119/gdisp_lld_board_template.h diff --git a/drivers/gdisp/SSD2119/board_SSD2119_embest_dmstf4bb.h b/drivers/gdisp/SSD2119/board_SSD2119_embest_dmstf4bb.h new file mode 100644 index 00000000..927e93a4 --- /dev/null +++ b/drivers/gdisp/SSD2119/board_SSD2119_embest_dmstf4bb.h @@ -0,0 +1,173 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD2119/board_SSD2119_embest_dmstf4bb.h + * @brief GDISP Graphic Driver subsystem board FSMC interface for the SSD2119 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->board to that structure. + +/* Using FSMC A19 (PE3) as DC */ +#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* DC = 0 */ +#define GDISP_RAM (*((volatile uint16_t *) 0x60100000)) /* DC = 1 */ +#define GDISP_DMA_STREAM STM32_DMA2_STREAM6 + +#define SET_RST palSetPad(GPIOD, 3); +#define CLR_RST palClearPad(GPIOD, 3); + +/* + * PWM configuration structure. We use timer 4 channel 2 (orange LED on board). + * The reason for so high clock is that with any lower, onboard coil is squeaking. + * The major disadvantage of this clock is a lack of linearity between PWM duty + * cycle width and brightness. In fact only with low preset one sees any change + * (eg. duty cycle between 1-20). Feel free to adjust this, maybe only my board + * behaves like this. According to the G5126 datesheet (backlight LED driver) + * the PWM frequency should be somewhere between 200 Hz to 200 kHz. + */ +static const PWMConfig pwmcfg = { + 1000000, /* 1 MHz PWM clock frequency. */ + 100, /* PWM period is 100 cycles. */ + NULL, + { + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL} + }, + 0 +}; + +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + #if defined(STM32F4XX) || defined(STM32F2XX) + /* STM32F4 FSMC init */ + rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); + + #if defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) + if (dmaStreamAllocate(GDISP_DMA_STREAM, 0, NULL, NULL)) + gfxExit(); + dmaStreamSetMemory0(GDISP_DMA_STREAM, &GDISP_RAM); + dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); + #endif + #else + #error "FSMC not implemented for this device" + #endif + + /* Group pins */ + IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8) | + (1 << 9) | (1 << 10) | (1 << 14) | (1 << 15), 0}; + + IOBus busE = {GPIOE, (1 << 3) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | + (1 << 13) | (1 << 14) | (1 << 15), 0}; + + /* FSMC is an alternate function 12 (AF12) */ + palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); + palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); + + /* FSMC timing register configuration */ + FSMC_Bank1->BTCR[0 + 1] = (FSMC_BTR1_ADDSET_2 | FSMC_BTR1_ADDSET_1) \ + | (FSMC_BTR1_DATAST_2 | FSMC_BTR1_DATAST_1) \ + | FSMC_BTR1_BUSTURN_0; + + /* Bank1 NOR/PSRAM control register configuration + * Write enable, memory databus width set to 16 bit, memory bank enable */ + FSMC_Bank1->BTCR[0] = FSMC_BCR1_WREN | FSMC_BCR1_MWID_0 | FSMC_BCR1_MBKEN; + + /* Display backlight control */ + /* TIM4 is an alternate function 2 (AF2) */ + pwmStart(&PWMD4, &pwmcfg); + palSetPadMode(GPIOD, 13, PAL_MODE_ALTERNATE(2)); + pwmEnableChannel(&PWMD4, 1, 100); + break; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if (state) { + CLR_RST; + } else { + SET_RST; + } +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + pwmEnableChannel(&PWMD4, 1, percent); +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + GDISP_REG = index; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + GDISP_RAM = data; +} + +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return GDISP_RAM; +} + +#if defined(GDISP_USE_DMA) + static inline void dma_with_noinc(GDisplay *g, color_t *buffer, int area) { + (void) g; + dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); + dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); + for (; area > 0; area -= 65535) { + dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area > 65535 ? 65535 : area); + dmaStreamEnable(GDISP_DMA_STREAM); + dmaWaitCompletion(GDISP_DMA_STREAM); + } + } + + static inline void dma_with_inc(GDisplay *g, color_t *buffer, int area) { + (void) g; + dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); + dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PINC | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); + for (; area > 0; area -= 65535) { + dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area > 65535 ? 65535 : area); + dmaStreamEnable(GDISP_DMA_STREAM); + dmaWaitCompletion(GDISP_DMA_STREAM); + } + } +#endif + +#endif /* _GDISP_LLD_BOARD_H */ + diff --git a/drivers/gdisp/SSD2119/board_SSD2119_template.h b/drivers/gdisp/SSD2119/board_SSD2119_template.h new file mode 100644 index 00000000..b4c6341d --- /dev/null +++ b/drivers/gdisp/SSD2119/board_SSD2119_template.h @@ -0,0 +1,191 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD2119/board_SSD2119_template.h + * @brief GDISP Graphic Driver subsystem board template for the SSD2119 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * + * @note Set the g->board member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Set the lcd back-light level. + * + * @param[in] g The GDisplay structure + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; +} + +/** + * @brief Set the bus in read mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +/** + * @brief Set the bus back into write mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +/** + * @brief Read data from the lcd. + * @return The data from the lcd + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return 0; +} + +/** + * The below section you can replace with #error if your interface doesn't support DMA + */ +#if defined(GDISP_USE_DMA) || defined(__DOXYGEN__) + //#error "GDISP - SSD2119: This interface does not support DMA" + + /** + * @brief Transfer data using DMA but don't increment the source address + * + * @param[in] g The GDisplay structure + * @param[in] buffer The source buffer location + * @param[in] area The number of pixels to transfer + * + * @notapi + */ + static inline void dma_with_noinc(GDisplay *g, color_t *buffer, int area) { + (void) g; + (void) buffer; + (void) area; + } + + /** + * @brief Transfer data using DMA incrementing the source address + * + * @param[in] g The GDisplay structure + * @param[in] buffer The source buffer location + * @param[in] area The number of pixels to transfer + * + * @notapi + */ + static inline void dma_with_inc(GDisplay *g, color_t *buffer, int area) { + (void) g; + (void) buffer; + (void) area; + } +#endif + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/SSD2119/gdisp_lld.c b/drivers/gdisp/SSD2119/gdisp_lld.c index e3a2329a..df05fc2c 100644 --- a/drivers/gdisp/SSD2119/gdisp_lld.c +++ b/drivers/gdisp/SSD2119/gdisp_lld.c @@ -8,20 +8,16 @@ /** * @file drivers/gdisp/SSD2119/gdisp_lld.c * @brief GDISP Graphics Driver subsystem low level driver source for the SSD2119 display. - * - * @addtogroup GDISP - * @{ */ #include "gfx.h" -#include "ssd2119.h" - #if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_SSD2119 #include "../drivers/gdisp/SSD2119/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" + #include "board_SSD2119.h" /*===========================================================================*/ @@ -41,6 +37,8 @@ #define GDISP_INITIAL_BACKLIGHT 100 #endif +#include "ssd2119.h" + /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ @@ -60,23 +58,22 @@ static void set_cursor(GDisplay* g) { write_reg(g, SSD2119_REG_Y_RAM_ADDR, g->p.y & 0x00FF); break; case GDISP_ROTATE_90: - write_reg(g, SSD2119_REG_X_RAM_ADDR, (GDISP_SCREEN_WIDTH - g->p.y - 1) & 0x01FF); - write_reg(g, SSD2119_REG_Y_RAM_ADDR, (GDISP_SCREEN_HEIGHT - g->p.x - 1) & 0x00FF); + write_reg(g, SSD2119_REG_X_RAM_ADDR, g->p.y & 0x01FF); + write_reg(g, SSD2119_REG_Y_RAM_ADDR, (GDISP_SCREEN_HEIGHT-1 - g->p.x) & 0x00FF); break; case GDISP_ROTATE_180: - write_reg(g, SSD2119_REG_X_RAM_ADDR, (GDISP_SCREEN_WIDTH - 1 - g->p.x) & 0x01FF); - write_reg(g, SSD2119_REG_Y_RAM_ADDR, (GDISP_SCREEN_HEIGHT - 1 - g->p.y) & 0x00FF); + write_reg(g, SSD2119_REG_X_RAM_ADDR, (GDISP_SCREEN_WIDTH-1 - g->p.x) & 0x01FF); + write_reg(g, SSD2119_REG_Y_RAM_ADDR, (GDISP_SCREEN_HEIGHT-1 - g->p.y) & 0x00FF); break; case GDISP_ROTATE_270: - write_reg(g, SSD2119_REG_X_RAM_ADDR, g->p.y & 0x01FF); + write_reg(g, SSD2119_REG_X_RAM_ADDR, (GDISP_SCREEN_WIDTH-1 - g->p.y) & 0x01FF); write_reg(g, SSD2119_REG_Y_RAM_ADDR, g->p.x & 0x00FF); break; } + write_index(g, SSD2119_REG_RAM_DATA); } static void set_viewport(GDisplay* g) { - set_cursor(g->p.x, g->p.y); - /* Reg 0x44 - Vertical RAM address position * Upper Byte - VEA * Lower Byte - VSA @@ -85,7 +82,6 @@ static void set_viewport(GDisplay* g) { * Lower 9 bits gives 0-511 range in each value, HSA and HEA respectively * 0 <= HSA <= HEA <= 0x13F */ - switch(g->g.Orientation) { case GDISP_ROTATE_0: write_reg(g, SSD2119_REG_V_RAM_POS, (((g->p.y + g->p.cy - 1) << 8) & 0xFF00 ) | (g->p.y & 0x00FF)); @@ -93,27 +89,21 @@ static void set_viewport(GDisplay* g) { write_reg(g, SSD2119_REG_H_RAM_END, (g->p.x + g->p.cx - 1) & 0x01FF); break; case GDISP_ROTATE_90: - write_reg(g, SSD2119_REG_V_RAM_POS, (((GDISP_SCREEN_HEIGHT - g->p.x - 1) & 0x00FF) << 8) | ((GDISP_SCREEN_HEIGHT - (g->p.x + g->p.cx)) & 0x00FF)); - write_reg(g, SSD2119_REG_H_RAM_START, (GDISP_SCREEN_WIDTH - (g->p.y + g->p.cy)) & 0x01FF); - write_reg(g, SSD2119_REG_H_RAM_END, (GDISP_SCREEN_WIDTH - g->p.y - 1) & 0x01FF); + write_reg(g, SSD2119_REG_V_RAM_POS, (((GDISP_SCREEN_HEIGHT-1 - g->p.x) & 0x00FF) << 8) | ((GDISP_SCREEN_HEIGHT - (g->p.x + g->p.cx)) & 0x00FF)); + write_reg(g, SSD2119_REG_H_RAM_START, (g->p.y & 0x01FF)); + write_reg(g, SSD2119_REG_H_RAM_END, (g->p.y + g->p.cy - 1) & 0x01FF); break; case GDISP_ROTATE_180: - write_reg(SSD2119_REG_V_RAM_POS, (((GDISP_SCREEN_HEIGHT - g->p.y - 1) & 0x00FF) << 8) | ((GDISP_SCREEN_HEIGHT - (g->p.y + g->p.cy)) & 0x00FF)); - write_reg(SSD2119_REG_H_RAM_START, (GDISP_SCREEN_WIDTH - (g->p.x + g->p.cx)) & 0x01FF); - write_reg(SSD2119_REG_H_RAM_END, (GDISP_SCREEN_WIDTH - g->p.x - 1) & 0x01FF); + write_reg(g, SSD2119_REG_V_RAM_POS, (((GDISP_SCREEN_HEIGHT-1 - g->p.y) & 0x00FF) << 8) | ((GDISP_SCREEN_HEIGHT - (g->p.y + g->p.cy)) & 0x00FF)); + write_reg(g, SSD2119_REG_H_RAM_START, (GDISP_SCREEN_WIDTH - (g->p.x + g->p.cx)) & 0x01FF); + write_reg(g, SSD2119_REG_H_RAM_END, (GDISP_SCREEN_WIDTH-1 - g->p.x) & 0x01FF); break; case GDISP_ROTATE_270: - write_reg(SSD2119_REG_V_RAM_POS, (((g->p.x + g->p.cx - 1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); - write_reg(SSD2119_REG_H_RAM_START, (g->p.y & 0x01FF)); - write_reg(SSD2119_REG_H_RAM_END, (g->p.y + g->p.cy - 1) & 0x01FF); + write_reg(g, SSD2119_REG_V_RAM_POS, (((g->p.x + g->p.cx - 1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); + write_reg(g, SSD2119_REG_H_RAM_START, (GDISP_SCREEN_WIDTH - (g->p.y + g->p.cy)) & 0x01FF); + write_reg(g, SSD2119_REG_H_RAM_END, (GDISP_SCREEN_WIDTH-1 - g->p.y) & 0x01FF); break; } - - set_cursor(g->p.x, g->p.y); -} - -static inline void reset_viewport(GDisplay* g) { - set_viewport(0, 0, g->g.Width, g->g.Height); } /*===========================================================================*/ @@ -129,7 +119,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { g->priv = 0; // initialise the board interface - init_board(); + init_board(g); // Hardware reset setpin_reset(g, TRUE); @@ -223,20 +213,22 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { write_reg(g, SSD2119_REG_Y_RAM_ADDR, 0x00); gfxSleepMicroseconds(5); - // Release the bus + // Finish Init + post_init_board(g); + + // Release the bus release_bus(g); - // Turn on the backlight + /* Turn on the back-light */ set_backlight(g, GDISP_INITIAL_BACKLIGHT); - // Initialise the GDISP structure + /* Initialise the GDISP structure */ g->g.Width = GDISP_SCREEN_WIDTH; g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Orientation = GDISP_ROTATE_0; g->g.Powermode = powerOn; g->g.Backlight = GDISP_INITIAL_BACKLIGHT; g->g.Contrast = GDISP_INITIAL_CONTRAST; - return TRUE; } @@ -261,14 +253,14 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { acquire_bus(g); set_viewport(g); set_cursor(g); - set_readmode(g); + setreadmode(g); dummy_read(g); } LLDSPEC color_t gdisp_lld_read_color(GDisplay* g) { return read_data(g); } LLDSPEC void gdisp_lld_read_stop(GDisplay* g) { - set_writemode(g); + setwritemode(g); release_bus(g); } #endif @@ -278,7 +270,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { acquire_bus(g); set_viewport(g); set_cursor(g); - dma_with_noinc(g, &color, g->p.cx * g->p.cy); + dma_with_noinc(g, &g->p.color, g->p.cx * g->p.cy); release_bus(g); } #endif @@ -306,450 +298,104 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { #endif #if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDisplay* g) { - // .... - } -#endif - - -//////////////////////// OLD STUFF FROM HERE //////////////////////////////////////////////////// - -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - #endif - - acquire_bus(); - set_cursor(x, y); - write_reg(SSD2119_REG_RAM_DATA, color); - release_bus(); -} - -/* ---- Optional Routines ---- */ -/* - All the below routines are optional. - Defining them will increase speed but everything - will work if they are not defined. - If you are not using a routine - turn it off using - the appropriate GDISP_HARDWARE_XXXX macro. - Don't bother coding for obvious similar routines if - there is no performance penalty as the emulation software - makes a good job of using similar routines. - eg. If gfillarea() is defined there is little - point in defining clear() unless the - performance bonus is significant. - For good performance it is suggested to implement - fillarea() and blitarea(). -*/ - -#if GDISP_HARDWARE_CLEARS || defined(__DOXYGEN__) - /** - * @brief Clear the display. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] color The color of the pixel - * - * @notapi - */ - void gdisp_lld_clear(color_t color) { - unsigned area; - - area = GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT; - - acquire_bus(); - reset_viewport(); - set_cursor(0, 0); - stream_start(); - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, &color); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area / 65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area % 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - uint32_t index; - for(index = 0; index < area; index++) - write_data(color); - #endif // defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - - stream_stop(); - release_bus(); - } -#endif - -#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a color. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] color The color of the fill - * - * @notapi - */ - void gdisp_lld_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) { - unsigned area; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - area = cx*cy; - - acquire_bus(); - set_viewport(x, y, cx, cy); - stream_start(); - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, &color); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area / 65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area % 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - uint32_t index; - for(index = 0; index < area; index++) - write_data(color); - #endif // defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - - stream_stop(); - release_bus(); - } -#endif - -#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__) - /** - * @brief Fill an area with a bitmap. - * @note Optional - The high level driver can emulate using software. - * - * @param[in] x, y The start filled area - * @param[in] cx, cy The width and height to be filled - * @param[in] srcx, srcy The bitmap position to start the fill from - * @param[in] srccx The width of a line in the bitmap. - * @param[in] buffer The pixels to use to fill the area. - * - * @notapi - */ - void gdisp_lld_blit_area_ex(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; srcx += GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; srcy += GDISP.clipy0 - y; y = GDISP.clipy0; } - if (srcx+cx > srccx) cx = srccx - srcx; - if (cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - buffer += srcx + srcy * srccx; - - acquire_bus(); - set_viewport(x, y, cx, cy); - stream_start(); - - #if defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - uint32_t area = cx * cy; - uint8_t i; - dmaStreamSetPeripheral(GDISP_DMA_STREAM, buffer); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PINC | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - for (i = area / 65535; i; i--) { - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - } - dmaStreamSetTransactionSize(GDISP_DMA_STREAM, area % 65535); - dmaStreamEnable(GDISP_DMA_STREAM); - dmaWaitCompletion(GDISP_DMA_STREAM); - #else - coord_t endx, endy; - uint32_t lg; - endx = srcx + cx; - endy = y + cy; - lg = srccx - cx; - for(; y < endy; y++, buffer += lg) - for(x=srcx; x < endx; x++) - write_data(*buffer++); - #endif // defined(GDISP_USE_FSMC) && defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - - stream_stop(); - release_bus(); - } -#endif - -#if (GDISP_NEED_PIXELREAD && GDISP_HARDWARE_PIXELREAD) || defined(__DOXYGEN__) - /** - * @brief Get the color of a particular pixel. - * @note Optional. - * @note If x,y is off the screen, the result is undefined. - * - * @param[in] x, y The pixel to be read - * - * @notapi - */ - color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y) { - color_t color; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; - #endif - - acquire_bus(); - set_cursor(x, y); - stream_start(); - - color = read_data(); // dummy read - color = read_data(); - - stream_stop(); - release_bus(); - - return color; - } -#endif - -#if (GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL) || defined(__DOXYGEN__) - /** - * @brief Scroll vertically a section of the screen. - * @note Optional. - * @note If x,y + cx,cy is off the screen, the result is undefined. - * @note If lines is >= cy, it is equivelent to a area fill with bgcolor. - * - * @param[in] x, y The start of the area to be scrolled - * @param[in] cx, cy The size of the area to be scrolled - * @param[in] lines The number of lines to scroll (Can be positive or negative) - * @param[in] bgcolor The color to fill the newly exposed area. - * - * @notapi - */ - void gdisp_lld_vertical_scroll(coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { - static color_t buf[((GDISP_SCREEN_HEIGHT > GDISP_SCREEN_WIDTH ) ? GDISP_SCREEN_HEIGHT : GDISP_SCREEN_WIDTH)]; - coord_t row0, row1; - unsigned i, gap, abslines, j; - - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0) { cx -= GDISP.clipx0 - x; x = GDISP.clipx0; } - if (y < GDISP.clipy0) { cy -= GDISP.clipy0 - y; y = GDISP.clipy0; } - if (!lines || cx <= 0 || cy <= 0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; - if (x+cx > GDISP.clipx1) cx = GDISP.clipx1 - x; - if (y+cy > GDISP.clipy1) cy = GDISP.clipy1 - y; - #endif - - abslines = lines < 0 ? -lines : lines; - - acquire_bus(); - if ((coord_t)abslines >= cy) { - abslines = cy; - gap = 0; - } else { - gap = cy - abslines; - for(i = 0; i < gap; i++) { - if(lines > 0) { - row0 = y + i + lines; - row1 = y + i; - } else { - row0 = (y - i - 1) + lines; - row1 = (y - i - 1); - } - - /* read row0 into the buffer and then write at row1*/ - set_viewport(x, row0, cx, 1); - stream_start(); - - j = read_data(); // dummy read - for (j = 0; (coord_t)j < cx; j++) - buf[j] = read_data(); - - stream_stop(); - - set_viewport(x, row1, cx, 1); - stream_start(); - for (j = 0; (coord_t)j < cx; j++) - write_data(buf[j]); - stream_stop(); - } - } - - /* fill the remaining gap */ - set_viewport(x, lines > 0 ? (y+(coord_t)gap) : y, cx, abslines); - stream_start(); - gap = cx*abslines; - for(i = 0; i < gap; i++) write_data(bgcolor); - stream_stop(); - release_bus(); - } -#endif - -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) - /** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ - void gdisp_lld_control(unsigned what, void *value) { - switch(what) { - case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) - return; - switch((gdisp_powermode_t)value) { - case powerOff: - acquire_bus(); - write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0001); // Enter sleep mode - write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0000); // Display off - write_reg(SSD2119_REG_OSC_START, 0x0000); // Turn off oscillator - release_bus(); - set_backlight(0); - break; - - case powerOn: - if (GDISP.Powermode == powerSleep) { - acquire_bus(); - write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0000); // Leave sleep mode - write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0033); // Display on - release_bus(); - gfxSleepMilliseconds(170); - } else if (GDISP.Powermode == powerDeepSleep) { - acquire_bus(); - write_reg(SSD2119_REG_SLEEP_MODE_2, 0x0999); // Disable deep sleep function - write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0000); // Leave sleep mode - write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0033); // Display on - release_bus(); - gfxSleepMilliseconds(170); - } else { - acquire_bus(); - write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0000); // Leave sleep mode - release_bus(); - gdisp_lld_init(); - } - set_backlight(100); - break; - - case powerSleep: - acquire_bus(); - write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0001); // Enter sleep mode - write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0000); // Display off - release_bus(); - set_backlight(0); - gfxSleepMilliseconds(25); - break; - - case powerDeepSleep: - acquire_bus(); - write_reg(SSD2119_REG_SLEEP_MODE_1, 0x0001); // Enter sleep mode - write_reg(SSD2119_REG_SLEEP_MODE_2, 0x2999); // Enable deep sleep function - write_reg(SSD2119_REG_DISPLAY_CTRL, 0x0000); // Display off - release_bus(); - set_backlight(0); - gfxSleepMilliseconds(25); - break; - - default: - return; - } - GDISP.Powermode = (gdisp_powermode_t)value; + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) return; - - case GDISP_CONTROL_ORIENTATION: - if (GDISP.Orientation == (gdisp_orientation_t)value) - return; - switch((gdisp_orientation_t)value) { - case GDISP_ROTATE_0: - acquire_bus(); - /* TB = 0 */ - write_reg(SSD2119_REG_OUTPUT_CTRL, 0x30EF); - /* ID = 11 AM = 0 */ - write_reg(SSD2119_REG_ENTRY_MODE, 0x6830); - release_bus(); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - - case GDISP_ROTATE_90: - acquire_bus(); - /* TB = 1 */ - write_reg(SSD2119_REG_OUTPUT_CTRL, 0x32EF); - /* ID = 10 AM = 1 */ - write_reg(SSD2119_REG_ENTRY_MODE, 0x6828); - release_bus(); - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - - case GDISP_ROTATE_180: - acquire_bus(); - /* TB = 0 */ - write_reg(SSD2119_REG_OUTPUT_CTRL, 0x30EF); - /* ID = 00 AM = 0 */ - write_reg(SSD2119_REG_ENTRY_MODE, 0x6800); - release_bus(); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - break; - - case GDISP_ROTATE_270: - acquire_bus(); - /* TB = 1 */ - write_reg(SSD2119_REG_OUTPUT_CTRL, 0x32EF); - /* ID = 01 AM = 1 */ - write_reg(SSD2119_REG_ENTRY_MODE, 0x6818); - release_bus(); - GDISP.Height = GDISP_SCREEN_WIDTH; - GDISP.Width = GDISP_SCREEN_HEIGHT; - break; - - default: - return; - } - - #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif - g->g.Orientation = (orientation_t)g->p.ptr; - return; - - case GDISP_CONTROL_BACKLIGHT: - if ((unsigned)value > 100) - value = (void *)100; - set_backlight((unsigned)value); - GDISP.Backlight = (unsigned)value; - return; - + switch((powermode_t)g->p.ptr) { + case powerOff: + case powerDeepSleep: + acquire_bus(g); + write_reg(g, SSD2119_REG_SLEEP_MODE_1, 0x0001); // Enter sleep mode + write_reg(g, SSD2119_REG_SLEEP_MODE_2, 0x2999); // Enable deep sleep function + write_reg(g, SSD2119_REG_DISPLAY_CTRL, 0x0000); // Display off + if ((powermode_t)g->p.ptr == powerOff) + write_reg(g, SSD2119_REG_OSC_START, 0x0000); // Turn off oscillator + release_bus(g); + set_backlight(g, 0); + break; + case powerSleep: + acquire_bus(g); + write_reg(g, SSD2119_REG_SLEEP_MODE_1, 0x0001); // Enter sleep mode + write_reg(g, SSD2119_REG_DISPLAY_CTRL, 0x0000); // Display off + release_bus(g); + set_backlight(g, 0); + break; + case powerOn: + acquire_bus(g); + if (g->g.Powermode == powerOff) { + write_reg(g, SSD2119_REG_OSC_START, 0x0001); // Start the oscillator + gfxSleepMicroseconds(5); + write_reg(g, SSD2119_REG_SLEEP_MODE_2, 0x0999); // Disable deep sleep function + } else if (g->g.Powermode == powerDeepSleep) + write_reg(g, SSD2119_REG_SLEEP_MODE_2, 0x0999); // Disable deep sleep function + write_reg(g, SSD2119_REG_SLEEP_MODE_1, 0x0000); // Leave sleep mode + write_reg(g, SSD2119_REG_DISPLAY_CTRL, 0x0033); // Display on + release_bus(g); + gfxSleepMicroseconds(25); + set_backlight(g, g->g.Backlight); + break; default: return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(g); + /* ID = 11 AM = 0 */ + write_reg(g, SSD2119_REG_ENTRY_MODE, 0x6830); + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + acquire_bus(g); + /* ID = 01 AM = 1 */ + write_reg(g, SSD2119_REG_ENTRY_MODE, 0x6818); + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + acquire_bus(g); + /* ID = 00 AM = 0 */ + write_reg(g, SSD2119_REG_ENTRY_MODE, 0x6800); + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + acquire_bus(g); + /* ID = 10 AM = 1 */ + write_reg(g, SSD2119_REG_ENTRY_MODE, 0x6828); + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + //case GDISP_CONTROL_CONTRAST: + default: + return; } } #endif #endif /* GFX_USE_GDISP */ -/** @} */ diff --git a/drivers/gdisp/SSD2119/gdisp_lld.mk b/drivers/gdisp/SSD2119/gdisp_lld.mk index e9c70efb..46807f62 100644 --- a/drivers/gdisp/SSD2119/gdisp_lld.mk +++ b/drivers/gdisp/SSD2119/gdisp_lld.mk @@ -1,5 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/SSD2119/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/SSD2119 +GFXSRC += $(GFXLIB)/drivers/gdisp/SSD2119/gdisp_lld.c diff --git a/drivers/gdisp/SSD2119/gdisp_lld_board_embest_dmstf4bb.h b/drivers/gdisp/SSD2119/gdisp_lld_board_embest_dmstf4bb.h deleted file mode 100644 index 126cd960..00000000 --- a/drivers/gdisp/SSD2119/gdisp_lld_board_embest_dmstf4bb.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD2119/gdisp_lld_board_embest_dmstf4bb.h - * @brief GDISP Graphic Driver subsystem board FSMC interface for the SSD2119 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/* This board file uses only FSMC, so don't undefine this. */ -#define GDISP_USE_FSMC -/* But it is OK to disable DMA use. */ -#define GDISP_USE_DMA -#define GDISP_DMA_STREAM STM32_DMA2_STREAM6 - -/* Using FSMC A19 (PE3) as DC */ -#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* DC = 0 */ -#define GDISP_RAM (*((volatile uint16_t *) 0x60100000)) /* DC = 1 */ - -#define SET_RST palSetPad(GPIOD, 3); -#define CLR_RST palClearPad(GPIOD, 3); - -/* - * PWM configuration structure. We use timer 4 channel 2 (orange LED on board). - * The reason for so high clock is that with any lower, onboard coil is squeaking. - * The major disadvantage of this clock is a lack of linearity between PWM duty - * cycle width and brightness. In fact only with low preset one sees any change - * (eg. duty cycle between 1-20). Feel free to adjust this, maybe only my board - * behaves like this. According to the G5126 datesheet (backlight LED driver) - * the PWM frequency should be somewhere between 200 Hz to 200 kHz. - */ -static const PWMConfig pwmcfg = { - 1000000, /* 1 MHz PWM clock frequency. */ - 100, /* PWM period is 100 cycles. */ - NULL, - { - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL}, - {PWM_OUTPUT_ACTIVE_HIGH, NULL} - }, - 0 -}; - -/** - * @brief Initialise the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins - * - * @notapi - */ -static inline void init_board(void) { - unsigned char FSMC_Bank; - - #ifndef GDISP_USE_FSMC - #error "This board uses only FSMC, please define GDISP_USE_FSMC" - #endif - - #if defined(STM32F4XX) || defined(STM32F2XX) - /* STM32F4 FSMC init */ - rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); - - #if defined(GDISP_USE_DMA) && defined(GDISP_DMA_STREAM) - if (dmaStreamAllocate(GDISP_DMA_STREAM, 0, NULL, NULL)) - gfxExit(); - dmaStreamSetMemory0(GDISP_DMA_STREAM, &GDISP_RAM); - dmaStreamSetMode(GDISP_DMA_STREAM, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_DIR_M2M); - #endif - #else - #error "FSMC not implemented for this device" - #endif - - /* Group pins */ - IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8) | - (1 << 9) | (1 << 10) | (1 << 14) | (1 << 15), 0}; - - IOBus busE = {GPIOE, (1 << 3) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | - (1 << 13) | (1 << 14) | (1 << 15), 0}; - - /* FSMC is an alternate function 12 (AF12) */ - palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); - palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); - - FSMC_Bank = 0; - /* FSMC timing register configuration */ - FSMC_Bank1->BTCR[FSMC_Bank + 1] = (FSMC_BTR1_ADDSET_2 | FSMC_BTR1_ADDSET_1) \ - | (FSMC_BTR1_DATAST_2 | FSMC_BTR1_DATAST_1) \ - | FSMC_BTR1_BUSTURN_0; - - /* Bank1 NOR/PSRAM control register configuration - * Write enable, memory databus width set to 16 bit, memory bank enable */ - FSMC_Bank1->BTCR[FSMC_Bank] = FSMC_BCR1_WREN | FSMC_BCR1_MWID_0 | FSMC_BCR1_MBKEN; - - /* Display backlight control */ - /* TIM4 is an alternate function 2 (AF2) */ - pwmStart(&PWMD4, &pwmcfg); - palSetPadMode(GPIOD, 13, PAL_MODE_ALTERNATE(2)); - pwmEnableChannel(&PWMD4, 1, 100); -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - if (state) { - CLR_RST; - } else { - SET_RST; - } -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - pwmEnableChannel(&PWMD4, 1, percent); -} - -/** - * @brief Take exclusive control of the bus - * @note Not needed, not implemented - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -/** - * @brief Release exclusive control of the bus - * @note Not needed, not implemented - * - * @notapi - */ -static inline void release_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - GDISP_REG = index; -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - GDISP_RAM = data; -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - return GDISP_RAM; -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/SSD2119/gdisp_lld_board_template.h b/drivers/gdisp/SSD2119/gdisp_lld_board_template.h deleted file mode 100644 index 2e4d53df..00000000 --- a/drivers/gdisp/SSD2119/gdisp_lld_board_template.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD2119/gdisp_lld_board_template.h - * @brief GDISP Graphic Driver subsystem board template for the SSD2119 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief Initialise the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins - * - * @notapi - */ -static inline void init_board(void) { - -} - -/** - * @brief Set or clear the lcd reset pin. - * - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * - * @notapi - */ -static inline void setpin_reset(bool_t state) { - -} - -/** - * @brief Set the lcd back-light level. - * - * @param[in] percent 0 to 100% - * - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * @note Not needed, not implemented - * - * @notapi - */ -static inline void acquire_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -/** - * @brief Release exclusive control of the bus - * @note Not needed, not implemented - * - * @notapi - */ -static inline void release_bus(void) { - /* Nothing to do here since LCD is the only device on that bus */ -} - -/** - * @brief Send data to the index register. - * - * @param[in] index The index register to set - * - * @notapi - */ -static inline void write_index(uint16_t index) { - -} - -/** - * @brief Send data to the lcd. - * - * @param[in] data The data to send - * - * @notapi - */ -static inline void write_data(uint16_t data) { - -} - -#if GDISP_HARDWARE_READPIXEL || GDISP_HARDWARE_SCROLL || defined(__DOXYGEN__) -/** - * @brief Read data from the lcd. - * - * @return The data from the lcd - * @note The chip select may need to be asserted/de-asserted - * around the actual spi read - * - * @notapi - */ -static inline uint16_t read_data(void) { - -} -#endif - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ diff --git a/drivers/gdisp/SSD2119/gdisp_lld_config.h b/drivers/gdisp/SSD2119/gdisp_lld_config.h index 3ad247e6..5d81057c 100644 --- a/drivers/gdisp/SSD2119/gdisp_lld_config.h +++ b/drivers/gdisp/SSD2119/gdisp_lld_config.h @@ -22,15 +22,16 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "SSD2119" - -#define GDISP_HARDWARE_CLEARS TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -#define GDISP_HARDWARE_SCROLL TRUE -#define GDISP_HARDWARE_PIXELREAD TRUE +#define GDISP_HARDWARE_STREAM_WRITE TRUE +#define GDISP_HARDWARE_STREAM_READ TRUE +#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE +#if defined(GDISP_USE_DMA) + #define GDISP_HARDWARE_FILLS TRUE + #define GDISP_HARDWARE_BITFILLS TRUE +#endif + #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ From 299cb353afcb1f43b8d209db80e9d186b62d9a3d Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 22 Oct 2013 19:52:54 +1000 Subject: [PATCH 091/160] Bug fixes to SSD1306. Orientation in all directions is also now supported. --- drivers/gdisp/SSD1306/gdisp_lld.c | 79 +++++++++++++++++++++++-------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/drivers/gdisp/SSD1306/gdisp_lld.c b/drivers/gdisp/SSD1306/gdisp_lld.c index b0834193..079c9256 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld.c +++ b/drivers/gdisp/SSD1306/gdisp_lld.c @@ -51,8 +51,11 @@ #define write_cmd3(g, cmd1, cmd2, cmd3) { write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); } // Some common routines and macros -#define delay(us) gfxSleepMicroseconds(us) -#define delayms(ms) gfxSleepMilliseconds(ms) +#define delay(us) gfxSleepMicroseconds(us) +#define delayms(ms) gfxSleepMilliseconds(ms) + +#define xyaddr(x, y) ((x) + ((y)>>3)*GDISP_SCREEN_WIDTH) +#define xybit(y) (1<<((y)&7)) /*===========================================================================*/ /* Driver exported functions. */ @@ -135,17 +138,57 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_HARDWARE_DRAWPIXEL LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + coord_t x, y; + + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90: + x = g->p.y; + y = GDISP_SCREEN_HEIGHT-1 - g->p.x; + break; + case GDISP_ROTATE_180: + x = GDISP_SCREEN_WIDTH-1 - g->p.x; + y = GDISP_SCREEN_HEIGHT-1 - g->p.y; + break; + case GDISP_ROTATE_270: + x = GDISP_SCREEN_HEIGHT-1 - g->p.y; + x = g->p.x; + break; + } if (g->p.color != Black) - RAM(g)[g->p.x + (g->p.y>>3)*GDISP_SCREEN_WIDTH] |= (1<<(g->p.y&7)); + RAM(g)[xyaddr(x, y)] |= xybit(y); else - RAM(g)[g->p.x + (g->p.y>>3)*GDISP_SCREEN_WIDTH] &= ~(1<<(g->p.y&7)); + RAM(g)[xyaddr(x, y)] &= ~xybit(y); g->flags |= GDISP_FLG_NEEDFLUSH; } #endif #if GDISP_HARDWARE_PIXELREAD LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { - return (RAM(g)[g->p.x + (g->p.y>>3)*GDISP_SCREEN_WIDTH] & (1<<(g->p.y&7))) ? White : Black; + coord_t x, y; + + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90: + x = g->p.y; + y = GDISP_SCREEN_HEIGHT-1 - g->p.x; + break; + case GDISP_ROTATE_180: + x = GDISP_SCREEN_WIDTH-1 - g->p.x; + y = GDISP_SCREEN_HEIGHT-1 - g->p.y; + break; + case GDISP_ROTATE_270: + x = GDISP_SCREEN_HEIGHT-1 - g->p.y; + y = g->p.x; + break; + } + return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black; } #endif @@ -167,6 +210,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { acquire_bus(g); write_cmd(g, SSD1306_DISPLAYON); release_bus(g); + break; default: return; } @@ -177,21 +221,16 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { if (g->g.Orientation == (orientation_t)g->p.ptr) return; switch((orientation_t)g->p.ptr) { + /* Rotation is handled by the drawing routines */ case GDISP_ROTATE_0: - acquire_bus(g); - write_cmd(g, SSD1306_COMSCANDEC); - write_cmd(g, SSD1306_SEGREMAP+1); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - release_bus(g); - break; case GDISP_ROTATE_180: - acquire_bus(g); - write_cmd(g, SSD1306_COMSCANINC); - write_cmd(g, SSD1306_SEGREMAP); - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Width = GDISP_SCREEN_WIDTH; - release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; break; default: return; @@ -203,14 +242,14 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; acquire_bus(g); - write_cmd2(g, SSD1306_SETCONTRAST, (((uint16_t)value)<<8)/101); + write_cmd2(g, SSD1306_SETCONTRAST, (((unsigned)g->p.ptr)<<8)/101); release_bus(g); g->g.Contrast = (unsigned)g->p.ptr; return; // Our own special controller code to inverse the display // 0 = normal, 1 = inverse - case GDISP_CONTROL_INVERT: + case GDISP_CONTROL_INVERSE: acquire_bus(g); write_cmd(g, g->p.ptr ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY); release_bus(g); From 92b00e125cf8d7754e12fd05e0a2cdfd6550af07 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 22 Oct 2013 19:53:39 +1000 Subject: [PATCH 092/160] Convert ST7565 driver to new driver format. --- drivers/gdisp/ST7565/board_ST7565_template.h | 108 +++++ drivers/gdisp/ST7565/gdisp_lld.c | 419 +++++++++--------- drivers/gdisp/ST7565/gdisp_lld.mk | 6 +- .../gdisp/ST7565/gdisp_lld_board_template.h | 82 ---- drivers/gdisp/ST7565/gdisp_lld_config.h | 11 +- 5 files changed, 320 insertions(+), 306 deletions(-) create mode 100644 drivers/gdisp/ST7565/board_ST7565_template.h delete mode 100644 drivers/gdisp/ST7565/gdisp_lld_board_template.h diff --git a/drivers/gdisp/ST7565/board_ST7565_template.h b/drivers/gdisp/ST7565/board_ST7565_template.h new file mode 100644 index 00000000..aef6cf2b --- /dev/null +++ b/drivers/gdisp/ST7565/board_ST7565_template.h @@ -0,0 +1,108 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ST7565/board_ST7565_template.h + * @brief GDISP Graphic Driver subsystem board interface for the ST7565 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * + * @note Set the g->board member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send a command to the controller. + * + * @param[in] g The GDisplay structure + * @param[in] cmd The command to send * + * + * @notapi + */ +static inline void write_cmd(GDisplay *g, uint8_t cmd) { + (void) g; + (void) cmd; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { + (void) g; + (void) data; + (void) length; +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ + diff --git a/drivers/gdisp/ST7565/gdisp_lld.c b/drivers/gdisp/ST7565/gdisp_lld.c index 960b1389..bd8c7b74 100644 --- a/drivers/gdisp/ST7565/gdisp_lld.c +++ b/drivers/gdisp/ST7565/gdisp_lld.c @@ -5,265 +5,258 @@ * http://ugfx.org/license.html */ +/** + * @file drivers/gdisp/ST7565/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the ST7565 display. + */ + #include "gfx.h" -#if GFX_USE_GDISP || defined(__DOXYGEN__) +#if GFX_USE_GDISP +#define GDISP_DRIVER_VMT GDISPVMT_ST7565 +#include "../drivers/gdisp/ST7565/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" -/* Include the emulation code for things we don't support */ -#include "gdisp/lld/emulation.c" -#include "st7565.h" -#include "gdisp_lld_board.h" - +#include "board_ST7565.h" /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ #ifndef GDISP_SCREEN_HEIGHT -#define GDISP_SCREEN_HEIGHT 64 + #define GDISP_SCREEN_HEIGHT 64 #endif #ifndef GDISP_SCREEN_WIDTH -#define GDISP_SCREEN_WIDTH 128 + #define GDISP_SCREEN_WIDTH 128 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 51 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 #endif -#define GDISP_INITIAL_CONTRAST 0xFF +#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0) + +#include "st7565.h" /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ // Some common routines and macros -#define delay(us) gfxSleepMicroseconds(us) -#define delay_ms(ms) gfxSleepMilliseconds(ms) +#define RAM(g) ((uint8_t *)g->priv) +#define write_cmd2(g, cmd1, cmd2) { write_cmd(g, cmd1); write_cmd(g, cmd2); } +#define write_cmd3(g, cmd1, cmd2, cmd3) { write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); } -// The memory buffer for the display -static uint8_t gdisp_buffer[GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8]; +// Some common routines and macros +#define delay(us) gfxSleepMicroseconds(us) +#define delay_ms(ms) gfxSleepMilliseconds(ms) -/** Set the display to normal or inverse. - * @param[in] value 0 for normal mode, or 1 for inverse mode. - * @notapi - */ -static void invert_display(uint8_t i) { - write_cmd(i ? ST7565_INVERT_DISPLAY : ST7565_POSITIVE_DISPLAY); -} - -/** Turn the whole display off. - * Sends the display to sleep, but leaves RAM intact. - * @notapi - */ -static void display_off(void) { - write_cmd(ST7565_DISPLAY_OFF); -} - -/** Turn the whole display on. - * Wakes up this display following a sleep() call. - * @notapi - */ -static void display_on(void) { - write_cmd(ST7565_DISPLAY_ON); -} - -/** Set the display contrast. - * @param[in] value The contrast, from 1 to 63. - * @notapi - */ -static void set_contrast(uint8_t value) { - write_cmd(ST7565_CONTRAST); - write_cmd(value & 0x3F); -} - -/** Set the display start line. This is the line at which the display will start rendering. - * @param[in] value A value from 0 to 63 denoting the line to start at. - * @notapi - */ -static void set_display_start_line(unsigned char value) { - write_cmd(ST7565_START_LINE | value); -} - -static void gdisp_lld_display(void) { - uint8_t p; - set_display_start_line(0); - - for (p = 0; p < 8; p++) { - write_cmd(ST7565_PAGE | p); - write_cmd(ST7565_COLUMN_MSB | 0); - write_cmd(ST7565_COLUMN_LSB | 0); - write_cmd(ST7565_RMW); - write_data(&gdisp_buffer[p * GDISP_SCREEN_WIDTH], GDISP_SCREEN_WIDTH); - } -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ +#define xyaddr(x, y) ((x) + ((y)>>3)*GDISP_SCREEN_WIDTH) +#define xybit(y) (1<<((y)&7)) /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ -/* ---- Required Routines ---- */ -/* - The following 2 routines are required. - All other routines are optional. - */ - /** - * @brief Low level GDISP driver initialization. - * - * @notapi + * As this controller can't update on a pixel boundary we need to maintain the + * the entire display surface in memory so that we can do the necessary bit + * operations. Fortunately it is a small display in monochrome. + * 64 * 128 / 8 = 1024 bytes. */ -bool_t gdisp_lld_init(void) { - // Initialize your display - init_board(); - // Hardware reset. - setpin_reset(TRUE); - delay_ms(10); - setpin_reset(FALSE); - delay_ms(1); +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // The private area is the display surface. + g->priv = gfxAlloc(GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8); - write_cmd(ST7565_LCD_BIAS_7); - write_cmd(ST7565_ADC_NORMAL); - write_cmd(ST7565_COM_SCAN_INC); - set_display_start_line(0); + // Initialise the board interface + init_board(g); - set_contrast(32); - write_cmd(ST7565_RESISTOR_RATIO | 0x3); + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(20); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(20); - // turn on voltage converter (VC=1, VR=0, VF=0) - write_cmd(ST7565_POWER_CONTROL | 0x04); - delay_ms(50); - // turn on voltage regulator (VC=1, VR=1, VF=0) - write_cmd(ST7565_POWER_CONTROL | 0x06); - delay_ms(50); - // turn on voltage follower (VC=1, VR=1, VF=1) - write_cmd(ST7565_POWER_CONTROL | 0x07); - delay_ms(50); + acquire_bus(g); - display_on(); - write_cmd(ST7565_ALLON_NORMAL); - invert_display(0);// Disable Inversion of display. + write_cmd(g, ST7565_LCD_BIAS_7); + write_cmd(g, ST7565_ADC_NORMAL); + write_cmd(g, ST7565_COM_SCAN_INC); + write_cmd(g, ST7565_START_LINE | 0); - write_cmd(ST7565_RMW); - gdisp_lld_display(); + write_cmd2(g, ST7565_CONTRAST, GDISP_INITIAL_CONTRAST*64/101); + write_cmd(g, ST7565_RESISTOR_RATIO | 0x3); - // Initialize the GDISP structure - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOn; - GDISP.Contrast = 50; -#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; -#endif - return TRUE; + // turn on voltage converter (VC=1, VR=0, VF=0) + write_cmd(g, ST7565_POWER_CONTROL | 0x04); + delay_ms(50); + + // turn on voltage regulator (VC=1, VR=1, VF=0) + write_cmd(g, ST7565_POWER_CONTROL | 0x06); + delay_ms(50); + + // turn on voltage follower (VC=1, VR=1, VF=1) + write_cmd(g, ST7565_POWER_CONTROL | 0x07); + delay_ms(50); + + write_cmd(g, ST7565_DISPLAY_ON); + write_cmd(g, ST7565_ALLON_NORMAL); + write_cmd(g, ST7565_POSITIVE_DISPLAY); // Disable Inversion of display. + + write_cmd(g, ST7565_RMW); + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + return TRUE; } -/** - * @brief Draws a pixel on the display. - * - * @param[in] x X location of the pixel - * @param[in] y Y location of the pixel - * @param[in] color The color of the pixel - * - * @notapi - */ -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) { -#if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - if (x < GDISP.clipx0 || y < GDISP.clipy0 || x >= GDISP.clipx1 || y >= GDISP.clipy1) return; +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay *g) { + unsigned p; + + // Don't flush if we don't need it. + if (!(g->flags & GDISP_FLG_NEEDFLUSH)) + return; + + acquire_bus(g); + for (p = 0; p < 8; p++) { + write_cmd(g, ST7565_PAGE | p); + write_cmd(g, ST7565_COLUMN_MSB | 0); + write_cmd(g, ST7565_COLUMN_LSB | 0); + write_cmd(g, ST7565_RMW); + write_data(g, RAM(g) + (p*GDISP_SCREEN_WIDTH), GDISP_SCREEN_WIDTH); + } + release_bus(g); + } #endif - if (color == 1) - gdisp_buffer[x+ (y/8)*GDISP_SCREEN_WIDTH] |= (1<g.Orientation) { + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90: + x = g->p.y; + y = GDISP_SCREEN_HEIGHT-1 - g->p.x; + break; + case GDISP_ROTATE_180: + x = GDISP_SCREEN_WIDTH-1 - g->p.x; + y = GDISP_SCREEN_HEIGHT-1 - g->p.y; + break; + case GDISP_ROTATE_270: + x = GDISP_SCREEN_HEIGHT-1 - g->p.y; + y = g->p.x; + break; + } + if (g->p.color != Black) + RAM(g)[xyaddr(x, y)] |= xybit(y); + else + RAM(g)[xyaddr(x, y)] &= ~xybit(y); + g->flags |= GDISP_FLG_NEEDFLUSH; + } +#endif -#if (GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL) || defined(__DOXYGEN__) -/** - * @brief Driver Control - * @details Unsupported control codes are ignored. - * @note The value parameter should always be typecast to (void *). - * @note There are some predefined and some specific to the low level driver. - * @note GDISP_CONTROL_POWER - Takes a gdisp_powermode_t - * GDISP_CONTROL_ORIENTATION - Takes a gdisp_orientation_t - * GDISP_CONTROL_BACKLIGHT - Takes an int from 0 to 100. For a driver - * that only supports off/on anything other - * than zero is on. - * GDISP_CONTROL_CONTRAST - Takes an int from 0 to 100. - * GDISP_CONTROL_LLD - Low level driver control constants start at - * this value. - * - * @param[in] what What to do. - * @param[in] value The value to use (always cast to a void *). - * - * @notapi - */ -void gdisp_lld_control(unsigned what, void *value) { - switch(what) { - case GDISP_CONTROL_POWER: - if (GDISP.Powermode == (gdisp_powermode_t)value) - return; +#if GDISP_HARDWARE_PIXELREAD + LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { + coord_t x, y; - switch((gdisp_powermode_t)value) { - case powerOff: - display_off(); - break; - case powerSleep: - display_off(); - break; - case powerDeepSleep: - display_off(); - break; - case powerOn: - display_on(); - break; - default: - return; - } - GDISP.Powermode = (gdisp_powermode_t)value; - return; + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90: + x = g->p.y; + y = GDISP_SCREEN_HEIGHT-1 - g->p.x; + break; + case GDISP_ROTATE_180: + x = GDISP_SCREEN_WIDTH-1 - g->p.x; + y = GDISP_SCREEN_HEIGHT-1 - g->p.y; + break; + case GDISP_ROTATE_270: + x = GDISP_SCREEN_HEIGHT-1 - g->p.y; + x = g->p.x; + break; + } + return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black; + } +#endif - case GDISP_CONTROL_BACKLIGHT: - set_backlight((uint8_t)(size_t)value); - return; +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + case powerSleep: + case powerDeepSleep: + acquire_bus(g); + write_cmd(g, ST7565_DISPLAY_OFF); + release_bus(g); + break; + case powerOn: + acquire_bus(g); + write_cmd(g, ST7565_DISPLAY_ON); + release_bus(g); + break; + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; - case GDISP_CONTROL_CONTRAST: - if ((unsigned)value > 100) value = (void*)100; - if (GDISP.Contrast == (uint8_t)((float)((size_t)value) * 63.0/100.0)) - return; - set_contrast((uint8_t)((float)((size_t)value) * 63.0/100.0) ); - GDISP.Contrast = (unsigned)value; - return; + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + /* Rotation is handled by the drawing routines */ + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; - case GDISP_CONTROL_LLD_FLUSH: - gdisp_lld_display(); - return; - } -} + case GDISP_CONTROL_CONTRAST: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + acquire_bus(g); + write_cmd2(g, ST7565_CONTRAST, ((((unsigned)g->p.ptr)<<6)/101) & 0x3F); + release_bus(g); + g->g.Contrast = (unsigned)g->p.ptr; + return; + } + } #endif // GDISP_NEED_CONTROL #endif // GFX_USE_GDISP -/** @} */ - diff --git a/drivers/gdisp/ST7565/gdisp_lld.mk b/drivers/gdisp/ST7565/gdisp_lld.mk index cd925824..cf0896e6 100644 --- a/drivers/gdisp/ST7565/gdisp_lld.mk +++ b/drivers/gdisp/ST7565/gdisp_lld.mk @@ -1,6 +1,2 @@ -# List the required driver. -GFXSRC += $(GFXLIB)/drivers/gdisp/ST7565/gdisp_lld.c - -# Required include directories GFXINC += $(GFXLIB)/drivers/gdisp/ST7565 - +GFXSRC += $(GFXLIB)/drivers/gdisp/ST7565/gdisp_lld.c diff --git a/drivers/gdisp/ST7565/gdisp_lld_board_template.h b/drivers/gdisp/ST7565/gdisp_lld_board_template.h deleted file mode 100644 index 2f40ccc7..00000000 --- a/drivers/gdisp/ST7565/gdisp_lld_board_template.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/** - * @brief Initialize the board for the display. - * @notes This board definition uses GPIO and assumes exclusive access to these GPIO pins - * @notapi - */ -static inline void init_board(void) { - /* Configure SPI bus here. Up to 10Mhz, SPI Mode = 3 (CPOL = 1, CPHA = 0) */ - /* Configure A0, !CS, !RST pin for output */ -} - -/** - * @brief Set or clear the lcd reset pin. - * @param[in] state TRUE = lcd in reset, FALSE = normal operation - * @notapi - */ -static inline void setpin_reset(bool_t state) { - /* Set !CS to low */ - if (state) { - /* Set !RST to low */ - } else { - /* Set !RST to high */ - } -} - -/** - * @brief Set the lcd back-light level. - * @param[in] percent 0 to 100% - * @notapi - */ -static inline void set_backlight(uint8_t percent) { - -} - -/** - * @brief Take exclusive control of the bus - * @notapi - */ -static inline void acquire_bus(void) { - -} - -/** - * @brief Release exclusive control of the bus - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Send command to the display. - * @param[in] cmd The command to send - * @notapi - */ -static inline void write_cmd(uint8_t cmd) { - /* Set A0 to low */ - /* Transmit cmd over SPI */ -} - -/** - * @brief Send data to the display. - * @param[in] data The data to send - * @notapi - */ -static inline void write_data(uint8_t* data, uint16_t length) { - /* Set A0 to high */ - /* Transmit data for length over SPI. DMA is recommended. */ -} - -#endif /* _GDISP_LLD_BOARD_H */ -/** @} */ - diff --git a/drivers/gdisp/ST7565/gdisp_lld_config.h b/drivers/gdisp/ST7565/gdisp_lld_config.h index 8d26a0aa..632dc431 100644 --- a/drivers/gdisp/ST7565/gdisp_lld_config.h +++ b/drivers/gdisp/ST7565/gdisp_lld_config.h @@ -14,13 +14,12 @@ /* Driver hardware support. */ /*===========================================================================*/ -#define GDISP_DRIVER_NAME "ST7565" +#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing +#define GDISP_HARDWARE_DRAWPIXEL TRUE +#define GDISP_HARDWARE_PIXELREAD TRUE +#define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_HARDWARE_CONTROL TRUE - -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_MONO - -#define GDISP_CONTROL_LLD_FLUSH (GDISP_CONTROL_LLD + 1) +#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_MONO #endif /* GFX_USE_GDISP */ From c353b6e9b01393c3c90632c97b4da0a315645b8e Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 23 Oct 2013 01:33:43 +1000 Subject: [PATCH 093/160] Remove superflous defines --- drivers/gdisp/SSD1306/SSD1306.h | 3 --- drivers/gdisp/ST7565/st7565.h | 3 --- 2 files changed, 6 deletions(-) diff --git a/drivers/gdisp/SSD1306/SSD1306.h b/drivers/gdisp/SSD1306/SSD1306.h index 38507d48..47ca39e4 100644 --- a/drivers/gdisp/SSD1306/SSD1306.h +++ b/drivers/gdisp/SSD1306/SSD1306.h @@ -8,9 +8,6 @@ #ifndef _SSD1306_H #define _SSD1306_H -#define SSD1306_BLACK 0 -#define SSD1306_WHITE 1 - #define SSD1306_SETCONTRAST 0x81 #define SSD1306_DISPLAYALLON_RESUME 0xA4 #define SSD1306_DISPLAYALLON 0xA5 diff --git a/drivers/gdisp/ST7565/st7565.h b/drivers/gdisp/ST7565/st7565.h index b1f43f6b..9542dd3f 100644 --- a/drivers/gdisp/ST7565/st7565.h +++ b/drivers/gdisp/ST7565/st7565.h @@ -8,9 +8,6 @@ #ifndef _ST7565_H #define _ST7565_H -#define ST7565_BLACK 0 -#define ST7565_WHITE 1 - #define ST7565_CONTRAST 0x81 #define ST7565_ALLON_NORMAL 0xA4 #define ST7565_ALLON 0xA5 From 5f17570ebcba8998757cdcb2df0a92a6215b7448 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 23 Oct 2013 01:34:56 +1000 Subject: [PATCH 094/160] Convert ED060SC4 to new driver format --- ...ard_example.h => board_ED060SC4_example.h} | 74 ++- .../gdisp/ED060SC4/board_ED060SC4_template.h | 202 ++++++ drivers/gdisp/ED060SC4/ed060sc4.h | 16 - drivers/gdisp/ED060SC4/gdisp_lld.c | 587 +++++++++--------- drivers/gdisp/ED060SC4/gdisp_lld.mk | 2 +- .../gdisp/ED060SC4/gdisp_lld_board_template.h | 83 --- drivers/gdisp/ED060SC4/gdisp_lld_config.h | 7 +- drivers/gdisp/ED060SC4/readme.txt | 3 +- 8 files changed, 554 insertions(+), 420 deletions(-) rename drivers/gdisp/ED060SC4/{gdisp_lld_board_example.h => board_ED060SC4_example.h} (61%) create mode 100644 drivers/gdisp/ED060SC4/board_ED060SC4_template.h delete mode 100644 drivers/gdisp/ED060SC4/ed060sc4.h delete mode 100644 drivers/gdisp/ED060SC4/gdisp_lld_board_template.h diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h b/drivers/gdisp/ED060SC4/board_ED060SC4_example.h similarity index 61% rename from drivers/gdisp/ED060SC4/gdisp_lld_board_example.h rename to drivers/gdisp/ED060SC4/board_ED060SC4_example.h index 98f05ee8..cb5a92b8 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld_board_example.h +++ b/drivers/gdisp/ED060SC4/board_ED060SC4_example.h @@ -43,84 +43,100 @@ #define GPIOC_VPOS_CTRL 14 #define GPIOC_VNEG_CTRL 15 +static inline void init_board(GDisplay *g) { -/* Set up IO pins for the panel connection. */ -static inline void init_board(void) { - /* Main SMPS power control, active low - * (open collector so that MOSFET gate can be pulled up to Vbat) */ - palWritePad(GPIOC, GPIOC_SMPS_CTRL, true); - palSetPadMode(GPIOC, GPIOC_SMPS_CTRL, PAL_MODE_OUTPUT_OPENDRAIN); - - /* Power control for the positive & negative side */ - palWritePad(GPIOC, GPIOC_VPOS_CTRL, false); - palSetPadMode(GPIOC, GPIOC_VPOS_CTRL, PAL_MODE_OUTPUT_PUSHPULL); - palWritePad(GPIOC, GPIOC_VNEG_CTRL, false); - palSetPadMode(GPIOC, GPIOC_VNEG_CTRL, PAL_MODE_OUTPUT_PUSHPULL); - - /* Main data bus */ - palWritePort(GPIOB, 0); - palSetGroupMode(GPIOB, 0xFFFF, 0, PAL_MODE_OUTPUT_PUSHPULL); + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + /* Main SMPS power control, active low + * (open collector so that MOSFET gate can be pulled up to Vbat) */ + palWritePad(GPIOC, GPIOC_SMPS_CTRL, true); + palSetPadMode(GPIOC, GPIOC_SMPS_CTRL, PAL_MODE_OUTPUT_OPENDRAIN); + + /* Power control for the positive & negative side */ + palWritePad(GPIOC, GPIOC_VPOS_CTRL, false); + palSetPadMode(GPIOC, GPIOC_VPOS_CTRL, PAL_MODE_OUTPUT_PUSHPULL); + palWritePad(GPIOC, GPIOC_VNEG_CTRL, false); + palSetPadMode(GPIOC, GPIOC_VNEG_CTRL, PAL_MODE_OUTPUT_PUSHPULL); + + /* Main data bus */ + palWritePort(GPIOB, 0); + palSetGroupMode(GPIOB, 0xFFFF, 0, PAL_MODE_OUTPUT_PUSHPULL); + break; + } } /* Delay for display waveforms. Should be an accurate microsecond delay. */ -static void eink_delay(int us) -{ +static void eink_delay(int us) { halPolledDelay(US2RTT(us)); } /* Turn the E-ink panel Vdd supply (+3.3V) on or off. */ -static inline void setpower_vdd(bool_t on) { +static inline void setpower_vdd(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOB, GPIOB_SMPS_CTRL, !on); palWritePad(GPIOA, GPIOA_EINK_VDD, on); } /* Turn the E-ink panel negative supplies (-15V, -20V) on or off. */ -static inline void setpower_vneg(bool_t on) { +static inline void setpower_vneg(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOA, GPIOA_VNEG_CTRL, on); } /* Turn the E-ink panel positive supplies (-15V, -20V) on or off. */ -static inline void setpower_vpos(bool_t on) { +static inline void setpower_vpos(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOA, GPIOA_VPOS_CTRL, on); } /* Set the state of the LE (source driver Latch Enable) pin. */ -static inline void setpin_le(bool_t on) { +static inline void setpin_le(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOB, GPIOB_EINK_LE, on); } /* Set the state of the OE (source driver Output Enable) pin. */ -static inline void setpin_oe(bool_t on) { +static inline void setpin_oe(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOB, GPIOB_EINK_OE, on); } /* Set the state of the CL (source driver Clock) pin. */ -static inline void setpin_cl(bool_t on) { +static inline void setpin_cl(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOB, GPIOB_EINK_CL, on); } /* Set the state of the SPH (source driver Start Pulse Horizontal) pin. */ -static inline void setpin_sph(bool_t on) { +static inline void setpin_sph(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOB, GPIOB_EINK_SPH, on); } /* Set the state of the D0-D7 (source driver Data) pins. */ -static inline void setpins_data(uint8_t value) { +static inline void setpins_data(GDisplay *g, uint8_t value) { + (void) g; palWriteGroup(GPIOB, 0xFF, GPIOB_EINK_D0, value); } /* Set the state of the CKV (gate driver Clock Vertical) pin. */ -static inline void setpin_ckv(bool_t on) { +static inline void setpin_ckv(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOB, GPIOB_EINK_CKV, on); } /* Set the state of the GMODE (gate driver Gate Mode) pin. */ -static inline void setpin_gmode(bool_t on) { +static inline void setpin_gmode(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOC, GPIOC_EINK_GMODE, on); } /* Set the state of the SPV (gate driver Start Pulse Vertical) pin. */ -static inline void setpin_spv(bool_t on) { +static inline void setpin_spv(GDisplay *g, bool_t on) { + (void) g; palWritePad(GPIOB, GPIOB_EINK_SPV, on); } diff --git a/drivers/gdisp/ED060SC4/board_ED060SC4_template.h b/drivers/gdisp/ED060SC4/board_ED060SC4_template.h new file mode 100644 index 00000000..6d71a986 --- /dev/null +++ b/drivers/gdisp/ED060SC4/board_ED060SC4_template.h @@ -0,0 +1,202 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ST7565/board_ST7565_template.h + * @brief GDISP Graphic Driver subsystem board interface for the ST7565 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief Optional parameters that can be put in this file. + * @note The values listed below are the defaults. + * + * @note #define GDISP_SCREEN_HEIGHT 600 + * @note #define GDISP_SCREEN_WIDTH 800 + * + * @note Number of pixels per byte
+ * #define EINK_PPB 4 + * + * @note Delay for generating clock pulses. + * Unit is approximate clock cycles of the CPU (0 to 15). + * This should be atleast 50 ns.
+ * #define EINK_CLOCKDELAY 0 + * + * @note Width of one framebuffer block. + * Must be divisible by EINK_PPB and evenly divide GDISP_SCREEN_WIDTH.
+ * #define EINK_BLOCKWIDTH 20 + * + * @note + * @note Height of one framebuffer block. + * Must evenly divide GDISP_SCREEN_WIDTH.
+ * #define EINK_BLOCKHEIGHT 20 + * + * @note Number of block buffers to use for framebuffer emulation.
+ * #define EINK_NUMBUFFERS 40 + * + * @note Do a "blinking" clear, i.e. clear to opposite polarity first. + * This reduces the image persistence.
+ * #define EINK_BLINKCLEAR TRUE + * + * @note Number of passes to use when clearing the display
+ * #define EINK_CLEARCOUNT 10 + * + * @note Number of passes to use when writing to the display
+ * #define EINK_WRITECOUNT 4 + */ + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * + * @note Set the g->board member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Delay for display waveforms. Should be an accurate microsecond delay. + * + * @param[in] us The number of microseconds + */ +static void eink_delay(int us) { + (void) us; +} + +/** + * @brief Turn the E-ink panel Vdd supply (+3.3V) on or off. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpower_vdd(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +/** + * @brief Turn the E-ink panel negative supplies (-15V, -20V) on or off. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpower_vneg(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +/** + * @brief Turn the E-ink panel positive supplies (-15V, -20V) on or off. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpower_vpos(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +/** + * @brief Set the state of the LE (source driver Latch Enable) pin. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpin_le(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +/** + * @brief Set the state of the OE (source driver Output Enable) pin. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpin_oe(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +/** + * @brief Set the state of the CL (source driver Clock) pin. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpin_cl(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +/** + * @brief Set the state of the SPH (source driver Start Pulse Horizontal) pin. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpin_sph(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +/** + * @brief Set the state of the D0-D7 (source driver Data) pins. + * + * @param[in] g The GDisplay structure + * @param[in] value The byte to write + */ +static inline void setpins_data(GDisplay *g, uint8_t value) { + (void) g; + (void) value; +} + +/** + * @brief Set the state of the CKV (gate driver Clock Vertical) pin. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpin_ckv(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +/** + * @brief Set the state of the GMODE (gate driver Gate Mode) pin. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpin_gmode(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +/** + * @brief Set the state of the SPV (gate driver Start Pulse Vertical) pin. + * + * @param[in] g The GDisplay structure + * @param[in] on On or off + */ +static inline void setpin_spv(GDisplay *g, bool_t on) { + (void) g; + (void) on; +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/ED060SC4/ed060sc4.h b/drivers/gdisp/ED060SC4/ed060sc4.h deleted file mode 100644 index 8a38f135..00000000 --- a/drivers/gdisp/ED060SC4/ed060sc4.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -#ifndef _ED060SC4_H_ -#define _ED060SC4_H_ - -#include "gfx.h" - -/* Control command for flushing all data to display. */ -#define GDISP_CONTROL_FLUSH (GDISP_CONTROL_LLD + 0) - -#endif diff --git a/drivers/gdisp/ED060SC4/gdisp_lld.c b/drivers/gdisp/ED060SC4/gdisp_lld.c index fcc03944..14e7f88a 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld.c +++ b/drivers/gdisp/ED060SC4/gdisp_lld.c @@ -5,30 +5,35 @@ * http://ugfx.org/license.html */ -/* Low-level E-ink panel driver routines for ED060SC4. */ +/** + * @file drivers/gdisp/ED060SC4/gdisp_lld.c + * @brief GDISP Graphics Driver for the E-ink panel ED060SC4. + */ #include "gfx.h" -#include "ed060sc4.h" #if GFX_USE_GDISP -#include "gdisp/lld/emulation.c" +#define GDISP_DRIVER_VMT GDISPVMT_ED060SC4 +#include "../drivers/gdisp/ED060SC4/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" -/* ================================= - * Default configuration - * ================================= */ +#include "board_ED060SC4.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ #ifndef GDISP_SCREEN_HEIGHT -# define GDISP_SCREEN_HEIGHT 600 + #define GDISP_SCREEN_HEIGHT 600 #endif - #ifndef GDISP_SCREEN_WIDTH -# define GDISP_SCREEN_WIDTH 800 + #define GDISP_SCREEN_WIDTH 800 #endif /* Number of pixels per byte */ #ifndef EINK_PPB -# define EINK_PPB 4 + #define EINK_PPB 4 #endif /* Delay for generating clock pulses. @@ -36,50 +41,50 @@ * This should be atleast 50 ns. */ #ifndef EINK_CLOCKDELAY -# define EINK_CLOCKDELAY 0 + #define EINK_CLOCKDELAY 0 #endif /* Width of one framebuffer block. * Must be divisible by EINK_PPB and evenly divide GDISP_SCREEN_WIDTH. */ #ifndef EINK_BLOCKWIDTH -# define EINK_BLOCKWIDTH 20 + #define EINK_BLOCKWIDTH 20 #endif /* Height of one framebuffer block. * Must evenly divide GDISP_SCREEN_WIDTH. */ #ifndef EINK_BLOCKHEIGHT -# define EINK_BLOCKHEIGHT 20 + #define EINK_BLOCKHEIGHT 20 #endif /* Number of block buffers to use for framebuffer emulation. */ #ifndef EINK_NUMBUFFERS -# define EINK_NUMBUFFERS 40 + #define EINK_NUMBUFFERS 40 #endif /* Do a "blinking" clear, i.e. clear to opposite polarity first. * This reduces the image persistence. */ #ifndef EINK_BLINKCLEAR -# define EINK_BLINKCLEAR TRUE + #define EINK_BLINKCLEAR TRUE #endif /* Number of passes to use when clearing the display */ #ifndef EINK_CLEARCOUNT -# define EINK_CLEARCOUNT 10 + #define EINK_CLEARCOUNT 10 #endif /* Number of passes to use when writing to the display */ #ifndef EINK_WRITECOUNT -# define EINK_WRITECOUNT 4 + #define EINK_WRITECOUNT 4 #endif -/* ==================================== - * Lower level driver functions - * ==================================== */ +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ -#include "gdisp_lld_board.h" +#define PRIV(g) ((drvPriv *)g->priv) /** Delay between signal changes, to give time for IO pins to change state. */ -static inline void clockdelay() +static inline void clockdelay(void) { #if EINK_CLOCKDELAY & 1 asm("nop"); @@ -107,21 +112,21 @@ static inline void clockdelay() } /** Fast vertical clock pulse for gate driver, used during initializations */ -static void vclock_quick() +static void vclock_quick(GDisplay *g) { - setpin_ckv(TRUE); + setpin_ckv(g, TRUE); eink_delay(1); - setpin_ckv(FALSE); + setpin_ckv(g, FALSE); eink_delay(4); } /** Horizontal clock pulse for clocking data into source driver */ -static void hclock() +static void hclock(GDisplay *g) { clockdelay(); - setpin_cl(TRUE); + setpin_cl(g, TRUE); clockdelay(); - setpin_cl(FALSE); + setpin_cl(g, FALSE); } /** Start a new vertical gate driver scan from top. @@ -129,156 +134,156 @@ static void hclock() * so you should always scan through the whole display before * starting a new scan. */ -static void vscan_start() +static void vscan_start(GDisplay *g) { - setpin_gmode(TRUE); - vclock_quick(); - setpin_spv(FALSE); - vclock_quick(); - setpin_spv(TRUE); - vclock_quick(); + setpin_gmode(g, TRUE); + vclock_quick(g); + setpin_spv(g, FALSE); + vclock_quick(g); + setpin_spv(g, TRUE); + vclock_quick(g); } /** Waveform for strobing a row of data onto the display. * Attempts to minimize the leaking of color to other rows by having * a long idle period after a medium-length strobe period. */ -static void vscan_write() +static void vscan_write(GDisplay *g) { - setpin_ckv(TRUE); - setpin_oe(TRUE); + setpin_ckv(g, TRUE); + setpin_oe(g, TRUE); eink_delay(5); - setpin_oe(FALSE); - setpin_ckv(FALSE); + setpin_oe(g, FALSE); + setpin_ckv(g, FALSE); eink_delay(200); } /** Waveform used when clearing the display. Strobes a row of data to the * screen, but does not mind some of it leaking to other rows. */ -static void vscan_bulkwrite() +static void vscan_bulkwrite(GDisplay *g) { - setpin_ckv(TRUE); + setpin_ckv(g, TRUE); eink_delay(20); - setpin_ckv(FALSE); + setpin_ckv(g, FALSE); eink_delay(200); } /** Waveform for skipping a vertical row without writing anything. * Attempts to minimize the amount of change in any row. */ -static void vscan_skip() +static void vscan_skip(GDisplay *g) { - setpin_ckv(TRUE); + setpin_ckv(g, TRUE); eink_delay(1); - setpin_ckv(FALSE); + setpin_ckv(g, FALSE); eink_delay(100); } /** Stop the vertical scan. The significance of this escapes me, but it seems * necessary or the next vertical scan may be corrupted. */ -static void vscan_stop() +static void vscan_stop(GDisplay *g) { - setpin_gmode(FALSE); - vclock_quick(); - vclock_quick(); - vclock_quick(); - vclock_quick(); - vclock_quick(); + setpin_gmode(g, FALSE); + vclock_quick(g); + vclock_quick(g); + vclock_quick(g); + vclock_quick(g); + vclock_quick(g); } /** Start updating the source driver data (from left to right). */ -static void hscan_start() +static void hscan_start(GDisplay *g) { /* Disable latching and output enable while we are modifying the row. */ - setpin_le(FALSE); - setpin_oe(FALSE); + setpin_le(g, FALSE); + setpin_oe(g, FALSE); /* The start pulse should remain low for the duration of the row. */ - setpin_sph(FALSE); + setpin_sph(g, FALSE); } /** Write data to the horizontal row. */ -static void hscan_write(const uint8_t *data, int count) +static void hscan_write(GDisplay *g, const uint8_t *data, int count) { while (count--) { /* Set the next byte on the data pins */ - setpins_data(*data++); + setpins_data(g, *data++); /* Give a clock pulse to the shift register */ - hclock(); + hclock(g); } } /** Finish and transfer the row to the source drivers. * Does not set the output enable, so the drivers are not yet active. */ -static void hscan_stop() +static void hscan_stop(GDisplay *g) { /* End the scan */ - setpin_sph(TRUE); - hclock(); + setpin_sph(g, TRUE); + hclock(g); /* Latch the new data */ - setpin_le(TRUE); + setpin_le(g, TRUE); clockdelay(); - setpin_le(FALSE); + setpin_le(g, FALSE); } /** Turn on the power to the E-Ink panel, observing proper power sequencing. */ -static void power_on() +static void power_on(GDisplay *g) { unsigned i; /* First the digital power supply and signal levels. */ - setpower_vdd(TRUE); - setpin_le(FALSE); - setpin_oe(FALSE); - setpin_cl(FALSE); - setpin_sph(TRUE); - setpins_data(0); - setpin_ckv(FALSE); - setpin_gmode(FALSE); - setpin_spv(TRUE); + setpower_vdd(g, TRUE); + setpin_le(g, FALSE); + setpin_oe(g, FALSE); + setpin_cl(g, FALSE); + setpin_sph(g, TRUE); + setpins_data(g, 0); + setpin_ckv(g, FALSE); + setpin_gmode(g, FALSE); + setpin_spv(g, TRUE); /* Min. 100 microsecond delay after digital supply */ gfxSleepMicroseconds(100); /* Then negative voltages and min. 1000 microsecond delay. */ - setpower_vneg(TRUE); + setpower_vneg(g, TRUE); gfxSleepMicroseconds(1000); /* Finally the positive voltages. */ - setpower_vpos(TRUE); + setpower_vpos(g, TRUE); /* Clear the vscan shift register */ - vscan_start(); + vscan_start(g); for (i = 0; i < GDISP_SCREEN_HEIGHT; i++) - vclock_quick(); - vscan_stop(); + vclock_quick(g); + vscan_stop(g); } /** Turn off the power, observing proper power sequencing. */ -static void power_off() +static void power_off(GDisplay *g) { /* First the high voltages */ - setpower_vpos(FALSE); - setpower_vneg(FALSE); + setpower_vpos(g, FALSE); + setpower_vneg(g, FALSE); /* Wait for any capacitors to drain */ gfxSleepMilliseconds(100); /* Then put all signals and digital supply to ground. */ - setpin_le(FALSE); - setpin_oe(FALSE); - setpin_cl(FALSE); - setpin_sph(FALSE); - setpins_data(0); - setpin_ckv(FALSE); - setpin_gmode(FALSE); - setpin_spv(FALSE); - setpower_vdd(FALSE); + setpin_le(g, FALSE); + setpin_oe(g, FALSE); + setpin_cl(g, FALSE); + setpin_sph(g, FALSE); + setpins_data(g, 0); + setpin_ckv(g, FALSE); + setpin_gmode(g, FALSE); + setpin_spv(g, FALSE); + setpower_vdd(g, FALSE); } /* ==================================== @@ -286,56 +291,58 @@ static void power_off() * ==================================== */ #if EINK_PPB == 4 -#define PIXELMASK 3 -#define PIXEL_WHITE 2 -#define PIXEL_BLACK 1 -#define BYTE_WHITE 0xAA -#define BYTE_BLACK 0x55 + #define PIXELMASK 3 + #define PIXEL_WHITE 2 + #define PIXEL_BLACK 1 + #define BYTE_WHITE 0xAA + #define BYTE_BLACK 0x55 #else -#error Unsupported EINK_PPB value. + #error Unsupported EINK_PPB value. #endif #if GDISP_SCREEN_HEIGHT % EINK_BLOCKHEIGHT != 0 -#error GDISP_SCREEN_HEIGHT must be evenly divisible by EINK_BLOCKHEIGHT + #error GDISP_SCREEN_HEIGHT must be evenly divisible by EINK_BLOCKHEIGHT #endif #if GDISP_SCREEN_WIDTH % EINK_BLOCKWIDTH != 0 -#error GDISP_SCREEN_WIDTH must be evenly divisible by EINK_BLOCKWIDTH + #error GDISP_SCREEN_WIDTH must be evenly divisible by EINK_BLOCKWIDTH #endif #if EINK_BLOCKWIDTH % EINK_PPB != 0 -#error EINK_BLOCKWIDTH must be evenly divisible by EINK_PPB + #error EINK_BLOCKWIDTH must be evenly divisible by EINK_PPB #endif #if EINK_NUMBUFFERS > 254 -#error EINK_NUMBUFFERS must be at most 254. + #error EINK_NUMBUFFERS must be at most 254. #endif -#define BLOCKS_Y (GDISP_SCREEN_HEIGHT / EINK_BLOCKHEIGHT) -#define BLOCKS_X (GDISP_SCREEN_WIDTH / EINK_BLOCKWIDTH) -#define WIDTH_BYTES (EINK_BLOCKWIDTH / EINK_PPB) +#define BLOCKS_Y (GDISP_SCREEN_HEIGHT / EINK_BLOCKHEIGHT) +#define BLOCKS_X (GDISP_SCREEN_WIDTH / EINK_BLOCKWIDTH) +#define WIDTH_BYTES (EINK_BLOCKWIDTH / EINK_PPB) /* Buffers that store the data for a small area of the display. */ typedef struct { uint8_t data[EINK_BLOCKHEIGHT][WIDTH_BYTES]; } block_t; -static uint8_t g_next_block; /* Index of the next free block buffer. */ -static block_t g_blocks[EINK_NUMBUFFERS]; +typedef struct drvPriv { + uint8_t g_next_block; /* Index of the next free block buffer. */ + block_t g_blocks[EINK_NUMBUFFERS]; -/* Map that stores the buffers associated to each area of the display. - * Value of 0 means that the block is not allocated. - * Other values are the index in g_blocks + 1. - */ -static uint8_t g_blockmap[BLOCKS_Y][BLOCKS_X]; + /* Map that stores the buffers associated to each area of the display. + * Value of 0 means that the block is not allocated. + * Other values are the index in g_blocks + 1. + */ + uint8_t g_blockmap[BLOCKS_Y][BLOCKS_X]; +} drvPriv; /** Check if the row contains any allocated blocks. */ -static bool_t blocks_on_row(unsigned by) +static bool_t blocks_on_row(GDisplay *g, unsigned by) { unsigned bx; for (bx = 0; bx < BLOCKS_X; bx++) { - if (g_blockmap[by][bx] != 0) + if (PRIV(g)->g_blockmap[by][bx] != 0) { return TRUE; } @@ -344,79 +351,47 @@ static bool_t blocks_on_row(unsigned by) } /** Write out a block row. */ -static void write_block_row(unsigned by) +static void write_block_row(GDisplay *g, unsigned by) { unsigned bx, dy, dx; for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) { - hscan_start(); + hscan_start(g); for (bx = 0; bx < BLOCKS_X; bx++) { - if (g_blockmap[by][bx] == 0) + if (PRIV(g)->g_blockmap[by][bx] == 0) { for (dx = 0; dx < WIDTH_BYTES; dx++) { const uint8_t dummy = 0; - hscan_write(&dummy, 1); + hscan_write(g, &dummy, 1); } } else { - block_t *block = &g_blocks[g_blockmap[by][bx] - 1]; - hscan_write(&block->data[dy][0], WIDTH_BYTES); + block_t *block = &PRIV(g)->g_blocks[PRIV(g)->g_blockmap[by][bx] - 1]; + hscan_write(g, &block->data[dy][0], WIDTH_BYTES); } } - hscan_stop(); + hscan_stop(g); - vscan_write(); + vscan_write(g); } } /** Clear the block map, i.e. deallocate all blocks */ -static void clear_block_map() +static void clear_block_map(GDisplay *g) { unsigned bx, by; for (by = 0; by < BLOCKS_Y; by++) { for (bx = 0; bx < BLOCKS_X; bx++) { - g_blockmap[by][bx] = 0; + PRIV(g)->g_blockmap[by][bx] = 0; } } - g_next_block = 0; -} - -/** Flush all the buffered rows to display. */ -static void flush_buffers() -{ - unsigned by, dy, i; - - for (i = 0; i < EINK_WRITECOUNT; i++) - { - vscan_start(); - - for (by = 0; by < BLOCKS_Y; by++) - { - if (!blocks_on_row(by)) - { - /* Skip the whole row of blocks. */ - for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) - { - vscan_skip(); - } - } - else - { - /* Write out the blocks. */ - write_block_row(by); - } - } - - vscan_stop(); - } - - clear_block_map(); + PRIV(g)->g_next_block = 0; } /** Initialize a newly allocated block. */ @@ -434,173 +409,217 @@ static void zero_block(block_t *block) /** Allocate a buffer * Automatically flushes if all buffers are full. */ -static block_t *alloc_buffer(unsigned bx, unsigned by) +static block_t *alloc_buffer(GDisplay *g, unsigned bx, unsigned by) { block_t *result; - if (g_blockmap[by][bx] == 0) + drvPriv *priv; + + priv = PRIV(g); + if (priv->g_blockmap[by][bx] == 0) { - if (g_next_block >= EINK_NUMBUFFERS) - { - flush_buffers(); - } + if (priv->g_next_block >= EINK_NUMBUFFERS) + gdisp_lld_flush(g); - result = &g_blocks[g_next_block]; - g_blockmap[by][bx] = g_next_block + 1; - g_next_block++; + result = &priv->g_blocks[priv->g_next_block]; + priv->g_blockmap[by][bx] = priv->g_next_block + 1; + priv->g_next_block++; zero_block(result); return result; } else { - result = &g_blocks[g_blockmap[by][bx] - 1]; + result = &priv->g_blocks[priv->g_blockmap[by][bx] - 1]; return result; } } -/* =============================== - * Public functions - * =============================== */ +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ -bool_t gdisp_lld_init(void) -{ - init_board(); +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + g->priv = gfxAlloc(sizeof(drvPriv)); + + init_board(g); /* Make sure that all the pins are in "off" state. * Having any pin high could cause voltage leaking to the * display, which in turn causes the image to leak slowly away. */ - power_off(); + power_off(g); - clear_block_map(); - - /* Initialize the global GDISP structure */ - GDISP.Width = GDISP_SCREEN_WIDTH; - GDISP.Height = GDISP_SCREEN_HEIGHT; - GDISP.Orientation = GDISP_ROTATE_0; - GDISP.Powermode = powerOff; - GDISP.Backlight = 0; - GDISP.Contrast = 0; - #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP - GDISP.clipx0 = 0; - GDISP.clipy0 = 0; - GDISP.clipx1 = GDISP.Width; - GDISP.clipy1 = GDISP.Height; - #endif + clear_block_map(g); + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = 100; + g->g.Contrast = 100; return TRUE; } -void gdisp_lld_draw_pixel(coord_t x, coord_t y, color_t color) -{ - block_t *block; - uint8_t byte; - unsigned bx, by, dx, dy; - uint8_t bitpos; - - bx = x / EINK_BLOCKWIDTH; - by = y / EINK_BLOCKHEIGHT; - dx = x % EINK_BLOCKWIDTH; - dy = y % EINK_BLOCKHEIGHT; - - if (bx < 0 || bx >= BLOCKS_X || by < 0 || by >= BLOCKS_Y) - return; - - block = alloc_buffer(bx, by); - - bitpos = (6 - 2 * (dx % EINK_PPB)); - byte = block->data[dy][dx / EINK_PPB]; - byte &= ~(PIXELMASK << bitpos); - if (color) - { - byte |= PIXEL_WHITE << bitpos; - } - else - { - byte |= PIXEL_BLACK << bitpos; - } - block->data[dy][dx / EINK_PPB] = byte; -} +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay *g) { + unsigned by, dy, i; -#if !GDISP_NEED_CONTROL -#error You must enable GDISP_NEED_CONTROL for the E-Ink driver. + for (i = 0; i < EINK_WRITECOUNT; i++) { + vscan_start(g); + + for (by = 0; by < BLOCKS_Y; by++) { + if (!blocks_on_row(g, by)) { + /* Skip the whole row of blocks. */ + for (dy = 0; dy < EINK_BLOCKHEIGHT; dy++) + vscan_skip(g); + } else { + /* Write out the blocks. */ + write_block_row(g, by); + } + } + + vscan_stop(g); + } + + clear_block_map(g); + } #endif -void gdisp_lld_control(unsigned what, void *value) { - gdisp_powermode_t newmode; - - switch(what) - { - case GDISP_CONTROL_POWER: - newmode = (gdisp_powermode_t)value; - - if (GDISP.Powermode == newmode) - return; - - if (newmode == powerOn) - { - power_on(); - } - else - { - flush_buffers(); - power_off(); - } - GDISP.Powermode = newmode; +#if GDISP_HARDWARE_DRAWPIXEL + void gdisp_lld_draw_pixel(GDisplay *g) { + block_t *block; + uint8_t byte; + unsigned bx, by, dx, dy; + uint8_t bitpos; + + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + bx = g->p.x / EINK_BLOCKWIDTH; + dx = g->p.x % EINK_BLOCKWIDTH; + by = g->p.y / EINK_BLOCKHEIGHT; + dy = g->p.y % EINK_BLOCKHEIGHT; break; - - case GDISP_CONTROL_FLUSH: - flush_buffers(); + case GDISP_ROTATE_90: + bx = g->p.y / EINK_BLOCKWIDTH; + dx = g->p.y % EINK_BLOCKWIDTH; + by = (GDISP_SCREEN_HEIGHT-1 - g->p.x) / EINK_BLOCKHEIGHT; + dy = (GDISP_SCREEN_HEIGHT-1 - g->p.x) % EINK_BLOCKHEIGHT; break; + case GDISP_ROTATE_180: + bx = (GDISP_SCREEN_WIDTH-1 - g->p.x) / EINK_BLOCKWIDTH; + dx = (GDISP_SCREEN_WIDTH-1 - g->p.x) % EINK_BLOCKWIDTH; + by = (GDISP_SCREEN_HEIGHT-1 - g->p.y) / EINK_BLOCKHEIGHT; + dy = (GDISP_SCREEN_HEIGHT-1 - g->p.y) % EINK_BLOCKHEIGHT; + break; + case GDISP_ROTATE_270: + bx = (GDISP_SCREEN_WIDTH-1 - g->p.y) / EINK_BLOCKWIDTH; + dx = (GDISP_SCREEN_WIDTH-1 - g->p.y) % EINK_BLOCKWIDTH; + by = g->p.x / EINK_BLOCKHEIGHT; + dy = g->p.x % EINK_BLOCKHEIGHT; + break; + } + + block = alloc_buffer(g, bx, by); + + bitpos = (6 - 2 * (dx % EINK_PPB)); + byte = block->data[dy][dx / EINK_PPB]; + byte &= ~(PIXELMASK << bitpos); + if (g->p.color != Black) + byte |= PIXEL_WHITE << bitpos; + else + byte |= PIXEL_BLACK << bitpos; + block->data[dy][dx / EINK_PPB] = byte; } -} +#endif + +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + case powerSleep: + case powerDeepSleep: + gdisp_lld_flush(g); + power_off(g); + break; + case powerOn: + power_on(g); + break; + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + default: + return; + } + } +#endif /* =============================== * Accelerated routines * =============================== */ #if GDISP_HARDWARE_CLEARS + static void subclear(GDisplay *g, color_t color) { + unsigned x, y; + uint8_t byte; -static void subclear(color_t color) -{ - unsigned x, y; - uint8_t byte; - - hscan_start(); - byte = color ? BYTE_WHITE : BYTE_BLACK; - for (x = 0; x < GDISP_SCREEN_WIDTH; x++) - { - hscan_write(&byte, 1); - } - hscan_stop(); - - setpin_oe(TRUE); - vscan_start(); - for (y = 0; y < GDISP_SCREEN_HEIGHT; y++) - { - vscan_bulkwrite(); - } - vscan_stop(); - setpin_oe(FALSE); -} + hscan_start(g); + byte = color ? BYTE_WHITE : BYTE_BLACK; + for (x = 0; x < GDISP_SCREEN_WIDTH; x++) + { + hscan_write(g, &byte, 1); + } + hscan_stop(g); -void gdisp_lld_clear(color_t color) -{ - unsigned i; - clear_block_map(); - - if (EINK_BLINKCLEAR) - { - subclear(!color); - gfxSleepMilliseconds(50); + setpin_oe(g, TRUE); + vscan_start(g); + for (y = 0; y < GDISP_SCREEN_HEIGHT; y++) + vscan_bulkwrite(g); + vscan_stop(g); + setpin_oe(g, FALSE); } - for (i = 0; i < EINK_CLEARCOUNT; i++) - { - subclear(color); - gfxSleepMilliseconds(10); + void gdisp_lld_clear(GDisplay *g) { + unsigned i; + + clear_block_map(g); + + if (EINK_BLINKCLEAR) { + subclear(g, !g->p.color); + gfxSleepMilliseconds(50); + } + + for (i = 0; i < EINK_CLEARCOUNT; i++) { + subclear(g, g->p.color); + gfxSleepMilliseconds(10); + } } - -} #endif -#endif +#endif // GFX_USE_GDISP diff --git a/drivers/gdisp/ED060SC4/gdisp_lld.mk b/drivers/gdisp/ED060SC4/gdisp_lld.mk index d5c1492f..fc62da03 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld.mk +++ b/drivers/gdisp/ED060SC4/gdisp_lld.mk @@ -1,2 +1,2 @@ -GFXSRC += $(GFXLIB)/drivers/gdisp/ED060SC4/gdisp_lld.c GFXINC += $(GFXLIB)/drivers/gdisp/ED060SC4 +GFXSRC += $(GFXLIB)/drivers/gdisp/ED060SC4/gdisp_lld.c diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h b/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h deleted file mode 100644 index 68129bf8..00000000 --- a/drivers/gdisp/ED060SC4/gdisp_lld_board_template.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/* Board interface definitions for ED060SC4 PrimeView E-ink panel. - * - * You should implement the following functions to define the interface to - * the panel on your board. - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -/* Set up IO pins for the panel connection. */ -static inline void init_board(void) { - #error Unimplemented -} - -/* Delay for display waveforms. Should be an accurate microsecond delay. */ -static void eink_delay(int us) -{ - #error Unimplemented -} - -/* Turn the E-ink panel Vdd supply (+3.3V) on or off. */ -static inline void setpower_vdd(bool_t on) { - #error Unimplemented -} - -/* Turn the E-ink panel negative supplies (-15V, -20V) on or off. */ -static inline void setpower_vneg(bool_t on) { - #error Unimplemented -} - -/* Turn the E-ink panel positive supplies (-15V, -20V) on or off. */ -static inline void setpower_vpos(bool_t on) { - #error Unimplemented -} - -/* Set the state of the LE (source driver Latch Enable) pin. */ -static inline void setpin_le(bool_t on) { - #error Unimplemented -} - -/* Set the state of the OE (source driver Output Enable) pin. */ -static inline void setpin_oe(bool_t on) { - #error Unimplemented -} - -/* Set the state of the CL (source driver Clock) pin. */ -static inline void setpin_cl(bool_t on) { - #error Unimplemented -} - -/* Set the state of the SPH (source driver Start Pulse Horizontal) pin. */ -static inline void setpin_sph(bool_t on) { - #error Unimplemented -} - -/* Set the state of the D0-D7 (source driver Data) pins. */ -static inline void setpins_data(uint8_t value) { - #error Unimplemented -} - -/* Set the state of the CKV (gate driver Clock Vertical) pin. */ -static inline void setpin_ckv(bool_t on) { - #error Unimplemented -} - -/* Set the state of the GMODE (gate driver Gate Mode) pin. */ -static inline void setpin_gmode(bool_t on) { - #error Unimplemented -} - -/* Set the state of the SPV (gate driver Start Pulse Vertical) pin. */ -static inline void setpin_spv(bool_t on) { - #error Unimplemented -} - -#endif diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_config.h b/drivers/gdisp/ED060SC4/gdisp_lld_config.h index befd997c..d7e836c9 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld_config.h +++ b/drivers/gdisp/ED060SC4/gdisp_lld_config.h @@ -12,12 +12,9 @@ #if GFX_USE_GDISP -#define GDISP_DRIVER_NAME "ED060SC4" +#define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing +#define GDISP_HARDWARE_DRAWPIXEL TRUE #define GDISP_HARDWARE_CLEARS TRUE -#define GDISP_HARDWARE_FILLS FALSE -#define GDISP_HARDWARE_BITFILLS FALSE -#define GDISP_HARDWARE_SCROLL FALSE -#define GDISP_HARDWARE_PIXELREAD FALSE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_MONO diff --git a/drivers/gdisp/ED060SC4/readme.txt b/drivers/gdisp/ED060SC4/readme.txt index 5409d810..852a0010 100644 --- a/drivers/gdisp/ED060SC4/readme.txt +++ b/drivers/gdisp/ED060SC4/readme.txt @@ -38,8 +38,7 @@ result in faster drawing, but also use more RAM on the processor: After drawing your images, you should flush the buffers using the following command: - #include - gdispControl(GDISP_CONTROL_FLUSH, 0); + gdispFlush(); The buffers are also flushed whenever you turn the display off using: From 6cc80926f00ce8d6533298cbb5ea061c1446287b Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Wed, 23 Oct 2013 00:18:03 +0200 Subject: [PATCH 095/160] Added gwinListGetSelectedText() --- include/gwin/list.h | 13 +++++++++++++ src/gwin/list.c | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/gwin/list.h b/include/gwin/list.h index fc189658..05433e87 100644 --- a/include/gwin/list.h +++ b/include/gwin/list.h @@ -205,6 +205,19 @@ bool_t gwinListItemIsSelected(GHandle gh, int item); */ int gwinListGetSelected(GHandle gh); +/** + * @brief Get the text of the selected item + * + * @param[in] gh The widget handle (must be a list handle) + * + * @return The test of the selected list item for a single-select list. + * + * @note It always returns NULL (nothing selected) for a multi-select list. + * + * @api + */ +const char* gwinListGetSelectedText(GHandle gh); + #if GWIN_NEED_LIST_IMAGES || defined(__DOXYGEN__) /** * @brief Set the image for a list item diff --git a/src/gwin/list.c b/src/gwin/list.c index 5407cb36..cf0bebc4 100644 --- a/src/gwin/list.c +++ b/src/gwin/list.c @@ -536,6 +536,18 @@ int gwinListItemCount(GHandle gh) { return gh2obj->cnt; } +const char* gwinListGetSelectedText(GHandle gh) { + // is it a valid handle? + if (gh->vmt != (gwinVMT *)&listVMT) + return 0; + + // return NULL if nothing is selected (or multi-select) + if (gwinListGetSelected(gh) < 0) + return 0; + + return gwinListItemGetText(gh, gwinListGetSelected(gh)); +} + #if GWIN_NEED_LIST_IMAGES void gwinListItemSetImage(GHandle gh, int item, gdispImage *pimg) { const gfxQueueASyncItem * qi; From 8fce1a6fcef51f171d5fd9ed381583507b361210 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Wed, 23 Oct 2013 16:26:34 +0200 Subject: [PATCH 096/160] Added gwinListSetScroll --- include/gwin/list.h | 19 +++++++++++++++++++ releases.txt | 15 +++++++++++---- src/gwin/list.c | 20 +++++++++++++++++++- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/include/gwin/list.h b/include/gwin/list.h index 05433e87..cba5b137 100644 --- a/include/gwin/list.h +++ b/include/gwin/list.h @@ -56,6 +56,13 @@ typedef struct GListObject { gfxQueueASync list_head; // The list of items } GListObject; +/** + * @brief Enum to change the behaviour of the scroll area + * + * @note This might be used with @p gwinListSetScroll() + */ +typedef enum scroll_t { scrollAlways, scrollAuto } scroll_t; + #ifdef __cplusplus extern "C" { #endif @@ -85,6 +92,18 @@ extern "C" { */ GHandle gwinListCreate(GListObject *widget, GWidgetInit *pInit, bool_t multiselect); +/** + * @brief Change the behaviour of the scroll area + * + * @note Current possible values: @p scrollAlways and @p scrollAuto + * + * @param[in] gh The widget handle (must be a list handle) + * @param[in] flag The behaviour to be set + * + * @api + */ +void gwinListSetScroll(GHandle gh, scroll_t flag); + /** * @brief Add an item to the list * diff --git a/releases.txt b/releases.txt index f03e31f4..1b10d295 100644 --- a/releases.txt +++ b/releases.txt @@ -2,7 +2,15 @@ *** Releases *** ***************************************************************************** -current release: 1.8 +current release: 2.0 + +*** changes after 1.9 *** +FEATURE: GDISP Streaming +FEATURE: New driver interface for GDISP +FEATURE: Multiple display support +FEATURE: Multiple controller support +FEATURE: Add gdispFlush() for those controllers that need it +FEATURE: Add GDISP_NEED_AUTOFLUSH to automatically flush when required. *** changes after 1.8 *** FEATURE: GWIN list boxes. @@ -13,9 +21,8 @@ FEATURE: SSD1306 driver by user goeck FEATURE: ST7565 driver by user sam0737 FEATURE: ED060SC4 driver by user jpa- FIX: SSD1289 area filling bug fix by user samofab -FEATURE: GDISP Streaming -FEATURE: New driver interface for GDISP -FEATURE: Multiple display support +FEATURE: Added gwinListGetSelectedText() +FEATURE: Added gwinListSetScroll() *** changes after 1.7 *** FEATURE: Rename of the project from ChibiOS/GFX to uGFX diff --git a/src/gwin/list.c b/src/gwin/list.c index cf0bebc4..fe903c16 100644 --- a/src/gwin/list.c +++ b/src/gwin/list.c @@ -37,6 +37,7 @@ // Flags for the GListObject #define GLIST_FLG_MULTISELECT (GWIN_FIRST_CONTROL_FLAG << 0) #define GLIST_FLG_HASIMAGES (GWIN_FIRST_CONTROL_FLAG << 1) +#define GLIST_FLG_SCROLLALWAYS (GWIN_FIRST_CONTROL_FLAG << 2) // Flags on a ListItem. #define GLIST_FLG_SELECTED 0x0001 @@ -93,7 +94,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { x = 1; // the scroll area - if (gw2obj->cnt > (gw->g.height-2) / iheight) { + if (gw2obj->cnt > (gw->g.height-2) / iheight || gw->g.flags & GLIST_FLG_SCROLLALWAYS) { iwidth = gw->g.width - (SCROLLWIDTH+3); gdispFillArea(gw->g.x+iwidth+2, gw->g.y+1, SCROLLWIDTH, gw->g.height-2, gdispBlendColor(ps->fill, gw->pstyle->background, 128)); gdispDrawLine(gw->g.x+iwidth+1, gw->g.y+1, gw->g.x+iwidth+1, gw->g.y+gw->g.height-2, ps->edge); @@ -327,12 +328,29 @@ GHandle gwinListCreate(GListObject* gobj, GWidgetInit* pInit, bool_t multiselect gobj->top = 0; if (multiselect) gobj->w.g.flags |= GLIST_FLG_MULTISELECT; + gobj->w.g.flags |= GLIST_FLG_SCROLLALWAYS; gwinSetVisible(&gobj->w.g, pInit->g.show); return (GHandle)gobj; } +void gwinListSetScroll(GHandle gh, scroll_t flag) { + // is it a valid handle? + if (gh->vmt != (gwinVMT *)&listVMT) + return 0; + + switch (flag) { + case scrollAlways: + ((GListObject*)gh)->w.g.flags |= GLIST_FLG_SCROLLALWAYS; + break; + + case scrollAuto: + ((GListObject*)gh)->w.g.flags &=~ GLIST_FLG_SCROLLALWAYS; + break; + } +} + int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) { ListItem *newItem; From 03a863f2924d4c89b91b5379f020aaa3f419b7e5 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Wed, 23 Oct 2013 16:28:45 +0200 Subject: [PATCH 097/160] docs --- include/gwin/list.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gwin/list.h b/include/gwin/list.h index cba5b137..b45e7767 100644 --- a/include/gwin/list.h +++ b/include/gwin/list.h @@ -57,7 +57,7 @@ typedef struct GListObject { } GListObject; /** - * @brief Enum to change the behaviour of the scroll area + * @brief Enum to change the behaviour of the scroll bar * * @note This might be used with @p gwinListSetScroll() */ @@ -93,7 +93,7 @@ extern "C" { GHandle gwinListCreate(GListObject *widget, GWidgetInit *pInit, bool_t multiselect); /** - * @brief Change the behaviour of the scroll area + * @brief Change the behaviour of the scroll bar * * @note Current possible values: @p scrollAlways and @p scrollAuto * From d41109a6c7e11002b00d4b8c4d65ce3ee1f9d254 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 24 Oct 2013 02:41:58 +0200 Subject: [PATCH 098/160] fixed small bug --- src/gwin/list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gwin/list.c b/src/gwin/list.c index fe903c16..0e93555d 100644 --- a/src/gwin/list.c +++ b/src/gwin/list.c @@ -94,7 +94,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { x = 1; // the scroll area - if (gw2obj->cnt > (gw->g.height-2) / iheight || gw->g.flags & GLIST_FLG_SCROLLALWAYS) { + if ((gw2obj->cnt > (gw->g.height-2) / iheight) || (gw->g.flags & GLIST_FLG_SCROLLALWAYS)) { iwidth = gw->g.width - (SCROLLWIDTH+3); gdispFillArea(gw->g.x+iwidth+2, gw->g.y+1, SCROLLWIDTH, gw->g.height-2, gdispBlendColor(ps->fill, gw->pstyle->background, 128)); gdispDrawLine(gw->g.x+iwidth+1, gw->g.y+1, gw->g.x+iwidth+1, gw->g.y+gw->g.height-2, ps->edge); From 248335c513fe92d1629f2c34c5777ef9b628d09e Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 24 Oct 2013 04:13:07 +0200 Subject: [PATCH 099/160] Added gwinLabelSetBorder() --- include/gwin/label.h | 14 ++++++++++++-- releases.txt | 1 + src/gwin/label.c | 35 ++++++++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/include/gwin/label.h b/include/gwin/label.h index c11b5c72..3156ca71 100644 --- a/include/gwin/label.h +++ b/include/gwin/label.h @@ -39,8 +39,8 @@ extern "C" { #endif /** - * @brief Create a label widget. - * @details A label widget is a simple window which has a static text. + * @brief Create a label widget. + * @details A label widget is a simple window which has a static text. * * @param[in] widget The label structure to initialise. If this is NULL, the structure is dynamically allocated. * @param[in] pInit The initialisation parameters to use. @@ -51,6 +51,16 @@ extern "C" { */ GHandle gwinLabelCreate(GLabelObject *widget, GWidgetInit *pInit); +/** + * @brief Border settings for the default rendering routine + * + * @param[in] gh The widget handle (must be a list handle) + * @param[in] border Shall a border be rendered? + * + * @api + */ +void gwinLabelSetBorder(GHandle gh, bool_t border); + #ifdef __cplusplus } #endif diff --git a/releases.txt b/releases.txt index 1b10d295..ad00e8d1 100644 --- a/releases.txt +++ b/releases.txt @@ -23,6 +23,7 @@ FEATURE: ED060SC4 driver by user jpa- FIX: SSD1289 area filling bug fix by user samofab FEATURE: Added gwinListGetSelectedText() FEATURE: Added gwinListSetScroll() +FEATURE: Added gwinLabelSetBorder() *** changes after 1.7 *** FEATURE: Rename of the project from ChibiOS/GFX to uGFX diff --git a/src/gwin/label.c b/src/gwin/label.c index a933b3ac..750cb4fb 100644 --- a/src/gwin/label.c +++ b/src/gwin/label.c @@ -21,16 +21,22 @@ #include "gwin/class_gwin.h" -#define GLABEL_FLG_WAUTO (GWIN_FIRST_CONTROL_FLAG<<0) -#define GLABEL_FLG_HAUTO (GWIN_FIRST_CONTROL_FLAG<<1) +// macros to assist in data type conversions +#define gh2obj ((GLabelObject *)gh) -// Simple: single line with no wrapping +// flags for the GLabelObject +#define GLABEL_FLG_WAUTO (GWIN_FIRST_CONTROL_FLAG << 0) +#define GLABEL_FLG_HAUTO (GWIN_FIRST_CONTROL_FLAG << 1) +#define GLABEL_FLG_BORDER (GWIN_FIRST_CONTROL_FLAG << 2) + +// simple: single line with no wrapping static coord_t getwidth(const char *text, font_t font, coord_t maxwidth) { (void) maxwidth; + return gdispGetStringWidth(text, font)+2; // Allow one pixel of padding on each side } -// Simple: single line with no wrapping +// simple: single line with no wrapping static coord_t getheight(const char *text, font_t font, coord_t maxwidth) { (void) text; (void) maxwidth; @@ -47,12 +53,18 @@ static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) { if (gw->g.width != w || gw->g.height != h) { gwinResize(&gw->g, w, h); + return; } + // render the text gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text, gw->pstyle->background, justifyLeft); + + // render the border (if any) + if (gw->g.flags & GLABEL_FLG_BORDER) + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text); } static const gwidgetVMT labelVMT = { @@ -109,12 +121,25 @@ GHandle gwinLabelCreate(GLabelObject *widget, GWidgetInit *pInit) { if (!(widget = (GLabelObject *)_gwidgetCreate(&widget->w, pInit, &labelVMT))) return 0; - widget->w.g.flags |= flags; + // no borders by default + widget->w.g.flags &=~ GLABEL_FLG_BORDER; gwinSetVisible(&widget->w.g, pInit->g.show); + return (GHandle)widget; } +void gwinLabelSetBorder(GHandle gh, bool_t border) { + // is it a valid handle? + if (gh->vmt != (gwinVMT *)&labelVMT) + return; + + if (border) + gh2obj->w.g.flags |= GLABEL_FLG_BORDER; + else + gh2obj->w.g.flags &=~ GLABEL_FLG_BORDER; +} + #endif // GFX_USE_GWIN && GFX_NEED_LABEL /** @} */ From 825bbf26a1bf11d7148a16229f6515fae5efb276 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 24 Oct 2013 04:31:31 +0200 Subject: [PATCH 100/160] fixed label bugs --- src/gwin/label.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gwin/label.c b/src/gwin/label.c index 750cb4fb..65afff7e 100644 --- a/src/gwin/label.c +++ b/src/gwin/label.c @@ -64,7 +64,7 @@ static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) { // render the border (if any) if (gw->g.flags & GLABEL_FLG_BORDER) - gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text); + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); } static const gwidgetVMT labelVMT = { @@ -122,8 +122,9 @@ GHandle gwinLabelCreate(GLabelObject *widget, GWidgetInit *pInit) { return 0; // no borders by default - widget->w.g.flags &=~ GLABEL_FLG_BORDER; + flags &=~ GLABEL_FLG_BORDER; + widget->w.g.flags |= flags; gwinSetVisible(&widget->w.g, pInit->g.show); return (GHandle)widget; From 8c1a37b59eef97c1e713a4ae24459f3af82b65f2 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 11:30:17 +1000 Subject: [PATCH 101/160] Add functions to the Win32 GDISP driver to enable full testing of the streaming driver interface. --- drivers/multiple/Win32/gdisp_lld.c | 260 +++++++++++++++++++--- drivers/multiple/Win32/gdisp_lld_config.h | 22 +- 2 files changed, 250 insertions(+), 32 deletions(-) diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 3ce50633..876168c3 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -17,38 +17,15 @@ #include "../drivers/multiple/Win32/gdisp_lld_config.h" #include "gdisp/lld/gdisp_lld.h" -#include -#include -#include -#include -#include -#include - #ifndef GDISP_SCREEN_WIDTH #define GDISP_SCREEN_WIDTH 640 #endif #ifndef GDISP_SCREEN_HEIGHT #define GDISP_SCREEN_HEIGHT 480 #endif - -#define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0) -#define GDISP_FLG_HASTOGGLE (GDISP_FLG_DRIVER<<1) -#define GDISP_FLG_HASMOUSE (GDISP_FLG_DRIVER<<2) - -#if GINPUT_NEED_TOGGLE - /* Include toggle support code */ - #include "ginput/lld/toggle.h" -#endif - #if GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 #error "GDISP Win32: This driver currently only supports the RGB888 pixel format." #endif - -#if GINPUT_NEED_MOUSE - /* Include mouse support code */ - #include "ginput/lld/mouse.h" -#endif - // Setting this to TRUE delays updating the screen // to the windows paint routine. Due to the // drawing lock this does not add as much speed @@ -57,18 +34,46 @@ // even draw_pixel(). // This is probably due to drawing operations being // combined as the update regions are merged. +// The only time you might want to turn this off is +// if you are debugging drawing and want to see each +// pixel as it is set. #define GDISP_WIN32_USE_INDIRECT_UPDATE TRUE +//#define GDISP_WIN32_USE_INDIRECT_UPDATE FALSE -// How far extra windows should be offset from the first. +// How far extra windows (multiple displays) should be offset from the first. #define DISPLAY_X_OFFSET 50 #define DISPLAY_Y_OFFSET 50 +#include +#include +#include +#include +#include +#include + +#define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0) +#define GDISP_FLG_HASTOGGLE (GDISP_FLG_DRIVER<<1) +#define GDISP_FLG_HASMOUSE (GDISP_FLG_DRIVER<<2) +#if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ + #define GDISP_FLG_WSTREAM (GDISP_FLG_DRIVER<<3) + #define GDISP_FLG_WRAPPED (GDISP_FLG_DRIVER<<4) +#endif + +#if GINPUT_NEED_TOGGLE + /* Include toggle support code */ + #include "ginput/lld/toggle.h" +#endif + +#if GINPUT_NEED_MOUSE + /* Include mouse support code */ + #include "ginput/lld/mouse.h" +#endif + static DWORD winThreadId; static ATOM winClass; static volatile bool_t QReady; static HANDLE drawMutex; - /*===========================================================================*/ /* Driver local routines . */ /*===========================================================================*/ @@ -96,6 +101,10 @@ typedef struct winPriv { #if GINPUT_NEED_TOGGLE uint8_t toggles; #endif + #if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ + coord_t x0, y0, x1, y1; + coord_t x, y; + #endif } winPriv; @@ -441,6 +450,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { assert(priv != NULL); memset(priv, 0, sizeof(winPriv)); g->priv = priv; + #if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ + // Initialise with an invalid window + g->flags &= ~GDISP_FLG_WSTREAM; + #endif g->board = 0; // no board interface for this controller // Create the window in the message thread @@ -467,6 +480,199 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { } #endif +#if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ + void BAD_PARAMETER(const char *msg) { + volatile int a; + // This is really just a point for us to set the debugger + a = 0; + } +#endif + +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + winPriv * priv; + + if (g->flags & GDISP_FLG_WSTREAM) + BAD_PARAMETER("write_start: already in streaming mode"); + if (g->p.cx <= 0 || g->p.cy <= 0 || g->p.x < 0 || g->p.y < 0 || g->p.x+g->p.cx > g->g.Width || g->p.y+g->p.cy > g->g.Height) + BAD_PARAMETER("write_start: bad window parameter"); + + priv = g->priv; + priv->x0 = g->p.x; priv->x1 = g->p.x + g->p.cx - 1; + priv->y0 = g->p.y; priv->y1 = g->p.y + g->p.cy - 1; + #if GDISP_HARDWARE_STREAM_POS + priv->x = g->p.x-1; // Make sure these values are invalid (for testing) + priv->y = g->p.y-1; + #else + priv->x = g->p.x; + priv->y = g->p.y; + #endif + g->flags |= GDISP_FLG_WSTREAM; + g->flags &= ~GDISP_FLG_WRAPPED; + } + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + winPriv * priv; + int x, y; + COLORREF color; + + priv = g->priv; + color = COLOR2BGR(g->p.color); + + if (!(g->flags & GDISP_FLG_WSTREAM)) + BAD_PARAMETER("write_color: not in streaming mode"); + if (priv->x < priv->x0 || priv->x > priv->x1 || priv->y < priv->y0 || priv->y > priv->y1) + BAD_PARAMETER("write_color: cursor outside streaming area"); + if (g->flags & GDISP_FLG_WRAPPED) { + BAD_PARAMETER("write_color: Warning - Area wrapped."); + g->flags &= ~GDISP_FLG_WRAPPED; + } + + #if GDISP_NEED_CONTROL + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + x = priv->x; + y = priv->y; + break; + case GDISP_ROTATE_90: + x = priv->y; + y = g->g.Width - 1 - priv->x; + break; + case GDISP_ROTATE_180: + x = g->g.Width - 1 - priv->x; + y = g->g.Height - 1 - priv->y; + break; + case GDISP_ROTATE_270: + x = g->g.Height - 1 - priv->y; + y = priv->x; + break; + } + #else + x = priv->x; + y = priv->y; + #endif + + // Draw the pixel on the screen and in the buffer. + WaitForSingleObject(drawMutex, INFINITE); + SetPixel(priv->dcBuffer, x, y, color); + #if GDISP_WIN32_USE_INDIRECT_UPDATE + ReleaseMutex(drawMutex); + { + RECT r; + r.left = x; r.right = x+1; + r.top = y; r.bottom = y+1; + InvalidateRect(priv->hwnd, &r, FALSE); + } + #else + { + HDC dc; + dc = GetDC(priv->hwnd); + SetPixel(dc, x, y, color); + ReleaseDC(priv->hwnd, dc); + ReleaseMutex(drawMutex); + } + #endif + + // Update the cursor + if (++priv->x > priv->x1) { + priv->x = priv->x0; + if (++priv->y > priv->y1) { + g->flags |= GDISP_FLG_WRAPPED; + priv->y = priv->y0; + } + } + } + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + if (!(g->flags & GDISP_FLG_WSTREAM)) + BAD_PARAMETER("write_stop: not in streaming mode"); + g->flags &= ~GDISP_FLG_WSTREAM; + } + #if GDISP_HARDWARE_STREAM_POS + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { + winPriv * priv; + + priv = g->priv; + + if (!(g->flags & GDISP_FLG_WSTREAM)) + BAD_PARAMETER("write_pos: not in streaming mode"); + if (g->p.x < priv->x0 || g->p.x > priv->x1 || g->p.y < priv->y0 || g->p.y > priv->y1) + BAD_PARAMETER("write_color: new cursor outside streaming area"); + priv->x = g->p.x; + priv->y = g->p.y; + } + #endif +#endif + +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDisplay *g) { + winPriv * priv; + + if (g->flags & GDISP_FLG_WSTREAM) + BAD_PARAMETER("read_start: already in streaming mode"); + if (g->p.cx <= 0 || g->p.cy <= 0 || g->p.x < 0 || g->p.y < 0 || g->p.x+g->p.cx > g->g.Width || g->p.y+g->p.cy > g->g.Height) + BAD_PARAMETER("read_start: bad window parameter"); + + priv = g->priv; + priv->x0 = g->p.x; priv->x1 = g->p.x + g->p.cx - 1; + priv->y0 = g->p.y; priv->y1 = g->p.y + g->p.cy - 1; + priv->x = g->p.x; + priv->y = g->p.y; + g->flags |= GDISP_FLG_WSTREAM; + g->flags &= ~GDISP_FLG_WRAPPED; + } + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { + winPriv * priv; + COLORREF color; + + priv = g->priv; + + if (!(g->flags & GDISP_FLG_WSTREAM)) + BAD_PARAMETER("read_color: not in streaming mode"); + if (priv->x < priv->x0 || priv->x > priv->x1 || priv->y < priv->y0 || priv->y > priv->y1) + BAD_PARAMETER("read_color: cursor outside streaming area"); + if (g->flags & GDISP_FLG_WRAPPED) { + BAD_PARAMETER("read_color: Warning - Area wrapped."); + g->flags &= ~GDISP_FLG_WRAPPED; + } + + WaitForSingleObject(drawMutex, INFINITE); + #if GDISP_NEED_CONTROL + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + color = GetPixel(priv->dcBuffer, g->p.x, g->p.y); + break; + case GDISP_ROTATE_90: + color = GetPixel(priv->dcBuffer, g->p.y, g->g.Width - 1 - g->p.x); + break; + case GDISP_ROTATE_180: + color = GetPixel(priv->dcBuffer, g->g.Width - 1 - g->p.x, g->g.Height - 1 - g->p.y); + break; + case GDISP_ROTATE_270: + color = GetPixel(priv->dcBuffer, g->g.Height - 1 - g->p.y, g->p.x); + break; + } + #else + color = GetPixel(priv->dcBuffer, g->p.x, g->p.y); + #endif + ReleaseMutex(drawMutex); + + // Update the cursor + if (++priv->x > priv->x1) { + priv->x = priv->x0; + if (++priv->y > priv->y1) { + g->flags |= GDISP_FLG_WRAPPED; + priv->y = priv->y0; + } + } + + return BGR2COLOR(color); + } + LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { + if (!(g->flags & GDISP_FLG_WSTREAM)) + BAD_PARAMETER("write_stop: not in streaming mode"); + g->flags &= ~GDISP_FLG_WSTREAM; + } +#endif + #if GDISP_HARDWARE_DRAWPIXEL LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { winPriv * priv; @@ -507,8 +713,8 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { ReleaseMutex(drawMutex); { RECT r; - r.left = g->p.x; r.right = g->p.x+1; - r.top = g->p.y; r.bottom = g->p.y+1; + r.left = x; r.right = x+1; + r.top = y; r.bottom = y+1; InvalidateRect(priv->hwnd, &r, FALSE); } #else diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h index f6544eb4..e2fc3de4 100644 --- a/drivers/multiple/Win32/gdisp_lld_config.h +++ b/drivers/multiple/Win32/gdisp_lld_config.h @@ -26,12 +26,24 @@ // application to force a display update. eg after streaming. #define GDISP_HARDWARE_FLUSH TRUE -#define GDISP_HARDWARE_DRAWPIXEL TRUE -#define GDISP_HARDWARE_FILLS TRUE -#define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_HARDWARE_BITFILLS TRUE -#define GDISP_HARDWARE_SCROLL TRUE + +//#define GDISP_WIN32_STREAMING_TEST +#ifdef GDISP_WIN32_STREAMING_TEST + // These streaming routines are here only to debug the high level gdisp + // code for streaming controllers. They are slow, inefficient and have + // lots of debugging turned on. + #define GDISP_HARDWARE_STREAM_WRITE TRUE + #define GDISP_HARDWARE_STREAM_READ TRUE + #define GDISP_HARDWARE_STREAM_POS TRUE +#else + // The proper way on the Win32. These routines are nice and fast. + #define GDISP_HARDWARE_DRAWPIXEL TRUE + #define GDISP_HARDWARE_FILLS TRUE + #define GDISP_HARDWARE_PIXELREAD TRUE + #define GDISP_HARDWARE_BITFILLS TRUE + #define GDISP_HARDWARE_SCROLL TRUE +#endif #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 From 4a5506df0a36a61b13c01b0173523a2ce31b5fb9 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 11:32:46 +1000 Subject: [PATCH 102/160] Fixes to GDISP for streaming drivers. Turn optimisation back on for SSD1289 driver --- drivers/gdisp/SSD1289/gdisp_lld_config.h | 2 +- src/gdisp/gdisp.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gdisp/SSD1289/gdisp_lld_config.h b/drivers/gdisp/SSD1289/gdisp_lld_config.h index f8743a2b..84e518d2 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_config.h @@ -24,7 +24,7 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE -//#define GDISP_HARDWARE_STREAM_POS TRUE +#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE #if defined(GDISP_USE_DMA) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 53882492..3d2e6e36 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -87,6 +87,7 @@ GDisplay *GDISP = GDisplayArray; static INLINE void setglobalwindow(GDisplay *g) { coord_t x, y; x = g->p.x; y = g->p.y; + g->p.x = g->p.y = 0; g->p.cx = g->g.Width; g->p.cy = g->g.Height; gdisp_lld_write_start(g); g->p.x = x; g->p.y = y; @@ -304,8 +305,9 @@ static void hline_clip(GDisplay *g) { { if (!(g->flags & GDISP_FLG_SCRSTREAM)) setglobalwindow(g); + g->p.cx = g->p.x1 - g->p.x + 1; gdisp_lld_write_pos(g); - do { gdisp_lld_write_color(g); } while(g->p.cx--); + do { gdisp_lld_write_color(g); } while(--g->p.cx); return; } #endif @@ -319,7 +321,7 @@ static void hline_clip(GDisplay *g) { g->p.cx = g->p.x1 - g->p.x + 1; g->p.cy = 1; gdisp_lld_write_start(g); - do { gdisp_lld_write_color(g); } while(g->p.cx--); + do { gdisp_lld_write_color(g); } while(--g->p.cx); gdisp_lld_write_stop(g); return; } @@ -404,7 +406,7 @@ static void vline_clip(GDisplay *g) { #endif gdisp_lld_write_pos(g); #endif - do { gdisp_lld_write_color(g); } while(g->p.cy--); + do { gdisp_lld_write_color(g); } while(--g->p.cy); gdisp_lld_write_stop(g); return; } From 90ad93c41fa86534479f7006ec2c3956da9eac3c Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 11:59:41 +1000 Subject: [PATCH 103/160] Updates to SSD1306 driver to raise thread priority during flushing. --- drivers/gdisp/SSD1306/board_SSD1306_i2c.h | 15 +++++++++++++-- drivers/gdisp/SSD1306/board_SSD1306_spi.h | 13 ++++++++++++- drivers/gdisp/SSD1306/gdisp_lld.c | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/gdisp/SSD1306/board_SSD1306_i2c.h b/drivers/gdisp/SSD1306/board_SSD1306_i2c.h index c89562e0..69c054f5 100644 --- a/drivers/gdisp/SSD1306/board_SSD1306_i2c.h +++ b/drivers/gdisp/SSD1306/board_SSD1306_i2c.h @@ -41,6 +41,10 @@ // I2C configuration structure. static I2CConfig i2cconfig; +#if GFX_USE_OS_CHIBIOS + static int32_t thdPriority = 0; +#endif + static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->board to NULL as we don't use it. @@ -62,10 +66,10 @@ static inline void init_board(GDisplay *g) { * 0x0030020A; // 400kHz Fast Mode * 0x00100002; // 800kHz Fast Mode + */ - i2cconfig.timingr = 0x00100002; // 800kHz Fast Mode+ - i2cInit(); palSetPadMode(SSD1306_SCL_PORT, SSD1306_SCL_PIN, PAL_MODE_ALTERNATE(1)); palSetPadMode(SSD1306_SDA_PORT, SSD1306_SDA_PIN, PAL_MODE_ALTERNATE(1)); + i2cconfig.timingr = 0x00100002; // 800kHz Fast Mode+ + i2cInit(); break; } } @@ -84,11 +88,18 @@ static inline void setpin_reset(GDisplay *g, bool_t state) { static inline void acquire_bus(GDisplay *g) { (void) g; + #if GFX_USE_OS_CHIBIOS + thdPriority = (int32_t)chThdGetPriority(); + chThdSetPriority(HIGHPRIO); + #endif i2cAcquireBus(&I2CD1); } static inline void release_bus(GDisplay *g) { (void) g; + #if GFX_USE_OS_CHIBIOS + chThdSetPriority(thdPriority); + #endif i2cReleaseBus(&I2CD1); } diff --git a/drivers/gdisp/SSD1306/board_SSD1306_spi.h b/drivers/gdisp/SSD1306/board_SSD1306_spi.h index e206a517..476c51bf 100644 --- a/drivers/gdisp/SSD1306/board_SSD1306_spi.h +++ b/drivers/gdisp/SSD1306/board_SSD1306_spi.h @@ -44,6 +44,10 @@ static const SPIConfig spi1config = { //SPI_CR1_BR_0 }; +#if GFX_USE_OS_CHIBIOS + static int32_t thdPriority = 0; +#endif + static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->board to NULL as we don't use it. @@ -54,7 +58,6 @@ static inline void init_board(GDisplay *g) { // RESET pin. palSetPadMode(SSD1306_RESET_PORT, SSD1306_RESET_PIN, PAL_MODE_OUTPUT_PUSHPULL); - spiInit(); palSetPadMode(SSD1306_MISO_PORT, SSD1306_MISO_PIN, PAL_MODE_ALTERNATE(1)| PAL_STM32_OSPEED_HIGHEST); palSetPadMode(SSD1306_MOSI_PORT, SSD1306_MOSI_PIN, PAL_MODE_ALTERNATE(1)| @@ -64,6 +67,7 @@ static inline void init_board(GDisplay *g) { palSetPad(SSD1306_CS_PORT, SSD1306_CS_PIN); palSetPadMode(SSD1306_CS_PORT, SSD1306_CS_PIN, PAL_MODE_ALTERNATE(1)| PAL_STM32_OSPEED_HIGHEST); + spiInit(); break; } } @@ -82,11 +86,18 @@ static inline void setpin_reset(GDisplay *g, bool_t state) { static inline void acquire_bus(GDisplay *g) { (void) g; + #if GFX_USE_OS_CHIBIOS + thdPriority = (int32_t)chThdGetPriority(); + chThdSetPriority(HIGHPRIO); + #endif spiAcquireBus(&SPID1); } static inline void release_bus(GDisplay *g) { (void) g; + #if GFX_USE_OS_CHIBIOS + chThdSetPriority(thdPriority); + #endif spiReleaseBus(&SPID1); } diff --git a/drivers/gdisp/SSD1306/gdisp_lld.c b/drivers/gdisp/SSD1306/gdisp_lld.c index 079c9256..81b3b692 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld.c +++ b/drivers/gdisp/SSD1306/gdisp_lld.c @@ -12,7 +12,7 @@ #include "gfx.h" -#if GFX_USE_GDISP || defined(__DOXYGEN__) +#if GFX_USE_GDISP #define GDISP_DRIVER_VMT GDISPVMT_SSD1306 #include "../drivers/gdisp/SSD1306/gdisp_lld_config.h" From 452cfc1b1351e8070ed609d84cae0249411a236b Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 12:57:20 +1000 Subject: [PATCH 104/160] Add GDISP_NEED_TIMERFLUSH to enable automatic display flushing on a timer. --- gfxconf.example.h | 1 + include/gdisp/options.h | 13 +++++++++++++ include/gfx_rules.h | 28 +++++++++++++++++++++++++--- src/gdisp/gdisp.c | 21 ++++++++++++++++++++- 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/gfxconf.example.h b/gfxconf.example.h index 958d35da..d5b4af5c 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -35,6 +35,7 @@ /* Features for the GDISP subsystem */ #define GDISP_NEED_AUTOFLUSH FALSE +#define GDISP_NEED_TIMERFLUSH FALSE #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE diff --git a/include/gdisp/options.h b/include/gdisp/options.h index 72fe2038..4b199118 100644 --- a/include/gdisp/options.h +++ b/include/gdisp/options.h @@ -28,12 +28,25 @@ * Setting this to TRUE causes GDISP to automatically flush * after each drawing operation. Note this may be slow but enables * an application to avoid having to manually call the flush routine. + * @note If TRUE and GDISP_NEED_TIMERFLUSH is also TRUE, this takes precedence. * @note Most controllers don't need flushing which is why this is set to * FALSE by default. */ #ifndef GDISP_NEED_AUTOFLUSH #define GDISP_NEED_AUTOFLUSH FALSE #endif + /** + * @brief Should drawing operations be automatically flushed on a timer. + * @details Defaults to FALSE, Can be set to FALSE or a timer period in milliseconds. + * @note The period should not be set too short or it will consume all your CPU. A + * value between 250 and 500 milliseconds would probably be suitable. + * @note If TRUE and GDISP_NEED_AUTOFLUSH is also TRUE, this is ineffective. + * @note Most controllers don't need flushing which is why this is set to + * FALSE by default. + */ + #ifndef GDISP_NEED_TIMERFLUSH + #define GDISP_NEED_TIMERFLUSH FALSE + #endif /** * @brief Should all operations be clipped to the screen and colors validated. * @details Defaults to TRUE. diff --git a/include/gfx_rules.h b/include/gfx_rules.h index c58fc5ba..853d9e8a 100644 --- a/include/gfx_rules.h +++ b/include/gfx_rules.h @@ -138,10 +138,32 @@ #ifndef GDISP_CONTROLLER_LIST #error "GDISP Multiple Controllers: You must specify a value for GDISP_CONTROLLER_LIST" #endif + #ifndef GDISP_CONTROLLER_DISPLAYS + #error "GDISP Multiple Controllers: You must specify a value for GDISP_CONTROLLER_DISPLAYS" + #endif #ifndef GDISP_PIXELFORMAT + #error "GDISP Multiple Controllers: You must specify a value for GDISP_PIXELFORMAT" + #endif + #endif + #if GDISP_NEED_AUTOFLUSH && GDISP_NEED_TIMERFLUSH + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GDISP: Both GDISP_NEED_AUTOFLUSH and GDISP_NEED_TIMERFLUSH has been set. GDISP_NEED_TIMERFLUSH has disabled for you." + #endif + #undef GDISP_NEED_TIMERFLUSH + #define GDISP_NEED_TIMERFLUSH FALSE + #endif + #if GDISP_NEED_TIMERFLUSH + #if GDISP_NEED_TIMERFLUSH < 50 || GDISP_NEED_TIMERFLUSH > 1200 + #error "GDISP: GDISP_NEED_TIMERFLUSH has been set to an invalid value (FALSE, 50-1200)." + #endif + #if !GFX_USE_GTIMER #if GFX_DISPLAY_RULE_WARNINGS - #error "GDISP Multiple Controllers: You must specify a value for GDISP_PIXELFORMAT" + #warning "GDISP: GDISP_NEED_TIMERFLUSH has been set but GFX_USE_GTIMER has not been set. It has been turned on for you." #endif + #undef GFX_USE_GTIMER + #define GFX_USE_GTIMER TRUE + #undef GDISP_NEED_MULTITHREAD + #define GDISP_NEED_MULTITHREAD TRUE #endif #endif #if GDISP_NEED_ANTIALIAS && !GDISP_NEED_PIXELREAD @@ -194,9 +216,9 @@ #endif #if GFX_USE_GTIMER - #if GFX_USE_GDISP && !GDISP_NEED_MULTITHREAD && !GDISP_NEED_ASYNC + #if GFX_USE_GDISP && !GDISP_NEED_MULTITHREAD #if GFX_DISPLAY_RULE_WARNINGS - #warning "GTIMER: Neither GDISP_NEED_MULTITHREAD nor GDISP_NEED_ASYNC has been specified." + #warning "GTIMER: GDISP_NEED_MULTITHREAD has not been specified." #warning "GTIMER: Make sure you are not performing any GDISP/GWIN drawing operations in the timer callback!" #endif #endif diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 3d2e6e36..fdda1cff 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -44,6 +44,11 @@ static const struct GDISPVMT const * ControllerList[GDISP_TOTAL_CONTROLLERS] = {GDISP_CONTROLLER_LIST}; static const unsigned DisplayCountList[GDISP_TOTAL_CONTROLLERS] = {GDISP_CONTROLLER_DISPLAYS}; #endif + +#if GDISP_NEED_TIMERFLUSH + static GTimer FlushTimer; +#endif + static GDisplay GDisplayArray[GDISP_TOTAL_DISPLAYS]; GDisplay *GDISP = GDisplayArray; @@ -509,6 +514,16 @@ static void line_clip(GDisplay *g) { } #endif +#if GDISP_NEED_TIMERFLUSH + static void FlushTimerFn(void *param) { + GDisplay * g; + (void) param; + + for(g = GDisplayArray; g < &GDisplayArray[GDISP_TOTAL_DISPLAYS]; g++) + gdispGFlush(g); + } +#endif + /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ @@ -521,7 +536,6 @@ void _gdispInit(void) { uint16_t j; #endif - /* Initialise driver */ #if GDISP_TOTAL_CONTROLLERS > 1 for(g = GDisplayArray, j=0; j < GDISP_TOTAL_CONTROLLERS; j++) @@ -587,6 +601,11 @@ void _gdispInit(void) { #endif } #endif + + #if GDISP_NEED_TIMERFLUSH + gtimerInit(&FlushTimer); + gtimerStart(&FlushTimer, FlushTimerFn, 0, TRUE, GDISP_NEED_TIMERFLUSH); + #endif } GDisplay *gdispGetDisplay(unsigned display) { From 21afd2b8f19d522fab6b78670bf1afcf11388cd5 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 13:59:03 +1000 Subject: [PATCH 105/160] Created a crude auto-scaling logo (for startup) --- src/gdisp/gdisp.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index fdda1cff..263e882d 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -510,7 +510,41 @@ static void line_clip(GDisplay *g) { #if GDISP_STARTUP_LOGO_TIMEOUT > 0 static void StatupLogoDisplay(GDisplay *g) { - gdispGFillArea(g, g->g.Width/4, g->g.Height/4, g->g.Width/2, g->g.Height/2, Blue); + coord_t x, y, w; + const coord_t * p; + static const coord_t blks[] = { + // u + 2, 6, 1, 10, + 3, 11, 4, 1, + 6, 6, 1, 6, + // G + 8, 0, 1, 12, + 9, 0, 6, 1, + 9, 11, 6, 1, + 14, 6, 1, 5, + 12, 6, 2, 1, + // F + 16, 0, 1, 12, + 17, 0, 6, 1, + 17, 6, 3, 1, + // X + 22, 6, 7, 1, + 24, 0, 1, 6, + 22, 7, 1, 5, + 28, 0, 1, 6, + 26, 7, 1, 5, + }; + + // Get a starting position and a scale + // Work on a 8x16 grid for each char, 4 chars (uGFX) in 1 line, using half the screen + w = g->g.Width/(8*4*2); + if (!w) w = 1; + x = (g->g.Width - (8*4)*w)/2; + y = (g->g.Height - (16*1)*w)/2; + + // Simple but crude! + for(p = blks; p < blks+sizeof(blks)/sizeof(blks[0]); p+=4) + gdispGFillArea(g, x+p[0]*w, y+p[1]*w, p[2]*w, p[3]*w, Blue); } #endif From e6f17baf6133fb83c5c72f7b173cf50c9c275224 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 15:03:47 +1000 Subject: [PATCH 106/160] GMISC invsqrt() function. Fix a 64bit processor bug. Add support for processors where the floating point and integer endianness don't match. Add support for processors with a non-standard floating point format. Update gdisp_streaming demo with extra comments to reflect the above changes. --- demos/modules/gdisp/gdisp_streaming/gfxconf.h | 10 ++-- demos/modules/gdisp/gdisp_streaming/main.c | 32 +++++++---- gfxconf.example.h | 3 +- include/gmisc/options.h | 27 +++++++++- src/gmisc/trig.c | 54 ++++++++++++++----- 5 files changed, 97 insertions(+), 29 deletions(-) diff --git a/demos/modules/gdisp/gdisp_streaming/gfxconf.h b/demos/modules/gdisp/gdisp_streaming/gfxconf.h index 4db07fb9..b38be854 100644 --- a/demos/modules/gdisp/gdisp_streaming/gfxconf.h +++ b/demos/modules/gdisp/gdisp_streaming/gfxconf.h @@ -35,9 +35,11 @@ /* Builtin Fonts */ #define GDISP_INCLUDE_FONT_UI2 FALSE -#define GFX_USE_GMISC TRUE -#define GMISC_NEED_FIXEDTRIG FALSE -#define GMISC_NEED_FASTTRIG FALSE -#define GMISC_NEED_INVSQRT TRUE +#define GFX_USE_GMISC TRUE +#define GMISC_NEED_FIXEDTRIG FALSE +#define GMISC_NEED_FASTTRIG FALSE +#define GMISC_NEED_INVSQRT TRUE +//#define GDISP_INVSQRT_MIXED_ENDIAN TRUE +//#define GDISP_INVSQRT_REAL_SLOW TRUE #endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/gdisp_streaming/main.c b/demos/modules/gdisp/gdisp_streaming/main.c index 774ee833..5b857eeb 100644 --- a/demos/modules/gdisp/gdisp_streaming/main.c +++ b/demos/modules/gdisp/gdisp_streaming/main.c @@ -31,15 +31,29 @@ #include "gfx.h" #include -#define Lightgrey () -#define Midgrey () -#define Darkgrey (HTML2COLOR(0x303030)) - -#define BALLCOLOR1 Red -#define BALLCOLOR2 Yellow -#define WALLCOLOR HTML2COLOR(0x303030) -#define BACKCOLOR HTML2COLOR(0xC0C0C0) -#define FLOORCOLOR HTML2COLOR(0x606060) +/** + * NOTE: + * + * This demo uses floating point operations. Don't expect it to work with any + * speed unless your processor has an FPU. + * + * If you see garbage inside the ball as it is running rather than the red and yellow + * checkerboard pattern then the fast invsqrt() function in GMISC does not work on + * your processor. + * + * You can modify the implementation of invsqrt() by firstly defining + * #define GDISP_INVSQRT_MIXED_ENDIAN TRUE + * in your gfxconf.h file. + * + * If it still doesn't work then instead define + * #define GDISP_INVSQRT_REAL_SLOW TRUE + * in your gfxconf.h file. This should always work although it will probably be slow. + */ +#define BALLCOLOR1 Red +#define BALLCOLOR2 Yellow +#define WALLCOLOR HTML2COLOR(0x303030) +#define BACKCOLOR HTML2COLOR(0xC0C0C0) +#define FLOORCOLOR HTML2COLOR(0x606060) #define SHADOWALPHA (255-255*0.2) int main(void) { diff --git a/gfxconf.example.h b/gfxconf.example.h index d5b4af5c..1b9faca2 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -181,11 +181,12 @@ #define GWIN_CONSOLE_USE_BASESTREAM FALSE #define GWIN_CONSOLE_USE_FLOAT FALSE #define GWIN_NEED_IMAGE_ANIMATION FALSE + #define GDISP_INVSQRT_MIXED_ENDIAN FALSE + #define GDISP_INVSQRT_REAL_SLOW FALSE */ /* Optional Low Level Driver Definitions */ /* - #define GDISP_USE_CUSTOM_BOARD FALSE #define GDISP_SCREEN_WIDTH 320 #define GDISP_SCREEN_HEIGHT 240 #define GDISP_USE_FSMC diff --git a/include/gmisc/options.h b/include/gmisc/options.h index 73b41800..9c309487 100644 --- a/include/gmisc/options.h +++ b/include/gmisc/options.h @@ -44,9 +44,34 @@ /** * @} * - * @name GMISC Optional Sizing Parameters + * @name GMISC Optional Parameters * @{ */ + /** + * @brief Modifies the @p invsqrt() function to assume a different integer to floating point endianness. + * @note Normally the floating point format and the integer format have + * the same endianness. Unfortunately there are some strange + * processors that don't eg. some very early ARM devices. + * For those where the endianness doesn't match you can fix it by + * defining GDISP_INVSQRT_MIXED_ENDIAN. + * @note This still assumes the processor is using an ieee floating point format. + * + * If you have a software floating point that uses a non-standard + * floating point format (or very strange hardware) then define + * GDISP_INVSQRT_REAL_SLOW and it will do it the hard way. + */ + #ifndef GDISP_INVSQRT_MIXED_ENDIAN + #define GDISP_INVSQRT_MIXED_ENDIAN FALSE + #endif + /** + * @brief Modifies the @p invsqrt() function to do things the long slow way. + * @note This causes the @p invsqrt() function to work regardless of the + * processor floating point format. + * @note This makes the @p invsqrt() function very slow. + */ + #ifndef GDISP_INVSQRT_REAL_SLOW + #define GDISP_INVSQRT_REAL_SLOW FALSE + #endif /** @} */ #endif /* _GMISC_OPTIONS_H */ diff --git a/src/gmisc/trig.c b/src/gmisc/trig.c index 00b6365a..cd35bdc0 100644 --- a/src/gmisc/trig.c +++ b/src/gmisc/trig.c @@ -143,21 +143,47 @@ #endif #if GMISC_NEED_INVSQRT - // Algorithm based on Quake code - float invsqrt(float n) { - long i; - float x2, y; - const float threehalfs = 1.5F; + // Algorithm based on Quake code. + #if GDISP_INVSQRT_REAL_SLOW + #include + float invsqrt(float n) { + return 1.0/sqrt(n); + } + #else + float invsqrt(float n) { + int32_t i; + float x2; - x2 = n * 0.5F; - y = n; - i = * ( long * ) &y; // evil floating point bit level hacking - i = 0x5f3759df - ( i >> 1 ); // what the? - y = * ( float * ) &i; - y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration - //y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration for extra precision, this can be removed - return y; - } + x2 = n * 0.5F; + + // Convert into an int32 (no binary format conversion) + #if GDISP_INVSQRT_MIXED_ENDIAN + ((char *)&i)[0] = ((char *)&n)[3]; + ((char *)&i)[1] = ((char *)&n)[2]; + ((char *)&i)[2] = ((char *)&n)[1]; + ((char *)&i)[3] = ((char *)&n)[0]; + #else + i = *(int32_t *)&n; + #endif + + // evil floating point bit level hacking + i = 0x5F3759DF - (i >> 1); + + // Convert back to a float (no binary format conversion) + #if GDISP_INVSQRT_MIXED_ENDIAN + ((char *)&n)[0] = ((char *)&i)[3]; + ((char *)&n)[1] = ((char *)&i)[2]; + ((char *)&n)[2] = ((char *)&i)[1]; + ((char *)&n)[3] = ((char *)&i)[0]; + #else + n = *(float *)&i; + #endif + + n = n * (1.5F - (x2 * n * n)); // 1st iteration + //n = n * (1.5F - (x2 * n * n)); // 2nd iteration for extra precision, this can be removed + return n; + } + #endif #endif #endif /* GFX_USE_GMISC */ From 0ea2f5463730a0067f4c146dd7f33398fcac8229 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 15:25:50 +1000 Subject: [PATCH 107/160] Slight improvement to the precision of the GMISC invsqrt() function. --- src/gmisc/trig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gmisc/trig.c b/src/gmisc/trig.c index cd35bdc0..2485da85 100644 --- a/src/gmisc/trig.c +++ b/src/gmisc/trig.c @@ -167,7 +167,7 @@ #endif // evil floating point bit level hacking - i = 0x5F3759DF - (i >> 1); + i = 0x5F375A86 - (i >> 1); // The quake code used 0x5F3759DF but this is better. // Convert back to a float (no binary format conversion) #if GDISP_INVSQRT_MIXED_ENDIAN From 6ad2ecf8185810ae27b25f26fe3d5171381ebe65 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 16:51:22 +1000 Subject: [PATCH 108/160] Fix invalid return value in gwin/lists.c --- src/gwin/list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gwin/list.c b/src/gwin/list.c index 0e93555d..57046102 100644 --- a/src/gwin/list.c +++ b/src/gwin/list.c @@ -338,7 +338,7 @@ GHandle gwinListCreate(GListObject* gobj, GWidgetInit* pInit, bool_t multiselect void gwinListSetScroll(GHandle gh, scroll_t flag) { // is it a valid handle? if (gh->vmt != (gwinVMT *)&listVMT) - return 0; + return; switch (flag) { case scrollAlways: From 7ba622b797696dd894c427617fa71ed3ca3b4f02 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 16:52:17 +1000 Subject: [PATCH 109/160] Add initial orientation to the widgets demo. --- demos/modules/gwin/widgets/main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c index 31b65a65..0dec7275 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -262,6 +262,10 @@ int main(void) { // Initialize the display gfxInit(); + #if GDISP_NEED_CONTROL + gdispSetOrientation(GDISP_ROTATE_90); + #endif + // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); From 0b5fccd2c3a8d0022e662d393bf856e6bfa13702 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 16:53:07 +1000 Subject: [PATCH 110/160] GDISP Win32 driver bug fix --- drivers/multiple/Win32/gdisp_lld.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 876168c3..7d7abb06 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -73,6 +73,9 @@ static DWORD winThreadId; static ATOM winClass; static volatile bool_t QReady; static HANDLE drawMutex; +#if GINPUT_NEED_MOUSE + static GDisplay * mouseDisplay; +#endif /*===========================================================================*/ /* Driver local routines . */ @@ -441,8 +444,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { // Only turn on mouse on the first window for now #if GINPUT_NEED_MOUSE - if (!g->controllerdisplay) + if (!g->controllerdisplay) { + mouseDisplay = g; g->flags |= GDISP_FLG_HASMOUSE; + } #endif // Create a private area for this window @@ -811,6 +816,8 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { // Copy the bits we need switch(g->g.Orientation) { + case GDISP_ROTATE_0: + return 0; // not handled as it doesn't need to be. case GDISP_ROTATE_90: for(src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) { dst = dstbuf+sz-g->p.cy+j; @@ -931,7 +938,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_NEED_CONTROL if (buffer != (pixel_t *)g->p.ptr) - free(srcimg); + free(buffer); #endif } #endif @@ -977,7 +984,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { priv = g->priv; #if GDISP_NEED_CONTROL - switch(GC->g.Orientation) { + switch(g->g.Orientation) { case GDISP_ROTATE_0: rect.top = g->p.y; rect.bottom = rect.top+g->p.cy; @@ -995,7 +1002,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { case GDISP_ROTATE_180: rect.bottom = g->g.Height - g->p.y; rect.top = rect.bottom-g->p.cy; - rect.right = GC->g.Width - g->p.x; + rect.right = g->g.Width - g->p.x; rect.left = rect.right-g->p.cx; lines = g->p.y1; vertical_scroll: @@ -1116,13 +1123,16 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GINPUT_NEED_MOUSE void ginput_lld_mouse_init(void) {} void ginput_lld_mouse_get_reading(MouseReading *pt) { - GDisplay *g; + GDisplay * g; + winPriv * priv; - g = GDISP_WIN32; - pt->x = g->priv->mousex; - pt->y = g->priv->mousey > g->g.Height ? g->g.Height : mousey; - pt->z = (g->priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; - pt->buttons = g->priv->mousebuttons; + g = mouseDisplay; + priv = g->priv; + + pt->x = priv->mousex; + pt->y = priv->mousey > g->g.Height ? g->g.Height : priv->mousey; + pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 100 : 0; + pt->buttons = priv->mousebuttons; } #endif /* GINPUT_NEED_MOUSE */ From db9f4a367daff83729ed9f144623db46ba08c80b Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 16:53:42 +1000 Subject: [PATCH 111/160] Bug fix to GDISP API --- include/gdisp/gdisp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index 1b17fabe..810ecb6b 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -1114,7 +1114,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co * * @api */ -#define gdispGUnsetClip(g) gdispGSetClip((g),0,0,(g)->Width,(g)->Height) +#define gdispGUnsetClip(g) gdispGSetClip((g),0,0,gdispGGetWidth(g),gdispGGetHeight(g)) #define gdispUnsetClip() gdispGUnsetClip(GDISP) #ifdef __cplusplus From 1a99b3c321f6456c79aeb402fb34f421d2349d04 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 16:56:09 +1000 Subject: [PATCH 112/160] New: ginputSetMouseDisplay() to allow the mouse to work with a non-default display. Fix: Mouse orientation fixed to match the now corrected GDISP orientation. Comment updates --- include/ginput/mouse.h | 19 ++++++++-- src/ginput/mouse.c | 83 ++++++++++++++++++++++++------------------ 2 files changed, 64 insertions(+), 38 deletions(-) diff --git a/include/ginput/mouse.h b/include/ginput/mouse.h index 93537329..f13379c3 100644 --- a/include/ginput/mouse.h +++ b/include/ginput/mouse.h @@ -84,7 +84,8 @@ extern "C" { /** * @brief Creates an instance of a mouse and returns the Source handler - * @note hack: if the instance is 9999, no calibration will be performed! + * @note HACK: if the instance is 9999, it is treated as instance 0 except + * that no calibration will be performed! * * @param[in] instance The ID of the mouse input instance (from 0 to 9999) * @@ -92,6 +93,19 @@ extern "C" { */ GSourceHandle ginputGetMouse(uint16_t instance); + /** + * @brief Assign the display associated with the mouse + * @note This only needs to be called if the mouse is associated with a display + * other than the current default display. It must be called before + * @p ginputGetMouse() if the new display is to be used during the calibration + * process. Other than calibration the display is used for range checking, + * and may also be used to display a mouse pointer. + * + * @param[in] instance The ID of the mouse input instance + * @param[in] g The GDisplay to which this mouse belongs + */ + void ginputSetMouseDisplay(uint16_t instance, GDisplay *g); + /** * @brief Get the current mouse position and button status * @note Unlinke a listener event, this status cannot record meta events such as @@ -129,12 +143,11 @@ extern "C" { * as the gdispGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it. * If this is called after gdispGetMouse() has been called and the driver requires calibration storage, it will immediately save the * data is has already obtained. - * The 'requireFree' parameter indicates if the fetch buffer must be free()'d to deallocate the buffer provided by the Fetch routine. * * @param[in] instance The ID of the mouse input instance * @param[in] fnsave The routine to save the data * @param[in] fnload The routine to restore the data - * @param[in] requireFree ToDo + * @param[in] requireFree TRUE if the buffer returned by the load function must be freed by the mouse code. */ void ginputSetMouseCalibrationRoutines(uint16_t instance, GMouseCalibrationSaveRoutine fnsave, GMouseCalibrationLoadRoutine fnload, bool_t requireFree); diff --git a/src/ginput/mouse.c b/src/ginput/mouse.c index 74b5a990..b662008e 100644 --- a/src/ginput/mouse.c +++ b/src/ginput/mouse.c @@ -19,6 +19,8 @@ #include "ginput/lld/mouse.h" +static GDisplay *mouseDisplay = 0; + #if GINPUT_MOUSE_NEED_CALIBRATION #if !defined(GFX_USE_GDISP) || !GFX_USE_GDISP #error "GINPUT: GFX_USE_GDISP must be defined when mouse or touch calibration is required" @@ -74,26 +76,26 @@ static struct MouseConfig_t { #if GINPUT_MOUSE_NEED_CALIBRATION static inline void _tsDrawCross(const MousePoint *pp) { - gdispDrawLine(pp->x-15, pp->y, pp->x-2, pp->y, White); - gdispDrawLine(pp->x+2, pp->y, pp->x+15, pp->y, White); - gdispDrawLine(pp->x, pp->y-15, pp->x, pp->y-2, White); - gdispDrawLine(pp->x, pp->y+2, pp->x, pp->y+15, White); + gdispGDrawLine(mouseDisplay, pp->x-15, pp->y, pp->x-2, pp->y, White); + gdispGDrawLine(mouseDisplay, pp->x+2, pp->y, pp->x+15, pp->y, White); + gdispGDrawLine(mouseDisplay, pp->x, pp->y-15, pp->x, pp->y-2, White); + gdispGDrawLine(mouseDisplay, pp->x, pp->y+2, pp->x, pp->y+15, White); - gdispDrawLine(pp->x-15, pp->y+15, pp->x-7, pp->y+15, RGB2COLOR(184,158,131)); - gdispDrawLine(pp->x-15, pp->y+7, pp->x-15, pp->y+15, RGB2COLOR(184,158,131)); + gdispGDrawLine(mouseDisplay, pp->x-15, pp->y+15, pp->x-7, pp->y+15, RGB2COLOR(184,158,131)); + gdispGDrawLine(mouseDisplay, pp->x-15, pp->y+7, pp->x-15, pp->y+15, RGB2COLOR(184,158,131)); - gdispDrawLine(pp->x-15, pp->y-15, pp->x-7, pp->y-15, RGB2COLOR(184,158,131)); - gdispDrawLine(pp->x-15, pp->y-7, pp->x-15, pp->y-15, RGB2COLOR(184,158,131)); + gdispGDrawLine(mouseDisplay, pp->x-15, pp->y-15, pp->x-7, pp->y-15, RGB2COLOR(184,158,131)); + gdispGDrawLine(mouseDisplay, pp->x-15, pp->y-7, pp->x-15, pp->y-15, RGB2COLOR(184,158,131)); - gdispDrawLine(pp->x+7, pp->y+15, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); - gdispDrawLine(pp->x+15, pp->y+7, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); + gdispGDrawLine(mouseDisplay, pp->x+7, pp->y+15, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); + gdispGDrawLine(mouseDisplay, pp->x+15, pp->y+7, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); - gdispDrawLine(pp->x+7, pp->y-15, pp->x+15, pp->y-15, RGB2COLOR(184,158,131)); - gdispDrawLine(pp->x+15, pp->y-15, pp->x+15, pp->y-7, RGB2COLOR(184,158,131)); + gdispGDrawLine(mouseDisplay, pp->x+7, pp->y-15, pp->x+15, pp->y-15, RGB2COLOR(184,158,131)); + gdispGDrawLine(mouseDisplay, pp->x+15, pp->y-15, pp->x+15, pp->y-7, RGB2COLOR(184,158,131)); } static inline void _tsClearCross(const MousePoint *pp) { - gdispFillArea(pp->x - 15, pp->y - 15, 42, 42, Blue); + gdispGFillArea(mouseDisplay, pp->x - 15, pp->y - 15, 42, 42, Blue); } static inline void _tsTransform(MouseReading *pt, const Calibration *c) { @@ -169,8 +171,8 @@ static void get_calibrated_reading(MouseReading *pt) { get_raw_reading(pt); #if GINPUT_MOUSE_NEED_CALIBRATION || GDISP_NEED_CONTROL - w = gdispGetWidth(); - h = gdispGetHeight(); + w = gdispGGetWidth(mouseDisplay); + h = gdispGGetHeight(mouseDisplay); #endif #if GINPUT_MOUSE_NEED_CALIBRATION @@ -178,14 +180,14 @@ static void get_calibrated_reading(MouseReading *pt) { #endif #if GDISP_NEED_CONTROL - switch(gdispGetOrientation()) { + switch(gdispGGetOrientation(mouseDisplay)) { case GDISP_ROTATE_0: break; case GDISP_ROTATE_90: { - coord_t t = pt->y; - pt->y = h - 1 - pt->x; - pt->x = t; + coord_t t = pt->x; + pt->x = w - 1 - pt->y; + pt->y = t; } break; case GDISP_ROTATE_180: @@ -194,9 +196,9 @@ static void get_calibrated_reading(MouseReading *pt) { break; case GDISP_ROTATE_270: { - coord_t t = pt->x; - pt->x = w - 1 - pt->y; - pt->y = t; + coord_t t = pt->y; + pt->y = h - 1 - pt->x; + pt->x = t; } break; } @@ -319,6 +321,10 @@ GSourceHandle ginputGetMouse(uint16_t instance) { if (instance && instance != 9999) return 0; + // Make sure we have a valid mouse display + if (!mouseDisplay) + mouseDisplay = GDISP; + // Do we need to initialise the mouse subsystem? if (!(MouseConfig.flags & FLG_INIT_DONE)) { ginput_lld_mouse_init(); @@ -362,6 +368,13 @@ GSourceHandle ginputGetMouse(uint16_t instance) { return (GSourceHandle)&MouseConfig; } +void ginputSetMouseDisplay(uint16_t instance, GDisplay *g) { + if (instance) + return; + + mouseDisplay = g ? g : GDISP; +} + bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pe) { // Win32 threads don't seem to recognise priority and/or pre-emption // so we add a sleep here to prevent 100% polled applications from locking up. @@ -393,8 +406,8 @@ bool_t ginputCalibrateMouse(uint16_t instance) { return FALSE; #else - const coord_t height = gdispGetHeight(); - const coord_t width = gdispGetWidth(); + const coord_t height = gdispGGetHeight(mouseDisplay); + const coord_t width = gdispGGetWidth(mouseDisplay); const MousePoint cross[] = {{(width / 4), (height / 4)}, {(width - (width / 4)) , (height / 4)}, {(width - (width / 4)) , (height - (height / 4))}, @@ -420,19 +433,19 @@ bool_t ginputCalibrateMouse(uint16_t instance) { MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED); #if GDISP_NEED_CONTROL - gdispSetOrientation(GDISP_ROTATE_0); + gdispGSetOrientation(mouseDisplay, GDISP_ROTATE_0); #endif #if GDISP_NEED_CLIP - gdispSetClip(0, 0, width, height); + gdispGSetClip(mouseDisplay, 0, 0, width, height); #endif #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 while(1) { #endif - gdispClear(Blue); + gdispGClear(mouseDisplay, Blue); - gdispFillStringBox(0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter); + gdispGFillStringBox(mouseDisplay, 0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter); for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) { _tsDrawCross(pc); @@ -461,9 +474,9 @@ bool_t ginputCalibrateMouse(uint16_t instance) { _tsClearCross(pc); if (i >= 1 && pt->x == (pt-1)->x && pt->y == (pt-1)->y) { - gdispFillStringBox(0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, font2, Red, Yellow, justifyCenter); + gdispGFillStringBox(mouseDisplay, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, font2, Red, Yellow, justifyCenter); gfxSleepMilliseconds(5000); - gdispFillArea(0, 35, width, 40, Blue); + gdispGFillArea(mouseDisplay, 0, 35, width, 40, Blue); } } @@ -489,7 +502,7 @@ bool_t ginputCalibrateMouse(uint16_t instance) { if (err <= GINPUT_MOUSE_MAX_CALIBRATION_ERROR * GINPUT_MOUSE_MAX_CALIBRATION_ERROR) break; - gdispFillStringBox(0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); + gdispGFillStringBox(mouseDisplay, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); gfxSleepMilliseconds(5000); } #endif @@ -512,9 +525,9 @@ bool_t ginputCalibrateMouse(uint16_t instance) { // Clear the screen using the GWIN default background color #if GFX_USE_GWIN - gdispClear(gwinGetDefaultBgColor()); + gdispGClear(mouseDisplay, gwinGetDefaultBgColor()); #else - gdispClear(Black); + gdispGClear(mouseDisplay, Black); #endif return TRUE; @@ -523,8 +536,8 @@ bool_t ginputCalibrateMouse(uint16_t instance) { /* Set the routines to save and fetch calibration data. * This function should be called before first calling ginputGetMouse() for a particular instance - * as the gdispGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it. - * If this is called after gdispGetMouse() has been called and the driver requires calibration storage, it will immediately save the data is has already obtained. + * as the ginputGetMouse() routine may attempt to fetch calibration data and perform a startup calibration if there is no way to get it. + * If this is called after ginputGetMouse() has been called and the driver requires calibration storage, it will immediately save the data is has already obtained. * The 'requireFree' parameter indicates if the fetch buffer must be free()'d to deallocate the buffer provided by the Fetch routine. */ void ginputSetMouseCalibrationRoutines(uint16_t instance, GMouseCalibrationSaveRoutine fnsave, GMouseCalibrationLoadRoutine fnload, bool_t requireFree) { From e642edb4e182cad5aa2b109b3baf23cacc903084 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 18:33:40 +1000 Subject: [PATCH 113/160] Store the display locally within the mouse structure. Add ginputGetMouseDisplay() --- include/ginput/mouse.h | 10 ++++++ src/ginput/mouse.c | 71 +++++++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/include/ginput/mouse.h b/include/ginput/mouse.h index f13379c3..aa9864a9 100644 --- a/include/ginput/mouse.h +++ b/include/ginput/mouse.h @@ -56,6 +56,7 @@ typedef struct GEventMouse_t { GMETA_MOUSE_CXTCLICK = 8 // For mice - The right button has just been depressed // For touch - a long press has just occurred } meta; + GDisplay * display; // The display this mouse is currently associated with. } GEventMouse; // Mouse/Touch Listen Flags - passed to geventAddSourceToListener() @@ -106,6 +107,15 @@ extern "C" { */ void ginputSetMouseDisplay(uint16_t instance, GDisplay *g); + /** + * @brief Get the display currently associated with the mouse + * @return A pointer to the display + * + * @param[in] instance The ID of the mouse input instance + * @param[in] g The GDisplay to which this mouse belongs + */ + GDisplay *ginputGetMouseDisplay(uint16_t instance); + /** * @brief Get the current mouse position and button status * @note Unlinke a listener event, this status cannot record meta events such as diff --git a/src/ginput/mouse.c b/src/ginput/mouse.c index b662008e..99ef04f6 100644 --- a/src/ginput/mouse.c +++ b/src/ginput/mouse.c @@ -19,8 +19,6 @@ #include "ginput/lld/mouse.h" -static GDisplay *mouseDisplay = 0; - #if GINPUT_MOUSE_NEED_CALIBRATION #if !defined(GFX_USE_GDISP) || !GFX_USE_GDISP #error "GINPUT: GFX_USE_GDISP must be defined when mouse or touch calibration is required" @@ -72,30 +70,31 @@ static struct MouseConfig_t { GMouseCalibrationLoadRoutine fnloadcal; Calibration caldata; #endif + GDisplay * display; } MouseConfig; #if GINPUT_MOUSE_NEED_CALIBRATION static inline void _tsDrawCross(const MousePoint *pp) { - gdispGDrawLine(mouseDisplay, pp->x-15, pp->y, pp->x-2, pp->y, White); - gdispGDrawLine(mouseDisplay, pp->x+2, pp->y, pp->x+15, pp->y, White); - gdispGDrawLine(mouseDisplay, pp->x, pp->y-15, pp->x, pp->y-2, White); - gdispGDrawLine(mouseDisplay, pp->x, pp->y+2, pp->x, pp->y+15, White); + gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y, pp->x-2, pp->y, White); + gdispGDrawLine(MouseConfig.display, pp->x+2, pp->y, pp->x+15, pp->y, White); + gdispGDrawLine(MouseConfig.display, pp->x, pp->y-15, pp->x, pp->y-2, White); + gdispGDrawLine(MouseConfig.display, pp->x, pp->y+2, pp->x, pp->y+15, White); - gdispGDrawLine(mouseDisplay, pp->x-15, pp->y+15, pp->x-7, pp->y+15, RGB2COLOR(184,158,131)); - gdispGDrawLine(mouseDisplay, pp->x-15, pp->y+7, pp->x-15, pp->y+15, RGB2COLOR(184,158,131)); + gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y+15, pp->x-7, pp->y+15, RGB2COLOR(184,158,131)); + gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y+7, pp->x-15, pp->y+15, RGB2COLOR(184,158,131)); - gdispGDrawLine(mouseDisplay, pp->x-15, pp->y-15, pp->x-7, pp->y-15, RGB2COLOR(184,158,131)); - gdispGDrawLine(mouseDisplay, pp->x-15, pp->y-7, pp->x-15, pp->y-15, RGB2COLOR(184,158,131)); + gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y-15, pp->x-7, pp->y-15, RGB2COLOR(184,158,131)); + gdispGDrawLine(MouseConfig.display, pp->x-15, pp->y-7, pp->x-15, pp->y-15, RGB2COLOR(184,158,131)); - gdispGDrawLine(mouseDisplay, pp->x+7, pp->y+15, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); - gdispGDrawLine(mouseDisplay, pp->x+15, pp->y+7, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); + gdispGDrawLine(MouseConfig.display, pp->x+7, pp->y+15, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); + gdispGDrawLine(MouseConfig.display, pp->x+15, pp->y+7, pp->x+15, pp->y+15, RGB2COLOR(184,158,131)); - gdispGDrawLine(mouseDisplay, pp->x+7, pp->y-15, pp->x+15, pp->y-15, RGB2COLOR(184,158,131)); - gdispGDrawLine(mouseDisplay, pp->x+15, pp->y-15, pp->x+15, pp->y-7, RGB2COLOR(184,158,131)); + gdispGDrawLine(MouseConfig.display, pp->x+7, pp->y-15, pp->x+15, pp->y-15, RGB2COLOR(184,158,131)); + gdispGDrawLine(MouseConfig.display, pp->x+15, pp->y-15, pp->x+15, pp->y-7, RGB2COLOR(184,158,131)); } static inline void _tsClearCross(const MousePoint *pp) { - gdispGFillArea(mouseDisplay, pp->x - 15, pp->y - 15, 42, 42, Blue); + gdispGFillArea(MouseConfig.display, pp->x - 15, pp->y - 15, 42, 42, Blue); } static inline void _tsTransform(MouseReading *pt, const Calibration *c) { @@ -171,8 +170,8 @@ static void get_calibrated_reading(MouseReading *pt) { get_raw_reading(pt); #if GINPUT_MOUSE_NEED_CALIBRATION || GDISP_NEED_CONTROL - w = gdispGGetWidth(mouseDisplay); - h = gdispGGetHeight(mouseDisplay); + w = gdispGGetWidth(MouseConfig.display); + h = gdispGGetHeight(MouseConfig.display); #endif #if GINPUT_MOUSE_NEED_CALIBRATION @@ -180,7 +179,7 @@ static void get_calibrated_reading(MouseReading *pt) { #endif #if GDISP_NEED_CONTROL - switch(gdispGGetOrientation(mouseDisplay)) { + switch(gdispGGetOrientation(MouseConfig.display)) { case GDISP_ROTATE_0: break; case GDISP_ROTATE_90: @@ -305,6 +304,7 @@ static void MousePoll(void *param) { pe->meta |= psl->srcflags; psl->srcflags = 0; } + pe->display = MouseConfig.display; geventSendEvent(psl); } } @@ -322,8 +322,8 @@ GSourceHandle ginputGetMouse(uint16_t instance) { return 0; // Make sure we have a valid mouse display - if (!mouseDisplay) - mouseDisplay = GDISP; + if (!MouseConfig.display) + MouseConfig.display = GDISP; // Do we need to initialise the mouse subsystem? if (!(MouseConfig.flags & FLG_INIT_DONE)) { @@ -372,7 +372,14 @@ void ginputSetMouseDisplay(uint16_t instance, GDisplay *g) { if (instance) return; - mouseDisplay = g ? g : GDISP; + MouseConfig.display = g ? g : GDISP; +} + +GDisplay *ginputGetMouseDisplay(uint16_t instance) { + if (instance) + return 0; + + return MouseConfig.display; } bool_t ginputGetMouseStatus(uint16_t instance, GEventMouse *pe) { @@ -406,8 +413,8 @@ bool_t ginputCalibrateMouse(uint16_t instance) { return FALSE; #else - const coord_t height = gdispGGetHeight(mouseDisplay); - const coord_t width = gdispGGetWidth(mouseDisplay); + const coord_t height = gdispGGetHeight(MouseConfig.display); + const coord_t width = gdispGGetWidth(MouseConfig.display); const MousePoint cross[] = {{(width / 4), (height / 4)}, {(width - (width / 4)) , (height / 4)}, {(width - (width / 4)) , (height - (height / 4))}, @@ -433,19 +440,19 @@ bool_t ginputCalibrateMouse(uint16_t instance) { MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED); #if GDISP_NEED_CONTROL - gdispGSetOrientation(mouseDisplay, GDISP_ROTATE_0); + gdispGSetOrientation(MouseConfig.display, GDISP_ROTATE_0); #endif #if GDISP_NEED_CLIP - gdispGSetClip(mouseDisplay, 0, 0, width, height); + gdispGSetClip(MouseConfig.display, 0, 0, width, height); #endif #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 while(1) { #endif - gdispGClear(mouseDisplay, Blue); + gdispGClear(MouseConfig.display, Blue); - gdispGFillStringBox(mouseDisplay, 0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter); + gdispGFillStringBox(MouseConfig.display, 0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter); for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) { _tsDrawCross(pc); @@ -474,9 +481,9 @@ bool_t ginputCalibrateMouse(uint16_t instance) { _tsClearCross(pc); if (i >= 1 && pt->x == (pt-1)->x && pt->y == (pt-1)->y) { - gdispGFillStringBox(mouseDisplay, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, font2, Red, Yellow, justifyCenter); + gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, font2, Red, Yellow, justifyCenter); gfxSleepMilliseconds(5000); - gdispGFillArea(mouseDisplay, 0, 35, width, 40, Blue); + gdispGFillArea(MouseConfig.display, 0, 35, width, 40, Blue); } } @@ -502,7 +509,7 @@ bool_t ginputCalibrateMouse(uint16_t instance) { if (err <= GINPUT_MOUSE_MAX_CALIBRATION_ERROR * GINPUT_MOUSE_MAX_CALIBRATION_ERROR) break; - gdispGFillStringBox(mouseDisplay, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); + gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); gfxSleepMilliseconds(5000); } #endif @@ -525,9 +532,9 @@ bool_t ginputCalibrateMouse(uint16_t instance) { // Clear the screen using the GWIN default background color #if GFX_USE_GWIN - gdispGClear(mouseDisplay, gwinGetDefaultBgColor()); + gdispGClear(MouseConfig.display, gwinGetDefaultBgColor()); #else - gdispGClear(mouseDisplay, Black); + gdispGClear(MouseConfig.display, Black); #endif return TRUE; From a28dce97d877160b10a3683fbf8ea578c8405417 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 18:34:26 +1000 Subject: [PATCH 114/160] Add multiple display support to image decoding. --- include/gdisp/image.h | 14 +++--- src/gdisp/image.c | 17 +++---- src/gdisp/image_bmp.c | 12 ++--- src/gdisp/image_gif.c | 98 ++++++++++++++++++++-------------------- src/gdisp/image_native.c | 6 +-- 5 files changed, 75 insertions(+), 72 deletions(-) diff --git a/include/gdisp/image.h b/include/gdisp/image.h index 8619cb9c..ff2e9d85 100644 --- a/include/gdisp/image.h +++ b/include/gdisp/image.h @@ -243,6 +243,7 @@ extern "C" { * @brief Draw the image * @return GDISP_IMAGE_ERR_OK (0) on success or an error code. * + * @param[in] g The display to draw on * @param[in] img The image structure * @param[in] x,y The screen location to draw the image * @param[in] cx,cy The area on the screen to draw @@ -257,7 +258,8 @@ extern "C" { * is drawing. This may be significantly slower than if the image has been cached (but * uses a lot less RAM) */ - gdispImageError gdispImageDraw(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + gdispImageError gdispGImageDraw(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + #define gdispImageDraw(img,x,y,cx,cy,sx,sy) gdispGImageDraw(GDISP,img,x,y,cx,cy,sx,sy) /** * @brief Prepare for the next frame/page in the image file. @@ -299,7 +301,7 @@ extern "C" { gdispImageError gdispImageOpen_NATIVE(gdispImage *img); void gdispImageClose_NATIVE(gdispImage *img); gdispImageError gdispImageCache_NATIVE(gdispImage *img); - gdispImageError gdispImageDraw_NATIVE(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + gdispImageError gdispGImageDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); delaytime_t gdispImageNext_NATIVE(gdispImage *img); /* @} */ #endif @@ -315,7 +317,7 @@ extern "C" { gdispImageError gdispImageOpen_GIF(gdispImage *img); void gdispImageClose_GIF(gdispImage *img); gdispImageError gdispImageCache_GIF(gdispImage *img); - gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + gdispImageError gdispGImageDraw_GIF(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); delaytime_t gdispImageNext_GIF(gdispImage *img); /* @} */ #endif @@ -331,7 +333,7 @@ extern "C" { gdispImageError gdispImageOpen_BMP(gdispImage *img); void gdispImageClose_BMP(gdispImage *img); gdispImageError gdispImageCache_BMP(gdispImage *img); - gdispImageError gdispImageDraw_BMP(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + gdispImageError gdispGImageDraw_BMP(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); delaytime_t gdispImageNext_BMP(gdispImage *img); /* @} */ #endif @@ -347,7 +349,7 @@ extern "C" { gdispImageError gdispImageOpen_JPG(gdispImage *img); void gdispImageClose_JPG(gdispImage *img); gdispImageError gdispImageCache_JPG(gdispImage *img); - gdispImageError gdispImageDraw_JPG(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + gdispImageError gdispGImageDraw_JPG(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); delaytime_t gdispImageNext_JPG(gdispImage *img); /* @} */ #endif @@ -363,7 +365,7 @@ extern "C" { gdispImageError gdispImageOpen_PNG(gdispImage *img); void gdispImageClose_PNG(gdispImage *img); gdispImageError gdispImageCache_PNG(gdispImage *img); - gdispImageError gdispImageDraw_PNG(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); + gdispImageError gdispGImageDraw_PNG(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); delaytime_t gdispImageNext_PNG(gdispImage *img); /* @} */ #endif diff --git a/src/gdisp/image.c b/src/gdisp/image.c index 1e9ac3d6..62af0aeb 100644 --- a/src/gdisp/image.c +++ b/src/gdisp/image.c @@ -23,7 +23,8 @@ typedef struct gdispImageHandlers { gdispImageError (*open)(gdispImage *img); /* The open function */ void (*close)(gdispImage *img); /* The close function */ gdispImageError (*cache)(gdispImage *img); /* The cache function */ - gdispImageError (*draw)(gdispImage *img, + gdispImageError (*draw)(GDisplay *g, + gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); /* The draw function */ @@ -33,27 +34,27 @@ typedef struct gdispImageHandlers { static gdispImageHandlers ImageHandlers[] = { #if GDISP_NEED_IMAGE_NATIVE { gdispImageOpen_NATIVE, gdispImageClose_NATIVE, - gdispImageCache_NATIVE, gdispImageDraw_NATIVE, gdispImageNext_NATIVE, + gdispImageCache_NATIVE, gdispGImageDraw_NATIVE, gdispImageNext_NATIVE, }, #endif #if GDISP_NEED_IMAGE_GIF { gdispImageOpen_GIF, gdispImageClose_GIF, - gdispImageCache_GIF, gdispImageDraw_GIF, gdispImageNext_GIF, + gdispImageCache_GIF, gdispGImageDraw_GIF, gdispImageNext_GIF, }, #endif #if GDISP_NEED_IMAGE_BMP { gdispImageOpen_BMP, gdispImageClose_BMP, - gdispImageCache_BMP, gdispImageDraw_BMP, gdispImageNext_BMP, + gdispImageCache_BMP, gdispGImageDraw_BMP, gdispImageNext_BMP, }, #endif #if GDISP_NEED_IMAGE_JPG { gdispImageOpen_JPG, gdispImageClose_JPG, - gdispImageCache_JPG, gdispImageDraw_JPG, gdispImageNext_JPG, + gdispImageCache_JPG, gdispGImageDraw_JPG, gdispImageNext_JPG, }, #endif #if GDISP_NEED_IMAGE_PNG { gdispImageOpen_PNG, gdispImageClose_PNG, - gdispImageCache_PNG, gdispImageDraw_PNG, gdispImageNext_PNG, + gdispImageCache_PNG, gdispGImageDraw_PNG, gdispImageNext_PNG, }, #endif }; @@ -205,9 +206,9 @@ gdispImageError gdispImageCache(gdispImage *img) { return img->fns->cache(img); } -gdispImageError gdispImageDraw(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { +gdispImageError gdispGImageDraw(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { if (!img->fns) return GDISP_IMAGE_ERR_BADFORMAT; - return img->fns->draw(img, x, y, cx, cy, sx, sy); + return img->fns->draw(g, img, x, y, cx, cy, sx, sy); } delaytime_t gdispImageNext(gdispImage *img) { diff --git a/src/gdisp/image_bmp.c b/src/gdisp/image_bmp.c index e23d0fb1..158d6edc 100644 --- a/src/gdisp/image_bmp.c +++ b/src/gdisp/image_bmp.c @@ -828,7 +828,7 @@ gdispImageError gdispImageCache_BMP(gdispImage *img) { return GDISP_IMAGE_ERR_OK; } -gdispImageError gdispImageDraw_BMP(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { +gdispImageError gdispGImageDraw_BMP(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { gdispImagePrivate * priv; coord_t mx, my; coord_t pos, len, st; @@ -842,7 +842,7 @@ gdispImageError gdispImageDraw_BMP(gdispImage *img, coord_t x, coord_t y, coord_ /* Draw from the image cache - if it exists */ if (priv->frame0cache) { - gdispBlitAreaEx(x, y, cx, cy, sx, sy, img->width, priv->frame0cache); + gdispGBlitArea(g, x, y, cx, cy, sx, sy, img->width, priv->frame0cache); return GDISP_IMAGE_ERR_OK; } @@ -864,9 +864,9 @@ gdispImageError gdispImageDraw_BMP(gdispImage *img, coord_t x, coord_t y, coord_ len = pos-st; if (mx+st+len > sx+cx) len = sx+cx-mx-st; if (len == 1) - gdispDrawPixel(x+mx+st-sx, y+my-sy, priv->buf[st]); + gdispGDrawPixel(g, x+mx+st-sx, y+my-sy, priv->buf[st]); else - gdispBlitAreaEx(x+mx+st-sx, y+my-sy, len, 1, st, 0, pos, priv->buf); + gdispGBlitArea(g, x+mx+st-sx, y+my-sy, len, 1, st, 0, pos, priv->buf); } mx += pos; } @@ -882,9 +882,9 @@ gdispImageError gdispImageDraw_BMP(gdispImage *img, coord_t x, coord_t y, coord_ len = pos-st; if (mx+st+len > sx+cx) len = sx+cx-mx-st; if (len == 1) - gdispDrawPixel(x+mx+st-sx, y+my-sy, priv->buf[st]); + gdispGDrawPixel(g, x+mx+st-sx, y+my-sy, priv->buf[st]); else - gdispBlitAreaEx(x+mx+st-sx, y+my-sy, len, 1, st, 0, pos, priv->buf); + gdispGBlitArea(g, x+mx+st-sx, y+my-sy, len, 1, st, 0, pos, priv->buf); } mx += pos; } diff --git a/src/gdisp/image_gif.c b/src/gdisp/image_gif.c index d067bd0f..1ff72ff0 100644 --- a/src/gdisp/image_gif.c +++ b/src/gdisp/image_gif.c @@ -820,7 +820,7 @@ baddatacleanup: return GDISP_IMAGE_ERR_BADDATA; } -gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { +gdispImageError gdispGImageDraw_GIF(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { gdispImagePrivate * priv; imgdecode * decode; uint8_t * q = 0; @@ -847,9 +847,9 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // The spec says to restore the backgound color (priv->bgcolor) but in practice if there is transparency // image decoders tend to assume that a restore to the transparent color is required instead if (((priv->dispose.flags & GIFL_TRANSPARENT) /*&& priv->dispose.paltrans == priv->bgcolor*/) || priv->bgcolor >= priv->palsize) - gdispFillArea(x+mx-sx, y+my-sy, fx-mx, fy-my, img->bgcolor); + gdispGFillArea(g, x+mx-sx, y+my-sy, fx-mx, fy-my, img->bgcolor); else - gdispFillArea(x+mx-sx, y+my-sy, fx-mx, fy-my, priv->palette[priv->bgcolor]); + gdispGFillArea(g, x+mx-sx, y+my-sy, fx-mx, fy-my, priv->palette[priv->bgcolor]); } } @@ -881,23 +881,23 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have a transparent pixel - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } continue; } priv->buf[gcnt++] = cache->palette[col]; if (gcnt >= BLIT_BUFFER_SIZE) { // We have run out of buffer - dump it to the display - gdispBlitAreaEx(x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); + gdispGBlitArea(g, x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; } } // We have finished the line - dump the buffer to the display switch(gcnt) { - case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; + case 0: break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; } } @@ -935,15 +935,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have a transparent pixel - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } continue; } priv->buf[gcnt++] = decode->palette[col]; if (gcnt >= BLIT_BUFFER_SIZE) { // We have run out of buffer - dump it to the display - gdispBlitAreaEx(x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); + gdispGBlitArea(g, x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; } continue; @@ -951,15 +951,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have finished the visible area - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } } // We have finished the line - dump the buffer to the display switch(gcnt) { - case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; + case 0: break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; } } // Every 8th row starting at row 4 @@ -981,15 +981,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have a transparent pixel - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } continue; } priv->buf[gcnt++] = decode->palette[col]; if (gcnt >= BLIT_BUFFER_SIZE) { // We have run out of buffer - dump it to the display - gdispBlitAreaEx(x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); + gdispGBlitArea(g, x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; } continue; @@ -997,15 +997,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have finished the visible area - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } } // We have finished the line - dump the buffer to the display switch(gcnt) { - case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; + case 0: break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; } } // Every 4th row starting at row 2 @@ -1027,15 +1027,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have a transparent pixel - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } continue; } priv->buf[gcnt++] = decode->palette[col]; if (gcnt >= BLIT_BUFFER_SIZE) { // We have run out of buffer - dump it to the display - gdispBlitAreaEx(x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); + gdispGBlitArea(g, x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; } continue; @@ -1043,15 +1043,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have finished the visible area - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } } // We have finished the line - dump the buffer to the display switch(gcnt) { - case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; + case 0: break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; } } // Every 2nd row starting at row 1 @@ -1073,15 +1073,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have a transparent pixel - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } continue; } priv->buf[gcnt++] = decode->palette[col]; if (gcnt >= BLIT_BUFFER_SIZE) { // We have run out of buffer - dump it to the display - gdispBlitAreaEx(x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); + gdispGBlitArea(g, x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; } continue; @@ -1089,15 +1089,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have finished the visible area - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } } // We have finished the line - dump the buffer to the display switch(gcnt) { - case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; + case 0: break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; } } } else { @@ -1120,15 +1120,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have a transparent pixel - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } continue; } priv->buf[gcnt++] = decode->palette[col]; if (gcnt >= BLIT_BUFFER_SIZE) { // We have run out of buffer - dump it to the display - gdispBlitAreaEx(x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); + gdispGBlitArea(g, x+mx-sx-gcnt+1, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; } continue; @@ -1136,15 +1136,15 @@ gdispImageError gdispImageDraw_GIF(gdispImage *img, coord_t x, coord_t y, coord_ // We have finished the visible area - dump the buffer to the display switch(gcnt) { case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); gcnt = 0; break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); gcnt = 0; break; } } // We have finished the line - dump the buffer to the display switch(gcnt) { - case 0: break; - case 1: gdispDrawPixel(x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; - default: gdispBlitAreaEx(x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; + case 0: break; + case 1: gdispGDrawPixel(g, x+mx-sx-gcnt, y+my-sy, priv->buf[0]); break; + default: gdispGBlitArea(g, x+mx-sx-gcnt, y+my-sy, gcnt, 1, 0, 0, gcnt, priv->buf); break; } } } diff --git a/src/gdisp/image_native.c b/src/gdisp/image_native.c index 24aed81f..72ae8b61 100644 --- a/src/gdisp/image_native.c +++ b/src/gdisp/image_native.c @@ -91,7 +91,7 @@ gdispImageError gdispImageCache_NATIVE(gdispImage *img) { return GDISP_IMAGE_ERR_OK; } -gdispImageError gdispImageDraw_NATIVE(gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { +gdispImageError gdispImageGDraw_NATIVE(GDisplay *g, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { coord_t mx, mcx; size_t pos, len; @@ -102,7 +102,7 @@ gdispImageError gdispImageDraw_NATIVE(gdispImage *img, coord_t x, coord_t y, coo /* Draw from the image cache - if it exists */ if (img->priv->frame0cache) { - gdispBlitAreaEx(x, y, cx, cy, sx, sy, img->width, img->priv->frame0cache); + gdispGBlitArea(g, x, y, cx, cy, sx, sy, img->width, img->priv->frame0cache); return GDISP_IMAGE_ERR_OK; } @@ -125,7 +125,7 @@ gdispImageError gdispImageDraw_NATIVE(gdispImage *img, coord_t x, coord_t y, coo return GDISP_IMAGE_ERR_BADDATA; /* Blit the chunk of data */ - gdispBlitAreaEx(mx, y, len, 1, 0, 0, len, img->priv->buf); + gdispGBlitArea(g, mx, y, len, 1, 0, 0, len, img->priv->buf); } /* Get the position for the start of the next line */ From 7a7e223d152b42553f7e6ce0220dd5d736b89c56 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 24 Oct 2013 18:36:11 +1000 Subject: [PATCH 115/160] Add multiple display support to GWIN. You can now create windows on multiple displays. --- include/gwin/button.h | 4 +- include/gwin/checkbox.h | 4 +- include/gwin/class_gwin.h | 6 ++- include/gwin/console.h | 4 +- include/gwin/graph.h | 4 +- include/gwin/gwin.h | 5 +- include/gwin/image.h | 4 +- include/gwin/label.h | 4 +- include/gwin/list.h | 4 +- include/gwin/radio.h | 4 +- include/gwin/slider.h | 4 +- src/gwin/button.c | 66 +++++++++++++------------- src/gwin/checkbox.c | 20 ++++---- src/gwin/console.c | 16 +++---- src/gwin/gimage.c | 22 ++++----- src/gwin/graph.c | 20 ++++---- src/gwin/gwidget.c | 10 ++-- src/gwin/gwin.c | 99 ++++++++++++++++++++------------------- src/gwin/gwm.c | 22 ++++----- src/gwin/label.c | 16 +++---- src/gwin/list.c | 26 +++++----- src/gwin/radio.c | 34 +++++++------- src/gwin/slider.c | 48 +++++++++---------- 23 files changed, 237 insertions(+), 209 deletions(-) diff --git a/include/gwin/button.h b/include/gwin/button.h index 13b135a3..d11764d6 100644 --- a/include/gwin/button.h +++ b/include/gwin/button.h @@ -59,6 +59,7 @@ extern "C" { * @brief Create a button widget. * @return NULL if there is no resultant drawing area, otherwise a window handle. * + * @param[in] g The GDisplay to display this window on * @param[in] gb The GButtonObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] pInit The initialisation parameters * @@ -74,7 +75,8 @@ extern "C" { * * @api */ -GHandle gwinButtonCreate(GButtonObject *gb, const GWidgetInit *pInit); +GHandle gwinGButtonCreate(GDisplay *g, GButtonObject *gb, const GWidgetInit *pInit); +#define gwinButtonCreate(gb, pInit) gwinGButtonCreate(GDISP, gb, pInit) /** * @brief Is the button current pressed diff --git a/include/gwin/checkbox.h b/include/gwin/checkbox.h index 29ebe96e..946f7e4a 100644 --- a/include/gwin/checkbox.h +++ b/include/gwin/checkbox.h @@ -52,6 +52,7 @@ typedef struct GCheckboxObject { * @brief Create a checkbox window. * @return NULL if there is no resultant drawing area, otherwise a window handle. * + * @param[in] g The GDisplay to display this window on * @param[in] gb The GCheckboxObject structure to initialise. If this is NULL, the structure is dynamically allocated. * @param[in] pInit The initialization parameters to use * @@ -67,7 +68,8 @@ typedef struct GCheckboxObject { * * @api */ -GHandle gwinCheckboxCreate(GCheckboxObject *gb, const GWidgetInit *pInit); +GHandle gwinGCheckboxCreate(GDisplay *g, GCheckboxObject *gb, const GWidgetInit *pInit); +#define gwinCheckboxCreate(gb, pInit) gwinGCheckboxCreate(GDISP, gb, pInit) /** * @brief Set the state of a checkbox diff --git a/include/gwin/class_gwin.h b/include/gwin/class_gwin.h index b3f630e3..62b1752e 100644 --- a/include/gwin/class_gwin.h +++ b/include/gwin/class_gwin.h @@ -150,6 +150,7 @@ extern "C" { /** * @brief Initialise (and allocate if necessary) the base GWIN object * + * @param[in] g The GDisplay to use for this window * @param[in] pgw The GWindowObject structure. If NULL one is allocated from the heap * @param[in] pInit The user initialization parameters * @param[in] vmt The virtual method table for the GWIN object @@ -159,12 +160,13 @@ extern "C" { * * @notapi */ -GHandle _gwindowCreate(GWindowObject *pgw, const GWindowInit *pInit, const gwinVMT *vmt, uint16_t flags); +GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit, const gwinVMT *vmt, uint16_t flags); #if GWIN_NEED_WIDGET || defined(__DOXYGEN__) /** * @brief Initialise (and allocate if necessary) the base Widget object * + * @param[in] g The GDisplay to display this window on * @param[in] pgw The GWidgetObject structure. If NULL one is allocated from the heap * @param[in] pInit The user initialization parameters * @param[in] vmt The virtual method table for the Widget object @@ -173,7 +175,7 @@ GHandle _gwindowCreate(GWindowObject *pgw, const GWindowInit *pInit, const gwinV * * @notapi */ - GHandle _gwidgetCreate(GWidgetObject *pgw, const GWidgetInit *pInit, const gwidgetVMT *vmt); + GHandle _gwidgetCreate(GDisplay *g, GWidgetObject *pgw, const GWidgetInit *pInit, const gwidgetVMT *vmt); /** * @brief Destroy the Widget object diff --git a/include/gwin/console.h b/include/gwin/console.h index c05c4ad2..ed65581e 100644 --- a/include/gwin/console.h +++ b/include/gwin/console.h @@ -50,6 +50,7 @@ extern "C" { * @note Text in a console window supports newlines and will wrap text as required. * @return NULL if there is no resultant drawing area, otherwise a window handle. * + * @param[in] g The GDisplay to display this window on * @param[in] gc The GConsoleObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] pInit The initialization parameters to use * @@ -64,7 +65,8 @@ extern "C" { * * @api */ -GHandle gwinConsoleCreate(GConsoleObject *gc, const GWindowInit *pInit); +GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *pInit); +#define gwinConsoleCreate(gc, pInit) gwinGConsoleCreate(GDISP, gc, pInit) #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM /** diff --git a/include/gwin/graph.h b/include/gwin/graph.h index fd99458d..65a64126 100644 --- a/include/gwin/graph.h +++ b/include/gwin/graph.h @@ -90,6 +90,7 @@ extern "C" { * @brief Create a graph window. * @return NULL if there is no resultant drawing area, otherwise a window handle. * + * @param[in] g The GDisplay to display this window on * @param[in] gg The GGraphObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] pInit The initialization parameters to use * @@ -107,7 +108,8 @@ extern "C" { * * @api */ -GHandle gwinGraphCreate(GGraphObject *gg, const GWindowInit *pInit); +GHandle gwinGGraphCreate(GDisplay *g, GGraphObject *gg, const GWindowInit *pInit); +#define gwinGraphCreate(gg, pInit) gwinGGraphCreate(GDISP, gg, pInit) /** * @brief Set the style of the graphing operations. diff --git a/include/gwin/gwin.h b/include/gwin/gwin.h index 372ece9c..37a14fa1 100644 --- a/include/gwin/gwin.h +++ b/include/gwin/gwin.h @@ -38,6 +38,7 @@ typedef struct GWindowObject { gfxQueueASyncItem wmq; // @< The next window (for the window manager) #endif const struct gwinVMT *vmt; // @< The VMT for this GWIN + GDisplay * display; // @< The display this window is on. coord_t x, y; // @< Screen relative position coord_t width, height; // @< Dimensions of this window color_t color, bgcolor; // @< The current drawing colors @@ -165,6 +166,7 @@ extern "C" { * @brief Create a basic window. * @return NULL if there is no resultant drawing area, otherwise a window handle. * + * @param[in] g The GDisplay to display this window on * @param[in] pgw The window structure to initialize. If this is NULL the structure is dynamically allocated. * @param[in] pInit How to initialise the window * @@ -177,7 +179,8 @@ extern "C" { * * @api */ - GHandle gwinWindowCreate(GWindowObject *pgw, const GWindowInit *pInit); + GHandle gwinGWindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit); + #define gwinWindowCreate(pgw, pInit) gwinGWindowCreate(GDISP, pgw, pInit); /** * @brief Destroy a window (of any type). Releases any dynamically allocated memory. diff --git a/include/gwin/image.h b/include/gwin/image.h index eae196e9..66dd0b94 100644 --- a/include/gwin/image.h +++ b/include/gwin/image.h @@ -47,6 +47,7 @@ extern "C" { * @details Display's a picture. * @return NULL if there is no resultant drawing area, otherwise the widget handle. * + * @param[in] g The GDisplay to display this window on * @param[in] widget The image widget structure to initialise. If this is NULL, the structure is dynamically allocated. * @param[in] pInit The initialization parameters to use. * @@ -55,7 +56,8 @@ extern "C" { * * @api */ -GHandle gwinImageCreate(GImageObject *widget, GWindowInit *pInit); +GHandle gwinGImageCreate(GDisplay *g, GImageObject *widget, GWindowInit *pInit); +#define gwinImageCreate(w, pInit) gwinGImageCreate(GDISP, w, pInit) /** * @brief Sets the input routines that support reading the image from memory diff --git a/include/gwin/label.h b/include/gwin/label.h index 3156ca71..3fe0f3d7 100644 --- a/include/gwin/label.h +++ b/include/gwin/label.h @@ -42,6 +42,7 @@ extern "C" { * @brief Create a label widget. * @details A label widget is a simple window which has a static text. * + * @param[in] g The GDisplay to display this window on * @param[in] widget The label structure to initialise. If this is NULL, the structure is dynamically allocated. * @param[in] pInit The initialisation parameters to use. * @@ -49,7 +50,8 @@ extern "C" { * * @api */ -GHandle gwinLabelCreate(GLabelObject *widget, GWidgetInit *pInit); +GHandle gwinGLabelCreate(GDisplay *g, GLabelObject *widget, GWidgetInit *pInit); +#define gwinLabelCreate(w, pInit) gwinGLabelCreate(GDISP, w, pInit) /** * @brief Border settings for the default rendering routine diff --git a/include/gwin/list.h b/include/gwin/list.h index b45e7767..4052f53f 100644 --- a/include/gwin/list.h +++ b/include/gwin/list.h @@ -82,6 +82,7 @@ extern "C" { * one toggle to a role, it will forget the previous toggle. Two roles are supported: * Role 0 = toggle for down, role 1 = toggle for up * + * @param[in] g The GDisplay to display this window on * @param[in] widget The GListObject structure to initialize. If this is NULL, the structure is dynamically allocated. * @param[in] pInit The initialization parameters to use * @param[in] multiselect If TRUE the list is multi-select instead of single-select. @@ -90,7 +91,8 @@ extern "C" { * * @api */ -GHandle gwinListCreate(GListObject *widget, GWidgetInit *pInit, bool_t multiselect); +GHandle gwinGListCreate(GDisplay *g, GListObject *widget, GWidgetInit *pInit, bool_t multiselect); +#define gwinListCreate(w, pInit, m) gwinGListCreate(GDISP, w, pInit, m) /** * @brief Change the behaviour of the scroll bar diff --git a/include/gwin/radio.h b/include/gwin/radio.h index e59c526e..3ee2918f 100644 --- a/include/gwin/radio.h +++ b/include/gwin/radio.h @@ -59,6 +59,7 @@ extern "C" { * @brief Create a radio widget. * @return NULL if there is no resultant drawing area, otherwise a window handle. * + * @param[in] g The GDisplay to display this window on * @param[in] gb The GRadioObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] pInit The initialisation parameters * @param[in] group The group of radio buttons this radio button belongs to. @@ -77,7 +78,8 @@ extern "C" { * * @api */ -GHandle gwinRadioCreate(GRadioObject *gb, const GWidgetInit *pInit, uint16_t group); +GHandle gwinGRadioCreate(GDisplay *g, GRadioObject *gb, const GWidgetInit *pInit, uint16_t group); +#define gwinRadioCreate(w, pInit, gr) gwinGRadioCreate(GDISP, w, pInit, gr) /** * @brief Press this radio button (and by definition unset any others in the group) diff --git a/include/gwin/slider.h b/include/gwin/slider.h index b037a621..8f87745c 100644 --- a/include/gwin/slider.h +++ b/include/gwin/slider.h @@ -58,6 +58,7 @@ extern "C" { * @brief Create a slider window. * @return NULL if there is no resultant drawing area, otherwise a window handle. * + * @param[in] g The GDisplay to display this window on * @param[in] gb The GSliderObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] pInit The initialization parameters to use * @@ -77,7 +78,8 @@ extern "C" { * * @api */ -GHandle gwinSliderCreate(GSliderObject *gb, const GWidgetInit *pInit); +GHandle gwinGSliderCreate(GDisplay *g, GSliderObject *gb, const GWidgetInit *pInit); +#define gwinSliderCreate(w, pInit) gwinGSliderCreate(GDISP, w, pInit) /** * @brief Set the slider range. diff --git a/src/gwin/button.c b/src/gwin/button.c index 4e4e67ee..b0fd973a 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -136,8 +136,8 @@ static const gwidgetVMT buttonVMT = { #endif }; -GHandle gwinButtonCreate(GButtonObject *gw, const GWidgetInit *pInit) { - if (!(gw = (GButtonObject *)_gwidgetCreate(&gw->w, pInit, &buttonVMT))) +GHandle gwinGButtonCreate(GDisplay *g, GButtonObject *gw, const GWidgetInit *pInit) { + if (!(gw = (GButtonObject *)_gwidgetCreate(g, &gw->w, pInit, &buttonVMT))) return 0; #if GINPUT_NEED_TOGGLE @@ -171,9 +171,9 @@ void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; pcol = getDrawColors(gw); - gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); - gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); - gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); + gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); } #if GDISP_NEED_ARC @@ -184,14 +184,14 @@ void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; pcol = getDrawColors(gw); - gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); if (gw->g.width >= 2*RND_CNR_SIZE+10) { - gdispFillRoundedBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, RND_CNR_SIZE-1, pcol->fill); - gdispDrawStringBox(gw->g.x+1, gw->g.y+RND_CNR_SIZE, gw->g.width-2, gw->g.height-(2*RND_CNR_SIZE), gw->text, gw->g.font, pcol->text, justifyCenter); - gdispDrawRoundedBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, RND_CNR_SIZE, pcol->edge); + gdispGFillRoundedBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, RND_CNR_SIZE-1, pcol->fill); + gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+RND_CNR_SIZE, gw->g.width-2, gw->g.height-(2*RND_CNR_SIZE), gw->text, gw->g.font, pcol->text, justifyCenter); + gdispGDrawRoundedBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, RND_CNR_SIZE, pcol->edge); } else { - gdispFillStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); - gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); + gdispGFillStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); } } #endif @@ -204,10 +204,10 @@ void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; pcol = getDrawColors(gw); - gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); - gdispFillEllipse(gw->g.x+1, gw->g.y+1, gw->g.width/2-1, gw->g.height/2-1, pcol->fill); - gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); - gdispDrawEllipse(gw->g.x, gw->g.y, gw->g.width/2, gw->g.height/2, pcol->edge); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + gdispGFillEllipse(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width/2-1, gw->g.height/2-1, pcol->fill); + gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); + gdispGDrawEllipse(gw->g.display, gw->g.x, gw->g.y, gw->g.width/2, gw->g.height/2, pcol->edge); } #endif @@ -228,10 +228,10 @@ void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { arw[5].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[5].y = gw->g.height/ARROWHEAD_DIVIDER; arw[6].x = 0; arw[6].y = gw->g.height/ARROWHEAD_DIVIDER; - gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); - gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill); - gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge); - gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + gdispGFillConvexPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->fill); + gdispGDrawPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->edge); + gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } void gwinButtonDraw_ArrowDown(GWidgetObject *gw, void *param) { @@ -250,10 +250,10 @@ void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { arw[5].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[5].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER; arw[6].x = 0; arw[6].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER; - gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); - gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill); - gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge); - gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + gdispGFillConvexPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->fill); + gdispGDrawPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->edge); + gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } void gwinButtonDraw_ArrowLeft(GWidgetObject *gw, void *param) { @@ -272,10 +272,10 @@ void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { arw[5].x = gw->g.width/ARROWHEAD_DIVIDER; arw[5].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2; arw[6].x = gw->g.width/ARROWHEAD_DIVIDER; arw[6].y = gw->g.height-1; - gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); - gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill); - gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge); - gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + gdispGFillConvexPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->fill); + gdispGDrawPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->edge); + gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } void gwinButtonDraw_ArrowRight(GWidgetObject *gw, void *param) { @@ -294,10 +294,10 @@ void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { arw[5].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[5].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2; arw[6].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[6].y = gw->g.height-1; - gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); - gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill); - gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge); - gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + gdispGFillConvexPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->fill); + gdispGDrawPoly(gw->g.display, gw->g.x, gw->g.y, arw, 7, pcol->edge); + gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } #endif @@ -317,8 +317,8 @@ void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { sy = 0; } - gdispImageDraw((gdispImage *)param, gw->g.x, gw->g.y, gw->g.width, gw->g.height, 0, sy); - gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); + gdispGImageDraw(gw->g.display, (gdispImage *)param, gw->g.x, gw->g.y, gw->g.width, gw->g.height, 0, sy); + gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } #endif diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c index 7a6198de..13730d50 100644 --- a/src/gwin/checkbox.c +++ b/src/gwin/checkbox.c @@ -108,8 +108,8 @@ static const gwidgetVMT checkboxVMT = { #endif }; -GHandle gwinCheckboxCreate(GCheckboxObject *gb, const GWidgetInit *pInit) { - if (!(gb = (GCheckboxObject *)_gwidgetCreate(&gb->w, pInit, &checkboxVMT))) +GHandle gwinGCheckboxCreate(GDisplay *g, GCheckboxObject *gb, const GWidgetInit *pInit) { + if (!(gb = (GCheckboxObject *)_gwidgetCreate(g, &gb->w, pInit, &checkboxVMT))) return 0; #if GINPUT_NEED_TOGGLE @@ -161,14 +161,14 @@ void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param) { pcol = getDrawColors(gw); ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height; - gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gw->pstyle->background); - gdispDrawBox(gw->g.x, gw->g.y, ld, ld, pcol->edge); + gdispGFillArea(gw->g.display, gw->g.x+1, gw->g.y+1, ld, ld-2, gw->pstyle->background); + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, ld, ld, pcol->edge); df = ld < 4 ? 1 : 2; if (gw->g.flags & GCHECKBOX_FLG_CHECKED) - gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill); + gdispGFillArea(gw->g.display, gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill); - gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyLeft); + gdispGFillStringBox(gw->g.display, gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyLeft); #undef gcw } @@ -183,14 +183,14 @@ void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) { ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height; ep = gw->g.width-ld-1; - gdispFillArea(gw->g.x+ep-1, gw->g.y+1, ld, ld-2, gw->pstyle->background); - gdispDrawBox(gw->g.x+ep, gw->g.y, ld, ld, pcol->edge); + gdispGFillArea(gw->g.display, gw->g.x+ep-1, gw->g.y+1, ld, ld-2, gw->pstyle->background); + gdispGDrawBox(gw->g.display, gw->g.x+ep, gw->g.y, ld, ld, pcol->edge); df = ld < 4 ? 1 : 2; if (gw->g.flags & GCHECKBOX_FLG_CHECKED) - gdispFillArea(gw->g.x+ep+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill); + gdispGFillArea(gw->g.display, gw->g.x+ep+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill); - gdispFillStringBox(gw->g.x, gw->g.y, ep-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyRight); + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, ep-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyRight); #undef gcw } diff --git a/src/gwin/console.c b/src/gwin/console.c index b6a20dea..1be18662 100644 --- a/src/gwin/console.c +++ b/src/gwin/console.c @@ -66,8 +66,8 @@ static const gwinVMT consoleVMT = { AfterClear, // The after-clear routine }; -GHandle gwinConsoleCreate(GConsoleObject *gc, const GWindowInit *pInit) { - if (!(gc = (GConsoleObject *)_gwindowCreate(&gc->g, pInit, &consoleVMT, 0))) +GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *pInit) { + if (!(gc = (GConsoleObject *)_gwindowCreate(g, &gc->g, pInit, &consoleVMT, 0))) return 0; #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM gc->stream.vmt = &GWindowConsoleVMT; @@ -97,7 +97,7 @@ void gwinPutChar(GHandle gh, char c) { fp = gdispGetFontMetric(gh->font, fontCharPadding); #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif if (c == '\n') { @@ -116,13 +116,13 @@ void gwinPutChar(GHandle gh, char c) { if (gcw->cy + fy > gh->height) { #if GDISP_NEED_SCROLL /* scroll the console */ - gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, fy, gh->bgcolor); + gdispGVerticalScroll(gh->display, gh->x, gh->y, gh->width, gh->height, fy, gh->bgcolor); /* reset the cursor to the start of the last line */ gcw->cx = 0; gcw->cy = (((coord_t)(gh->height/fy))-1)*fy; #else /* clear the console */ - gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); /* reset the cursor to the top of the window */ gcw->cx = 0; gcw->cy = 0; @@ -132,12 +132,12 @@ void gwinPutChar(GHandle gh, char c) { #if GWIN_CONSOLE_USE_CLEAR_LINES /* clear to the end of the line */ if (gcw->cx == 0) - gdispFillArea(gh->x, gh->y + gcw->cy, gh->width, fy, gh->bgcolor); + gdispGFillArea(gh->display, gh->x, gh->y + gcw->cy, gh->width, fy, gh->bgcolor); #endif #if GWIN_CONSOLE_USE_FILLED_CHARS - gdispFillChar(gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color, gh->bgcolor); + gdispGFillChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color, gh->bgcolor); #else - gdispDrawChar(gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color); + gdispGDrawChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color); #endif /* update cursor */ diff --git a/src/gwin/gimage.c b/src/gwin/gimage.c index 8eed3ac7..b1f8e078 100644 --- a/src/gwin/gimage.c +++ b/src/gwin/gimage.c @@ -51,7 +51,7 @@ static void _redraw(GHandle gh) { // If the image isn't open just clear the area if (!gdispImageIsOpen(&widget(gh)->image)) { - gdispFillArea(x, y, w, h, bg); + gdispGFillArea(gh->display, x, y, w, h, bg); return; } @@ -61,8 +61,8 @@ static void _redraw(GHandle gh) { dx = (gh->width-w)/2; x += dx; if (dx) - gdispFillArea(gh->x, y, dx, h, bg); - gdispFillArea(x+w, y, gh->width-dx-w, h, bg); + gdispGFillArea(gh->display, gh->x, y, dx, h, bg); + gdispGFillArea(gh->display, x+w, y, gh->width-dx-w, h, bg); dx = 0; } @@ -77,8 +77,8 @@ static void _redraw(GHandle gh) { dy = (gh->height-h)/2; y += dy; if (dy) - gdispFillArea(x, gh->y, w, dy, bg); - gdispFillArea(x, y+h, w, gh->height-dy-h, bg); + gdispGFillArea(gh->display, x, gh->y, w, dy, bg); + gdispGFillArea(gh->display, x, y+h, w, gh->height-dy-h, bg); dy = 0; } @@ -91,7 +91,7 @@ static void _redraw(GHandle gh) { gdispImageSetBgColor(&widget(gh)->image, bg); // Display the image - gdispImageDraw(&widget(gh)->image, x, y, w, h, dx, dy); + gdispGImageDraw(gh->display, &widget(gh)->image, x, y, w, h, dx, dy); #if GWIN_NEED_IMAGE_ANIMATION // read the delay for the next frame @@ -122,8 +122,8 @@ static const gwinVMT imageVMT = { 0, // The after-clear routine }; -GHandle gwinImageCreate(GImageObject *gobj, GWindowInit *pInit) { - if (!(gobj = (GImageObject *)_gwindowCreate(&gobj->g, pInit, &imageVMT, 0))) +GHandle gwinGImageCreate(GDisplay *g, GImageObject *gobj, GWindowInit *pInit) { + if (!(gobj = (GImageObject *)_gwindowCreate(g, &gobj->g, pInit, &imageVMT, 0))) return 0; // Ensure the gdispImageIsOpen() gives valid results @@ -153,7 +153,7 @@ bool_t gwinImageOpenMemory(GHandle gh, const void* memory) { // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw // but we put it in for safety anyway #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif _redraw(gh); } @@ -176,7 +176,7 @@ bool_t gwinImageOpenFile(GHandle gh, const char* filename) { // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw // but we put it in for safety anyway #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif _redraw(gh); } @@ -200,7 +200,7 @@ bool_t gwinImageOpenStream(GHandle gh, void *streamPtr) { // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw // but we put it in for safety anyway #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif _redraw(gh); } diff --git a/src/gwin/graph.c b/src/gwin/graph.c index 8cab05a4..1d513290 100644 --- a/src/gwin/graph.c +++ b/src/gwin/graph.c @@ -46,22 +46,22 @@ static void pointto(GGraphObject *gg, coord_t x, coord_t y, const GGraphPointSty y = gg->g.y + gg->g.height - 1 - gg->yorigin - y; if (style->size <= 1) { - gdispDrawPixel(x, y, style->color); + gdispGDrawPixel(gg->g.display, x, y, style->color); return; } switch(style->type) { case GGRAPH_POINT_SQUARE: - gdispDrawBox(x-style->size, y-style->size, 2*style->size, 2*style->size, style->color); + gdispGDrawBox(gg->g.display, x-style->size, y-style->size, 2*style->size, 2*style->size, style->color); break; #if GDISP_NEED_CIRCLE case GGRAPH_POINT_CIRCLE: - gdispDrawCircle(x, y, style->size, style->color); + gdispGDrawCircle(gg->g.display, x, y, style->size, style->color); break; #endif case GGRAPH_POINT_DOT: default: - gdispDrawPixel(x, y, style->color); + gdispGDrawPixel(gg->g.display, x, y, style->color); break; } } @@ -83,7 +83,7 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t if (style->size <= 0) { // Use the driver to draw a solid line - gdispDrawLine(x0, y0, x1, y1, style->color); + gdispGDrawLine(gg->g.display, x0, y0, x1, y1, style->color); return; } @@ -101,7 +101,7 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t case GGRAPH_LINE_SOLID: default: // Use the driver to draw a solid line - gdispDrawLine(x0, y0, x1, y1, style->color); + gdispGDrawLine(gg->g.display, x0, y0, x1, y1, style->color); return; } @@ -131,7 +131,7 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t if (run++ >= 0) { if (run >= run_on) run = run_off; - gdispDrawPixel(x0, y0, style->color); + gdispGDrawPixel(gg->g.display, x0, y0, style->color); } if (P < 0) { P += dy; @@ -151,7 +151,7 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t if (run++ >= 0) { if (run >= run_on) run = run_off; - gdispDrawPixel(x0, y0, style->color); + gdispGDrawPixel(gg->g.display, x0, y0, style->color); } if (P < 0) { P += dx; @@ -165,8 +165,8 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t } } -GHandle gwinGraphCreate(GGraphObject *gg, const GWindowInit *pInit) { - if (!(gg = (GGraphObject *)_gwindowCreate(&gg->g, pInit, &graphVMT, 0))) +GHandle gwinGGraphCreate(GDisplay *g, GGraphObject *gg, const GWindowInit *pInit) { + if (!(gg = (GGraphObject *)_gwindowCreate(g, &gg->g, pInit, &graphVMT, 0))) return 0; gg->xorigin = gg->yorigin = 0; gg->lastx = gg->lasty = 0; diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c index 111777a2..db9dc9fa 100644 --- a/src/gwin/gwidget.c +++ b/src/gwin/gwidget.c @@ -102,6 +102,10 @@ static void gwidgetEvent(void *param, GEvent *pe) { // Cycle through all windows for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + // check if the widget matches this display + if (gh->display != pme->display) + continue; + // check if it a widget that is enabled and visible if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) continue; @@ -225,8 +229,8 @@ void _gwidgetInit(void) { geventRegisterCallback(&gl, gwidgetEvent, 0); } -GHandle _gwidgetCreate(GWidgetObject *pgw, const GWidgetInit *pInit, const gwidgetVMT *vmt) { - if (!(pgw = (GWidgetObject *)_gwindowCreate(&pgw->g, &pInit->g, &vmt->g, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED))) +GHandle _gwidgetCreate(GDisplay *g, GWidgetObject *pgw, const GWidgetInit *pInit, const gwidgetVMT *vmt) { + if (!(pgw = (GWidgetObject *)_gwindowCreate(g, &pgw->g, &pInit->g, &vmt->g, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED))) return 0; pgw->text = pInit->text ? pInit->text : ""; @@ -281,7 +285,7 @@ void _gwidgetRedraw(GHandle gh) { return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif gw->fnDraw(gw, gw->fnParam); diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index 44d4143c..bb425e0f 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -90,7 +90,7 @@ void _gwinInit(void) { // Internal routine for use by GWIN components only // Initialise a window creating it dynamically if required. -GHandle _gwindowCreate(GWindowObject *pgw, const GWindowInit *pInit, const gwinVMT *vmt, uint16_t flags) { +GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit, const gwinVMT *vmt, uint16_t flags) { // Allocate the structure if necessary if (!pgw) { if (!(pgw = (GWindowObject *)gfxAlloc(vmt->size))) @@ -100,6 +100,7 @@ GHandle _gwindowCreate(GWindowObject *pgw, const GWindowInit *pInit, const gwinV pgw->flags = flags; // Initialise all basic fields + pgw->display = g; pgw->vmt = vmt; pgw->color = defaultFgColor; pgw->bgcolor = defaultBgColor; @@ -154,8 +155,8 @@ color_t gwinGetDefaultBgColor(void) { * The GWindow Routines *-----------------------------------------------*/ -GHandle gwinWindowCreate(GWindowObject *pgw, const GWindowInit *pInit) { - if (!(pgw = _gwindowCreate(pgw, pInit, &basegwinVMT, 0))) +GHandle gwinGWindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit) { + if (!(pgw = _gwindowCreate(g, pgw, pInit, &basegwinVMT, 0))) return 0; gwinSetVisible(pgw, pInit->show); return pgw; @@ -213,7 +214,7 @@ void gwinSetEnabled(GHandle gh, bool_t enabled) { gh->flags |= GWIN_FLG_ENABLED; if ((gh->flags & GWIN_FLG_VISIBLE) && gh->vmt->Redraw) { #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif gh->vmt->Redraw(gh); } @@ -223,7 +224,7 @@ void gwinSetEnabled(GHandle gh, bool_t enabled) { gh->flags &= ~GWIN_FLG_ENABLED; if ((gh->flags & GWIN_FLG_VISIBLE) && gh->vmt->Redraw) { #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif gh->vmt->Redraw(gh); } @@ -271,9 +272,9 @@ void gwinClear(GHandle gh) { return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); if (gh->vmt->AfterClear) gh->vmt->AfterClear(gh); } @@ -283,9 +284,9 @@ void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawPixel(gh->x+x, gh->y+y, gh->color); + gdispGDrawPixel(gh->display, gh->x+x, gh->y+y, gh->color); } void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) { @@ -293,9 +294,9 @@ void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) { return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawLine(gh->x+x0, gh->y+y0, gh->x+x1, gh->y+y1, gh->color); + gdispGDrawLine(gh->display, gh->x+x0, gh->y+y0, gh->x+x1, gh->y+y1, gh->color); } void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { @@ -303,9 +304,9 @@ void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawBox(gh->x+x, gh->y+y, cx, cy, gh->color); + gdispGDrawBox(gh->display, gh->x+x, gh->y+y, cx, cy, gh->color); } void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { @@ -313,9 +314,9 @@ void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispFillArea(gh->x+x, gh->y+y, cx, cy, gh->color); + gdispGFillArea(gh->display, gh->x+x, gh->y+y, cx, cy, gh->color); } void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { @@ -323,9 +324,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispBlitAreaEx(gh->x+x, gh->y+y, cx, cy, srcx, srcy, srccx, buffer); + gdispGBlitArea(gh->display, gh->x+x, gh->y+y, cx, cy, srcx, srcy, srccx, buffer); } #if GDISP_NEED_CIRCLE @@ -334,9 +335,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawCircle(gh->x+x, gh->y+y, radius, gh->color); + gdispGDrawCircle(gh->display, gh->x+x, gh->y+y, radius, gh->color); } void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) { @@ -344,9 +345,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispFillCircle(gh->x+x, gh->y+y, radius, gh->color); + gdispGFillCircle(gh->display, gh->x+x, gh->y+y, radius, gh->color); } #endif @@ -356,9 +357,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawEllipse(gh->x+x, gh->y+y, a, b, gh->color); + gdispGDrawEllipse(gh->display, gh->x+x, gh->y+y, a, b, gh->color); } void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) { @@ -366,9 +367,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispFillEllipse(gh->x+x, gh->y+y, a, b, gh->color); + gdispGFillEllipse(gh->display, gh->x+x, gh->y+y, a, b, gh->color); } #endif @@ -378,9 +379,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawArc(gh->x+x, gh->y+y, radius, startangle, endangle, gh->color); + gdispGDrawArc(gh->display, gh->x+x, gh->y+y, radius, startangle, endangle, gh->color); } void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) { @@ -388,9 +389,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispFillArc(gh->x+x, gh->y+y, radius, startangle, endangle, gh->color); + gdispGFillArc(gh->display, gh->x+x, gh->y+y, radius, startangle, endangle, gh->color); } #endif @@ -400,9 +401,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return defaultBgColor; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - return gdispGetPixelColor(gh->x+x, gh->y+y); + return gdispGGetPixelColor(gh->display, gh->x+x, gh->y+y); } #endif @@ -412,9 +413,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawChar(gh->x+x, gh->y+y, c, gh->font, gh->color); + gdispGDrawChar(gh->display, gh->x+x, gh->y+y, c, gh->font, gh->color); } void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c) { @@ -422,9 +423,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispFillChar(gh->x+x, gh->y+y, c, gh->font, gh->color, gh->bgcolor); + gdispGFillChar(gh->display, gh->x+x, gh->y+y, c, gh->font, gh->color, gh->bgcolor); } void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str) { @@ -432,9 +433,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawString(gh->x+x, gh->y+y, str, gh->font, gh->color); + gdispGDrawString(gh->display, gh->x+x, gh->y+y, str, gh->font, gh->color); } void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str) { @@ -442,9 +443,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispFillString(gh->x+x, gh->y+y, str, gh->font, gh->color, gh->bgcolor); + gdispGFillString(gh->display, gh->x+x, gh->y+y, str, gh->font, gh->color, gh->bgcolor); } void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) { @@ -452,9 +453,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawStringBox(gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, justify); + gdispGDrawStringBox(gh->display, gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, justify); } void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) { @@ -462,9 +463,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispFillStringBox(gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, gh->bgcolor, justify); + gdispGFillStringBox(gh->display, gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, gh->bgcolor, justify); } #endif @@ -474,9 +475,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispDrawPoly(tx+gh->x, ty+gh->y, pntarray, cnt, gh->color); + gdispGDrawPoly(gh->display, tx+gh->x, ty+gh->y, pntarray, cnt, gh->color); } void gwinFillConvexPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) { @@ -484,9 +485,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gdispFillConvexPoly(tx+gh->x, ty+gh->y, pntarray, cnt, gh->color); + gdispGFillConvexPoly(gh->display, tx+gh->x, ty+gh->y, pntarray, cnt, gh->color); } #endif @@ -496,9 +497,9 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor return GDISP_IMAGE_ERR_OK; #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - return gdispImageDraw(img, gh->x+x, gh->y+y, cx, cy, sx, sy); + return gdispGImageDraw(gh->display, img, gh->x+x, gh->y+y, cx, cy, sx, sy); } #endif diff --git a/src/gwin/gwm.c b/src/gwin/gwm.c index a8654089..d05a8177 100644 --- a/src/gwin/gwm.c +++ b/src/gwin/gwm.c @@ -119,7 +119,7 @@ static void WM_Delete(GHandle gh) { // Make the window invisible and clear the area underneath if ((gh->flags & GWIN_FLG_VISIBLE)) { gh->flags &= ~GWIN_FLG_VISIBLE; - gdispFillArea(gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); } // Remove it from the queue @@ -128,16 +128,16 @@ static void WM_Delete(GHandle gh) { static void WM_Visible(GHandle gh) { #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif if ((gh->flags & GWIN_FLG_VISIBLE)) { if (gh->vmt->Redraw) gh->vmt->Redraw(gh); else - gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); // A real window manager would also redraw the borders here } else - gdispFillArea(gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); } static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h) { @@ -145,12 +145,12 @@ static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h) { // If it won't fit on the screen move it around until it does. if (x < 0) { w += x; x = 0; } if (y < 0) { h += y; y = 0; } - if (x > gdispGetWidth()-MIN_WIN_WIDTH) x = gdispGetWidth()-MIN_WIN_WIDTH; - if (y > gdispGetHeight()-MIN_WIN_HEIGHT) y = gdispGetHeight()-MIN_WIN_HEIGHT; + if (x > gdispGGetWidth(gh->display)-MIN_WIN_WIDTH) x = gdispGGetWidth(gh->display)-MIN_WIN_WIDTH; + if (y > gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT) y = gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT; if (w < MIN_WIN_WIDTH) { w = MIN_WIN_WIDTH; } if (h < MIN_WIN_HEIGHT) { h = MIN_WIN_HEIGHT; } - if (x+w > gdispGetWidth()) w = gdispGetWidth() - x; - if (y+h > gdispGetHeight()) h = gdispGetHeight() - y; + if (x+w > gdispGGetWidth(gh->display)) w = gdispGGetWidth(gh->display) - x; + if (y+h > gdispGGetHeight(gh->display)) h = gdispGGetHeight(gh->display) - y; // If there has been no resize just exit if (gh->x == x && gh->y == y && gh->width == w && gh->height == h) @@ -158,7 +158,7 @@ static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h) { // Clear the old area if ((gh->flags & GWIN_FLG_VISIBLE)) - gdispFillArea(gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); // Set the new size gh->x = x; gh->y = y; @@ -168,7 +168,7 @@ static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h) { if ((gh->flags & GWIN_FLG_VISIBLE)) { if (gh->vmt->Redraw) { #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif gh->vmt->Redraw(gh); } @@ -190,7 +190,7 @@ static void WM_Raise(GHandle gh) { if ((gh->flags & GWIN_FLG_VISIBLE)) { if (gh->vmt->Redraw) { #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif gh->vmt->Redraw(gh); } diff --git a/src/gwin/label.c b/src/gwin/label.c index 65afff7e..5619761a 100644 --- a/src/gwin/label.c +++ b/src/gwin/label.c @@ -48,8 +48,8 @@ static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) { coord_t w, h; (void) param; - w = (gw->g.flags & GLABEL_FLG_WAUTO) ? getwidth(gw->text, gw->g.font, gdispGetWidth() - gw->g.x) : gw->g.width; - h = (gw->g.flags & GLABEL_FLG_HAUTO) ? getheight(gw->text, gw->g.font, gdispGetWidth() - gw->g.x) : gw->g.height; + w = (gw->g.flags & GLABEL_FLG_WAUTO) ? getwidth(gw->text, gw->g.font, gdispGGetWidth(gw->g.display) - gw->g.x) : gw->g.width; + h = (gw->g.flags & GLABEL_FLG_HAUTO) ? getheight(gw->text, gw->g.font, gdispGGetWidth(gw->g.display) - gw->g.x) : gw->g.height; if (gw->g.width != w || gw->g.height != h) { gwinResize(&gw->g, w, h); @@ -58,13 +58,13 @@ static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) { } // render the text - gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text, gw->pstyle->background, justifyLeft); // render the border (if any) if (gw->g.flags & GLABEL_FLG_BORDER) - gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); } static const gwidgetVMT labelVMT = { @@ -102,23 +102,23 @@ static const gwidgetVMT labelVMT = { #endif }; -GHandle gwinLabelCreate(GLabelObject *widget, GWidgetInit *pInit) { +GHandle gwinGLabelCreate(GDisplay *g, GLabelObject *widget, GWidgetInit *pInit) { uint16_t flags = 0; // auto assign width if (pInit->g.width <= 0) { flags |= GLABEL_FLG_WAUTO; - pInit->g.width = getwidth(pInit->text, gwinGetDefaultFont(), gdispGetWidth() - pInit->g.x); + pInit->g.width = getwidth(pInit->text, gwinGetDefaultFont(), gdispGGetWidth(g) - pInit->g.x); } // auto assign height if (pInit->g.height <= 0) { flags |= GLABEL_FLG_HAUTO; - pInit->g.height = getheight(pInit->text, gwinGetDefaultFont(), gdispGetWidth() - pInit->g.x); + pInit->g.height = getheight(pInit->text, gwinGetDefaultFont(), gdispGGetWidth(g) - pInit->g.x); } - if (!(widget = (GLabelObject *)_gwidgetCreate(&widget->w, pInit, &labelVMT))) + if (!(widget = (GLabelObject *)_gwidgetCreate(g, &widget->w, pInit, &labelVMT))) return 0; // no borders by default diff --git a/src/gwin/list.c b/src/gwin/list.c index 57046102..1662277d 100644 --- a/src/gwin/list.c +++ b/src/gwin/list.c @@ -96,15 +96,15 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { // the scroll area if ((gw2obj->cnt > (gw->g.height-2) / iheight) || (gw->g.flags & GLIST_FLG_SCROLLALWAYS)) { iwidth = gw->g.width - (SCROLLWIDTH+3); - gdispFillArea(gw->g.x+iwidth+2, gw->g.y+1, SCROLLWIDTH, gw->g.height-2, gdispBlendColor(ps->fill, gw->pstyle->background, 128)); - gdispDrawLine(gw->g.x+iwidth+1, gw->g.y+1, gw->g.x+iwidth+1, gw->g.y+gw->g.height-2, ps->edge); + gdispGFillArea(gw->g.display, gw->g.x+iwidth+2, gw->g.y+1, SCROLLWIDTH, gw->g.height-2, gdispBlendColor(ps->fill, gw->pstyle->background, 128)); + gdispGDrawLine(gw->g.display, gw->g.x+iwidth+1, gw->g.y+1, gw->g.x+iwidth+1, gw->g.y+gw->g.height-2, ps->edge); #if GDISP_NEED_CONVEX_POLYGON - gdispFillConvexPoly(gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+(ARROW/2+1), upArrow, 3, ps->fill); - gdispFillConvexPoly(gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+gw->g.height-(ARROW+ARROW/2+1), downArrow, 3, ps->fill); + gdispGFillConvexPoly(gw->g.display, gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+(ARROW/2+1), upArrow, 3, ps->fill); + gdispGFillConvexPoly(gw->g.display, gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+gw->g.height-(ARROW+ARROW/2+1), downArrow, 3, ps->fill); #else #warning "GWIN: Lists display better when GDISP_NEED_CONVEX_POLGON is turned on" - gdispFillArea(gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+(ARROW/2+1), ARROW, ARROW, ps->fill); - gdispFillArea(gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+gw->g.height-(ARROW+ARROW/2+1), ARROW, ARROW, ps->fill); + gdispGFillArea(gw->g.display, gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+(ARROW/2+1), ARROW, ARROW, ps->fill); + gdispGFillArea(gw->g.display, gw->g.x+iwidth+((SCROLLWIDTH-ARROW)/2+2), gw->g.y+gw->g.height-(ARROW+ARROW/2+1), ARROW, ARROW, ps->fill); #endif } else iwidth = gw->g.width - 2; @@ -126,7 +126,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { #if GWIN_NEED_LIST_IMAGES if ((gw->g.flags & GLIST_FLG_HASIMAGES)) { // Clear the image area - gdispFillArea(gw->g.x+1, gw->g.y+y, x-1, iheight, fill); + gdispGFillArea(gw->g.display, gw->g.x+1, gw->g.y+y, x-1, iheight, fill); if (qi2li->pimg && gdispImageIsOpen(qi2li->pimg)) { // Calculate which image sy = (qi2li->flags & GLIST_FLG_SELECTED) ? 0 : (iheight-TEXTGAP); @@ -136,19 +136,19 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { sy -= iheight-TEXTGAP; // Draw the image gdispImageSetBgColor(qi2li->pimg, fill); - gdispImageDraw(qi2li->pimg, gw->g.x+1, gw->g.y+y, iheight-TEXTGAP, iheight-TEXTGAP, 0, sy); + gdispGImageDraw(gw->g.display, qi2li->pimg, gw->g.x+1, gw->g.y+y, iheight-TEXTGAP, iheight-TEXTGAP, 0, sy); } } #endif - gdispFillStringBox(gw->g.x+x, gw->g.y+y, iwidth, iheight, qi2li->text, gw->g.font, ps->text, fill, justifyLeft); + gdispGFillStringBox(gw->g.display, gw->g.x+x, gw->g.y+y, iwidth, iheight, qi2li->text, gw->g.font, ps->text, fill, justifyLeft); } // Fill any remaining item space if (y < gw->g.height-1) - gdispFillArea(gw->g.x+1, gw->g.y+y, iwidth, gw->g.height-1-y, gw->pstyle->background); + gdispGFillArea(gw->g.display, gw->g.x+1, gw->g.y+y, iwidth, gw->g.height-1-y, gw->pstyle->background); // the list frame - gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, ps->edge); + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, ps->edge); } #if GINPUT_NEED_MOUSE @@ -318,8 +318,8 @@ static const gwidgetVMT listVMT = { #endif }; -GHandle gwinListCreate(GListObject* gobj, GWidgetInit* pInit, bool_t multiselect) { - if (!(gobj = (GListObject *)_gwidgetCreate(&gobj->w, pInit, &listVMT))) +GHandle gwinGListCreate(GDisplay *g, GListObject* gobj, GWidgetInit* pInit, bool_t multiselect) { + if (!(gobj = (GListObject *)_gwidgetCreate(g, &gobj->w, pInit, &listVMT))) return 0; // initialize the item queue diff --git a/src/gwin/radio.c b/src/gwin/radio.c index c9d089b0..7507634c 100644 --- a/src/gwin/radio.c +++ b/src/gwin/radio.c @@ -108,8 +108,8 @@ static const gwidgetVMT radioVMT = { #endif }; -GHandle gwinRadioCreate(GRadioObject *gw, const GWidgetInit *pInit, uint16_t group) { - if (!(gw = (GRadioObject *)_gwidgetCreate(&gw->w, pInit, &radioVMT))) +GHandle gwinGRadioCreate(GDisplay *g, GRadioObject *gw, const GWidgetInit *pInit, uint16_t group) { + if (!(gw = (GRadioObject *)_gwidgetCreate(g, &gw->w, pInit, &radioVMT))) return 0; #if GINPUT_NEED_TOGGLE @@ -177,21 +177,21 @@ void gwinRadioDraw_Radio(GWidgetObject *gw, void *param) { #if GDISP_NEED_CIRCLE df = (ld-1)/2; - gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background); - gdispDrawCircle(gw->g.x+df, gw->g.y+df, df, pcol->edge); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, ld, ld, gw->pstyle->background); + gdispGDrawCircle(gw->g.display, gw->g.x+df, gw->g.y+df, df, pcol->edge); if (gw->g.flags & GRADIO_FLG_PRESSED) - gdispFillCircle(gw->g.x+df, gw->g.y+df, df <= 2 ? 1 : (df-2), pcol->fill); + gdispGFillCircle(gw->g.display, gw->g.x+df, gw->g.y+df, df <= 2 ? 1 : (df-2), pcol->fill); #else - gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gw->pstyle->background); - gdispDrawBox(gw->g.x, gw->g.y, ld, ld, pcol->edge); + gdispGFillArea(gw->g.display, gw->g.x+1, gw->g.y+1, ld, ld-2, gw->pstyle->background); + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, ld, ld, pcol->edge); df = ld < 4 ? 1 : 2; if (gw->g.flags & GRADIO_FLG_PRESSED) - gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill); + gdispGFillArea(gw->g.display, gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill); #endif - gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyLeft); + gdispGFillStringBox(gw->g.display, gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyLeft); #undef gcw } @@ -202,9 +202,9 @@ void gwinRadioDraw_Button(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&radioVMT) return; pcol = getDrawColors(gw); - gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); - gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); - gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); + gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); } void gwinRadioDraw_Tab(GWidgetObject *gw, void *param) { @@ -215,12 +215,12 @@ void gwinRadioDraw_Tab(GWidgetObject *gw, void *param) { pcol = getDrawColors(gw); if ((gw->g.flags & GRADIO_FLG_PRESSED)) { - gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); - gdispFillStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); + gdispGFillStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); } else { - gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); - gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); - gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); + gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); } } diff --git a/src/gwin/slider.c b/src/gwin/slider.c index 63a57480..94d73034 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -223,8 +223,8 @@ static const gwidgetVMT sliderVMT = { #endif }; -GHandle gwinSliderCreate(GSliderObject *gs, const GWidgetInit *pInit) { - if (!(gs = (GSliderObject *)_gwidgetCreate(&gs->w, pInit, &sliderVMT))) +GHandle gwinGSliderCreate(GDisplay *g, GSliderObject *gs, const GWidgetInit *pInit) { + if (!(gs = (GSliderObject *)_gwidgetCreate(g, &gs->w, pInit, &sliderVMT))) return 0; #if GINPUT_NEED_TOGGLE gs->t_dn = GWIDGET_NO_INSTANCE; @@ -294,30 +294,30 @@ void gwinSliderDraw_Std(GWidgetObject *gw, void *param) { if (gw->g.width < gw->g.height) { // Vertical slider if (gsw->dpos != gw->g.height-1) - gdispFillArea(gw->g.x, gw->g.y+gsw->dpos, gw->g.width, gw->g.height - gsw->dpos, pcol->progress); // Active Area + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y+gsw->dpos, gw->g.width, gw->g.height - gsw->dpos, pcol->progress); // Active Area if (gsw->dpos != 0) - gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gw->pstyle->enabled.progress); // Inactive area - gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge - gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, pcol->edge); // Thumb + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gw->pstyle->enabled.progress); // Inactive area + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge + gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, pcol->edge); // Thumb if (gsw->dpos >= 2) - gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos-2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos-2, pcol->edge); // Thumb + gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gsw->dpos-2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos-2, pcol->edge); // Thumb if (gsw->dpos <= gw->g.height-2) - gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos+2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos+2, pcol->edge); // Thumb + gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gsw->dpos+2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos+2, pcol->edge); // Thumb // Horizontal slider } else { if (gsw->dpos != gw->g.width-1) - gdispFillArea(gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gw->pstyle->enabled.progress); // Inactive area + gdispGFillArea(gw->g.display, gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gw->pstyle->enabled.progress); // Inactive area if (gsw->dpos != 0) - gdispFillArea(gw->g.x, gw->g.y, gsw->dpos, gw->g.height, pcol->progress); // Active Area - gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge - gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, pcol->edge); // Thumb + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gsw->dpos, gw->g.height, pcol->progress); // Active Area + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge + gdispGDrawLine(gw->g.display, gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, pcol->edge); // Thumb if (gsw->dpos >= 2) - gdispDrawLine(gw->g.x+gsw->dpos-2, gw->g.y, gw->g.x+gsw->dpos-2, gw->g.y+gw->g.height-1, pcol->edge); // Thumb + gdispGDrawLine(gw->g.display, gw->g.x+gsw->dpos-2, gw->g.y, gw->g.x+gsw->dpos-2, gw->g.y+gw->g.height-1, pcol->edge); // Thumb if (gsw->dpos <= gw->g.width-2) - gdispDrawLine(gw->g.x+gsw->dpos+2, gw->g.y, gw->g.x+gsw->dpos+2, gw->g.y+gw->g.height-1, pcol->edge); // Thumb + gdispGDrawLine(gw->g.display, gw->g.x+gsw->dpos+2, gw->g.y, gw->g.x+gsw->dpos+2, gw->g.y+gw->g.height-1, pcol->edge); // Thumb } - gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); + gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); #undef gsw } @@ -338,7 +338,7 @@ void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { if (gw->g.width < gw->g.height) { // Vertical slider if (gsw->dpos != 0) // The unfilled area - gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gw->pstyle->enabled.progress); // Inactive area + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gw->pstyle->enabled.progress); // Inactive area if (gsw->dpos != gw->g.height-1) { // The filled area for(z=gw->g.height, v=gi->height; z > gsw->dpos;) { z -= v; @@ -346,27 +346,27 @@ void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { v -= gsw->dpos - z; z = gsw->dpos; } - gdispImageDraw(gi, gw->g.x, gw->g.y+z, gw->g.width, v, 0, gi->height-v); + gdispGImageDraw(gw->g.display, gi, gw->g.x, gw->g.y+z, gw->g.width, v, 0, gi->height-v); } } - gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge - gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, pcol->edge); // Thumb + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge + gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, pcol->edge); // Thumb // Horizontal slider } else { if (gsw->dpos != gw->g.width-1) // The unfilled area - gdispFillArea(gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gw->pstyle->enabled.progress); // Inactive area + gdispGFillArea(gw->g.display, gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gw->pstyle->enabled.progress); // Inactive area if (gsw->dpos != 0) { // The filled area for(z=0, v=gi->width; z < gsw->dpos; z += v) { if (z+v > gsw->dpos) v -= z+v - gsw->dpos; - gdispImageDraw(gi, gw->g.x+z, gw->g.y, v, gw->g.height, 0, 0); + gdispGImageDraw(gw->g.display, gi, gw->g.x+z, gw->g.y, v, gw->g.height, 0, 0); } } - gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge - gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, pcol->edge); // Thumb + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge + gdispGDrawLine(gw->g.display, gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, pcol->edge); // Thumb } - gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); + gdispGDrawStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); #undef gsw } From f3f7eba73cb199c0222440ea50052b77975f170a Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 24 Oct 2013 14:08:35 +0200 Subject: [PATCH 116/160] fixed board file name (all the others are upper case as well) --- drivers/gdisp/RA8875/gdisp_lld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gdisp/RA8875/gdisp_lld.c b/drivers/gdisp/RA8875/gdisp_lld.c index b0508b58..fb81c43a 100644 --- a/drivers/gdisp/RA8875/gdisp_lld.c +++ b/drivers/gdisp/RA8875/gdisp_lld.c @@ -19,7 +19,7 @@ #include "gdisp/lld/gdisp_lld.h" /* include the users board interface */ -#include "board_ra8875.h" +#include "board_RA8875.h" /*===========================================================================*/ /* Driver local definitions. */ From af3963d341f14fd46a2eaa26f53f44de641299dc Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 24 Oct 2013 14:49:00 +0200 Subject: [PATCH 117/160] fixed RA8875 board file for marlin --- drivers/gdisp/RA8875/board_RA8875_marlin.h | 64 +++++++++++++--------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/drivers/gdisp/RA8875/board_RA8875_marlin.h b/drivers/gdisp/RA8875/board_RA8875_marlin.h index e6c19d34..b1d55a92 100644 --- a/drivers/gdisp/RA8875/board_RA8875_marlin.h +++ b/drivers/gdisp/RA8875/board_RA8875_marlin.h @@ -10,52 +10,62 @@ * @brief GDISP Graphic Driver subsystem board interface for the RA8875 display. */ -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H +#ifndef _BOARD_RA8875_H +#define _BOARD_RA8875_H // For a multiple display configuration we would put all this in a structure and then -// set g->board to that structure. +// set g->board to that structure. #define GDISP_RAM (*((volatile uint16_t *) 0x68000000)) /* RS = 0 */ #define GDISP_REG (*((volatile uint16_t *) 0x68020000)) /* RS = 1 */ #define FSMC_BANK 4 static inline void init_board(GDisplay *g) { - // As we are not using multiple displays we set g->board to NULL as we don't use it. g->board = 0; switch(g->controllerdisplay) { - case 0: // Set up for Display 0 - /* set pins to FSMC mode */ - IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 8) | - (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; + // setup for display 0 + case 0: { - IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | - (1 << 13) | (1 << 14) | (1 << 15), 0}; + // enable the FSMC peripheral + rccEnableAHB3(RCC_AHB3ENR_FSMCEN, 0); - IOBus busG = {GPIOG, (1 << 10), 0}; + // setup the pin modes for FSMC + IOBus busD = {GPIOD, (1 << 0) | (1 << 1) | (1 << 4) | (1 << 5) | (1 << 8) | + (1 << 9) | (1 << 10) | (1 << 11) | (1 << 14) | (1 << 15), 0}; - palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); - palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); - palSetBusMode(&busG, PAL_MODE_ALTERNATE(12)); + IOBus busE = {GPIOE, (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12) | + (1 << 13) | (1 << 14) | (1 << 15), 0}; - /* FSMC timing */ - FSMC_Bank1->BTCR[FSMC_BANK+1] = (FSMC_BTR1_ADDSET_1 | FSMC_BTR1_ADDSET_3) \ - | (FSMC_BTR1_DATAST_1 | FSMC_BTR1_DATAST_3) \ - | (FSMC_BTR1_BUSTURN_1 | FSMC_BTR1_BUSTURN_3) ; + IOBus busG = {GPIOG, (1 << 10), 0}; - /* Bank1 NOR/SRAM control register configuration - * This is actually not needed as already set by default after reset */ - FSMC_Bank1->BTCR[FSMC_BANK] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; - break; + palSetBusMode(&busD, PAL_MODE_ALTERNATE(12)); + palSetBusMode(&busE, PAL_MODE_ALTERNATE(12)); + palSetBusMode(&busG, PAL_MODE_ALTERNATE(12)); + + // FSMC timing + FSMC_Bank1->BTCR[FSMC_BANK+1] = (FSMC_BTR1_ADDSET_1 | FSMC_BTR1_ADDSET_3) \ + | (FSMC_BTR1_DATAST_1 | FSMC_BTR1_DATAST_3) \ + | (FSMC_BTR1_BUSTURN_1 | FSMC_BTR1_BUSTURN_3) ; + + // Bank1 NOR/SRAM control register configuration + // This is actually not needed as already set by default after reset + FSMC_Bank1->BTCR[FSMC_BANK] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; + + break; + } + + // marlin does not have any secondary display so far + default: + break; } } static inline void post_init_board(GDisplay *g) { (void) g; - - /* FSMC delay reduced as the controller now runs at full speed */ + + // FSMC delay reduced as the controller now runs at full speed FSMC_Bank1->BTCR[2+1] = FSMC_BTR1_ADDSET_0 | FSMC_BTR1_DATAST_2 | FSMC_BTR1_BUSTURN_0 ; FSMC_Bank1->BTCR[2] = FSMC_BCR1_MWID_0 | FSMC_BCR1_WREN | FSMC_BCR1_MBKEN; } @@ -75,11 +85,13 @@ static inline void release_bus(GDisplay *g) { static inline void write_index(GDisplay *g, uint16_t index) { (void) g; + GDISP_REG = index; } static inline void write_data(GDisplay *g, uint16_t data) { (void) g; + GDISP_RAM = data; } @@ -93,7 +105,9 @@ static inline void setwritemode(GDisplay *g) { static inline uint16_t read_data(GDisplay *g) { (void) g; + return GDISP_RAM; } -#endif /* _GDISP_LLD_BOARD_H */ +#endif /* _BOARD_RA8875_H */ + From e0b2406da613b02fce6af8aead160e43301a3852 Mon Sep 17 00:00:00 2001 From: inmarket Date: Fri, 25 Oct 2013 14:39:56 +1000 Subject: [PATCH 118/160] Fix SSD1306 driver and board files to allow for seamless transfer of the command byte with the page line data without copying the data on to the stack. --- drivers/gdisp/SSD1306/board_SSD1306_i2c.h | 9 +++---- drivers/gdisp/SSD1306/board_SSD1306_spi.h | 9 +++---- .../gdisp/SSD1306/board_SSD1306_template.h | 6 ++--- drivers/gdisp/SSD1306/gdisp_lld.c | 26 ++++++++++++++++--- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/drivers/gdisp/SSD1306/board_SSD1306_i2c.h b/drivers/gdisp/SSD1306/board_SSD1306_i2c.h index 69c054f5..449d47ba 100644 --- a/drivers/gdisp/SSD1306/board_SSD1306_i2c.h +++ b/drivers/gdisp/SSD1306/board_SSD1306_i2c.h @@ -13,7 +13,8 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H -#define GDISP_BUS_MAX_TRANSFER_SIZE 64 +// The command byte to put on the front of each page line +#define SSD1306_PAGE_PREFIX 0x40 // Co = 0, D/C = 1 // For a multiple display configuration we would put all this in a structure and then // set g->board to that structure. @@ -116,14 +117,10 @@ static inline void write_cmd(GDisplay *g, uint8_t cmd) { } static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { - uint8_t command[1]; (void) g; - command[0] = 0x40; // Co = 0, D/C = 1 - i2cStart(&I2CD1, &i2cconfig); - i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, command, 1, NULL, 0, MS2ST(10)); - i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, command, data, NULL, length, MS2ST(10)); + i2cMasterTransmitTimeout(&I2CD1, SSD1306_I2C_ADDRESS, data, length, NULL, 0, MS2ST(10)); i2cStop(&I2CD1); } diff --git a/drivers/gdisp/SSD1306/board_SSD1306_spi.h b/drivers/gdisp/SSD1306/board_SSD1306_spi.h index 476c51bf..5b481630 100644 --- a/drivers/gdisp/SSD1306/board_SSD1306_spi.h +++ b/drivers/gdisp/SSD1306/board_SSD1306_spi.h @@ -13,7 +13,8 @@ #ifndef _GDISP_LLD_BOARD_H #define _GDISP_LLD_BOARD_H -#define GDISP_BUS_MAX_TRANSFER_SIZE 64 +// The command byte to put on the front of each page line +#define SSD1306_PAGE_PREFIX 0x40 // Co = 0, D/C = 1 // For a multiple display configuration we would put all this in a structure and then // set g->board to that structure. @@ -49,10 +50,12 @@ static const SPIConfig spi1config = { #endif static inline void init_board(GDisplay *g) { + unsigned i; // As we are not using multiple displays we set g->board to NULL as we don't use it. g->board = 0; + switch(g->controllerdisplay) { case 0: // Set up for Display 0 // RESET pin. @@ -115,14 +118,10 @@ static inline void write_cmd(GDisplay *g, uint8_t cmd) { } static inline void write_data(GDisplay *g, uint8_t* data, uint16_t length) { - uint8_t command[1]; (void) g; - command[0] = 0x40; // Co = 0, D/C = 1 - spiStart(&SPID1, &spi1config); spiSelect(&SPID1); - spiStartSend(&SPID1, 1, command); spiStartSend(&SPID1, length, data); spiUnselect(&SPID1); spiStop(&SPID1); diff --git a/drivers/gdisp/SSD1306/board_SSD1306_template.h b/drivers/gdisp/SSD1306/board_SSD1306_template.h index ec7f44f5..5b4bd05c 100644 --- a/drivers/gdisp/SSD1306/board_SSD1306_template.h +++ b/drivers/gdisp/SSD1306/board_SSD1306_template.h @@ -17,12 +17,12 @@ #define _GDISP_LLD_BOARD_H /** - * @brief How many bytes to write in one operation when updating the display. - * @note The screen size (in bytes) must evenly divide by this number. + * @brief Optional: A byte to prefix on each display page line. + * @note If not defined then no byte is prefixed on each page line. * * @notapi */ -#define GDISP_BUS_MAX_TRANSFER_SIZE 64 +//#define SSD1306_PAGE_PREFIX 0x40 /** * @brief Initialise the board for the display. diff --git a/drivers/gdisp/SSD1306/gdisp_lld.c b/drivers/gdisp/SSD1306/gdisp_lld.c index 81b3b692..390a9282 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld.c +++ b/drivers/gdisp/SSD1306/gdisp_lld.c @@ -36,6 +36,13 @@ #ifndef GDISP_INITIAL_BACKLIGHT #define GDISP_INITIAL_BACKLIGHT 100 #endif +#ifdef SSD1306_PAGE_PREFIX + #define SSD1306_PAGE_WIDTH (GDISP_SCREEN_WIDTH+1) + #define SSD1306_PAGE_OFFSET 1 +#else + #define SSD1306_PAGE_WIDTH GDISP_SCREEN_WIDTH + #define SSD1306_PAGE_OFFSET 0 +#endif #define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0) @@ -54,7 +61,7 @@ #define delay(us) gfxSleepMicroseconds(us) #define delayms(ms) gfxSleepMilliseconds(ms) -#define xyaddr(x, y) ((x) + ((y)>>3)*GDISP_SCREEN_WIDTH) +#define xyaddr(x, y) (SSD1306_PAGE_OFFSET + (x) + ((y)>>3)*SSD1306_PAGE_WIDTH) #define xybit(y) (1<<((y)&7)) /*===========================================================================*/ @@ -70,7 +77,18 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { // The private area is the display surface. - g->priv = gfxAlloc(GDISP_SCREEN_HEIGHT * GDISP_SCREEN_WIDTH / 8); + g->priv = gfxAlloc(GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH); + + // Fill in the prefix command byte on each page line of the display buffer + // We can do it during initialisation as this byte is never overwritten. + #ifdef SSD1306_PAGE_PREFIX + { + unsigned i; + + for(i=0; i < GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH; i+=SSD1306_PAGE_WIDTH) + RAM(g)[i] = SSD1306_PAGE_PREFIX; + } + #endif // Initialise the board interface init_board(g); @@ -131,8 +149,8 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { write_cmd(g, SSD1306_SETSTARTLINE | 0); - for(i=0; i < GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT/8; i+=GDISP_BUS_MAX_TRANSFER_SIZE) - write_data(g, RAM(g)+i, GDISP_BUS_MAX_TRANSFER_SIZE); + for(i=0; i < GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH; i+=SSD1306_PAGE_WIDTH) + write_data(g, RAM(g)+i, SSD1306_PAGE_WIDTH); } #endif From 9f1e3716812ed9e922af020498c36cadad49819d Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 26 Oct 2013 21:32:55 +1000 Subject: [PATCH 119/160] Compile fix for GE12 --- drivers/gdisp/Nokia6610GE12/gdisp_lld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c index ef8cd043..c04b4cf9 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c @@ -71,7 +71,7 @@ // Use the priv pointer itself to save our color. This save allocating ram for it // and works provided sizeof(color_t) <= sizeof(void *) -#define savecolor(g) ((color_t)g->priv) +#define savecolor(g) (*(color_t *)&g->priv) #define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0) From 2112074e79cf4d9cf4c40f358af3b6280f389148 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sat, 26 Oct 2013 14:59:52 +0200 Subject: [PATCH 120/160] Nokia6610GE8 compiler warning --- drivers/gdisp/Nokia6610GE8/gdisp_lld.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index f724ee42..e0cfb997 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -328,6 +328,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { acquire_bus(g); set_viewport(g); + /* to surpress compiler warnings */ + x = 0; + y = 0; + /* * Due to the way the Nokia6610 handles a decrementing column or page, * we have to make adjustments as to where it is actually drawing from in the bitmap. From a756806b77fc431c9515041fc83dbc06c2854b56 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sat, 26 Oct 2013 14:59:52 +0200 Subject: [PATCH 121/160] Compile Fix for Nokia6610GE12 --- drivers/gdisp/Nokia6610GE12/gdisp_lld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c index c04b4cf9..d1086c46 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c @@ -248,7 +248,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { case GDISP_CONTROL_CONTRAST: if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100; acquire_bus(g); - write_reg(g, CONTRAST,(unsigned)128*g->p.ptr/101-64); + write_reg(g, SETCON,(unsigned)128*(unsigned)g->p.ptr/101-64); release_bus(g); g->g.Contrast = (unsigned)g->p.ptr; return; From aca01e68a2b28d7027673dfb098155c119afdacc Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sat, 26 Oct 2013 17:51:27 +0200 Subject: [PATCH 122/160] whitespaces --- drivers/gdisp/ILI9320/gdisp_lld.mk | 4 +- drivers/gdisp/ILI9320/gdisp_lld_config.h | 52 ++++++++++++------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/gdisp/ILI9320/gdisp_lld.mk b/drivers/gdisp/ILI9320/gdisp_lld.mk index 656f5930..071e7c02 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.mk +++ b/drivers/gdisp/ILI9320/gdisp_lld.mk @@ -1,2 +1,2 @@ -GFXINC += $(GFXLIB)/drivers/gdisp/ILI9320 -GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9320/gdisp_lld.c +GFXINC += $(GFXLIB)/drivers/gdisp/ILI9320 +GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9320/gdisp_lld.c diff --git a/drivers/gdisp/ILI9320/gdisp_lld_config.h b/drivers/gdisp/ILI9320/gdisp_lld_config.h index 3c5c7484..861b3a1b 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_config.h @@ -4,33 +4,33 @@ * * http://ugfx.org/license.html */ - -/** - * @file drivers/gdisp/ILI9320/gdisp_lld_config.h - * @brief GDISP Graphic Driver subsystem low level driver header for the ILI9320 display. - * - * @addtogroup GDISP - * @{ - */ - -#ifndef GDISP_LLD_CONFIG_H -#define GDISP_LLD_CONFIG_H - -#if GFX_USE_GDISP - -/*===========================================================================*/ -/* Driver hardware support. */ -/*===========================================================================*/ - + +/** + * @file drivers/gdisp/ILI9320/gdisp_lld_config.h + * @brief GDISP Graphic Driver subsystem low level driver header for the ILI9320 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef GDISP_LLD_CONFIG_H +#define GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE #define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE - -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 - -#endif /* GFX_USE_GDISP */ - -#endif /* _GDISP_LLD_CONFIG_H */ -/** @} */ - + +#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */ +/** @} */ + From 2832f97fed4cf413a078995e6ca2068e13aabc1d Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sat, 26 Oct 2013 17:52:49 +0200 Subject: [PATCH 123/160] fixed orientation stuff in widgets demo --- demos/modules/gwin/widgets/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c index 0dec7275..dde955f3 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -262,10 +262,6 @@ int main(void) { // Initialize the display gfxInit(); - #if GDISP_NEED_CONTROL - gdispSetOrientation(GDISP_ROTATE_90); - #endif - // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("*")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); @@ -276,6 +272,10 @@ int main(void) { gwinAttachMouse(0); #endif + #if GDISP_NEED_CONTROL + gdispSetOrientation(GDISP_ROTATE_90); + #endif + // Create the gwin windows/widgets createWidgets(); From 579a7806716a08cbcc6829ea26eff3c15519a932 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sat, 26 Oct 2013 17:52:49 +0200 Subject: [PATCH 124/160] Test fix for ILI9320 driver. --- drivers/gdisp/ILI9320/gdisp_lld.c | 11 ++++++++--- drivers/gdisp/ILI9320/gdisp_lld_config.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index 6d7815cb..a18c2d82 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -199,6 +199,9 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { LLDSPEC void gdisp_lld_write_start(GDisplay *g) { acquire_bus(g); set_viewport(g); + #if !GDISP_HARDWARE_STREAM_POS + set_cursor(g); + #endif } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { write_data(g, g->p.color); @@ -206,9 +209,11 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); } - LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { - set_cursor(g); - } + #if GDISP_HARDWARE_STREAM_POS + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { + set_cursor(g); + } + #endif #endif #if GDISP_HARDWARE_STREAM_READ diff --git a/drivers/gdisp/ILI9320/gdisp_lld_config.h b/drivers/gdisp/ILI9320/gdisp_lld_config.h index 861b3a1b..1a1f139f 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_config.h @@ -24,7 +24,7 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_STREAM_READ TRUE -#define GDISP_HARDWARE_STREAM_POS TRUE +//#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 From 7c3b7270fc1b39bf231654b846bcaeccead4413c Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sun, 27 Oct 2013 16:39:42 +0100 Subject: [PATCH 125/160] moved include headers to correct location --- include/gwin/gwidget.h | 11 +++++++++++ include/gwin/gwin.h | 8 -------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/include/gwin/gwidget.h b/include/gwin/gwidget.h index b760dd41..493485b3 100644 --- a/include/gwin/gwidget.h +++ b/include/gwin/gwidget.h @@ -279,15 +279,26 @@ bool_t gwinAttachListener(GListener *pl); #if GWIN_NEED_BUTTON || defined(__DOXYGEN__) #include "gwin/button.h" #endif + #if GWIN_NEED_SLIDER || defined(__DOXYGEN__) #include "gwin/slider.h" #endif + #if GWIN_NEED_CHECKBOX || defined(__DOXYGEN__) #include "gwin/checkbox.h" #endif + #if GWIN_NEED_RADIO || defined(__DOXYGEN__) #include "gwin/radio.h" #endif +#if GWIN_NEED_LABEL || defined(__DOXYGEN__) + #include "gwin/label.h" +#endif + +#if GWIN_NEED_LIST || defined(__DOXYGEN__) + #include "gwin/list.h" +#endif + #endif /* _GWIDGET_H */ /** @} */ diff --git a/include/gwin/gwin.h b/include/gwin/gwin.h index 37a14fa1..fa5ba613 100644 --- a/include/gwin/gwin.h +++ b/include/gwin/gwin.h @@ -823,14 +823,6 @@ extern "C" { #include "gwin/image.h" #endif - #if GWIN_NEED_LABEL || defined(__DOXYGEN__) - #include "gwin/label.h" - #endif - - #if GWIN_NEED_LIST || defined(__DOXYGEN__) - #include "gwin/list.h" - #endif - #endif /* GFX_USE_GWIN */ #endif /* _GWIN_H */ From a1d453e46fc33376c2d0420e632ccfba66f47ced Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 28 Oct 2013 00:09:34 +0100 Subject: [PATCH 126/160] GDISP_NEED_TEXT and GDISP_NEED_ELLIPSE defaults to FALSE now. The former requires to enable at least one font which may not be needed (it sucks if compiling the basic examples) and the latter is barely needed anyway --- include/gdisp/options.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/gdisp/options.h b/include/gdisp/options.h index 4b199118..7796144c 100644 --- a/include/gdisp/options.h +++ b/include/gdisp/options.h @@ -79,11 +79,11 @@ #endif /** * @brief Are text functions needed. - * @details Defaults to TRUE + * @details Defaults to FALSE * @note You must also define at least one font. */ #ifndef GDISP_NEED_TEXT - #define GDISP_NEED_TEXT TRUE + #define GDISP_NEED_TEXT FALSE #endif /** * @brief Are circle functions needed. From 4b76efce1d2676333606d4fd08f34ace33824312 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 28 Oct 2013 00:35:08 +0100 Subject: [PATCH 127/160] Bugfix... how could we miss this? --- src/gwin/slider.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gwin/slider.c b/src/gwin/slider.c index 94d73034..0956ca8a 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -322,6 +322,7 @@ void gwinSliderDraw_Std(GWidgetObject *gw, void *param) { #undef gsw } +#if GDISP_NEED_IMAGE || defined(__DOXYGEN__) void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { #define gsw ((GSliderObject *)gw) #define gi ((gdispImage *)param) @@ -370,6 +371,7 @@ void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { #undef gsw } +#endif /* GDISP_NEED_IMAGE */ #endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */ /** @} */ From 36c55722ddc06af682d7c7bdeb71ba75a3b0fb83 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 28 Oct 2013 00:42:38 +0100 Subject: [PATCH 128/160] updated GDISP and GWIN demos --- .../gdisp/{gdisp_basics => basics}/gfxconf.h | 18 +- .../gdisp/{gdisp_basics => basics}/main.c | 4 +- .../{gdisp_circles => circles}/gfxconf.h | 20 +-- .../gdisp/{gdisp_circles => circles}/main.c | 2 +- .../{gdisp_fonts => fonts}/font_Apple12.h | 0 .../{gdisp_fonts => fonts}/font_FreePixel10.h | 0 .../font_GeosansLight11.h | 0 .../font_GeosansLight11_aa.h | 0 .../font_babyblue11_aa.h | 0 .../font_hellovetica11.h | 0 .../font_hellovetica11_aa.h | 0 .../font_pf_ronda_seven11_aa.h | 0 .../gdisp/{gdisp_fonts => fonts}/gfxconf.h | 10 +- .../gdisp/{gdisp_fonts => fonts}/main.c | 2 +- .../gdisp/{gdisp_fonts => fonts}/userfonts.h | 0 demos/modules/gdisp/fonts_cyrillic/gfxconf.h | 56 ++++++ demos/modules/gdisp/fonts_cyrillic/main.c | 49 +++++ .../userfonts.h | 0 .../gdisp/gdisp_fonts_cyrillic/gfxconf.h | 169 ------------------ .../modules/gdisp/gdisp_fonts_cyrillic/main.c | 20 --- .../gdisp/gdisp_images/results_650x493.png | Bin 32345 -> 0 bytes demos/modules/gdisp/gdisp_text/gfxconf.h | 75 -------- demos/modules/gdisp/gdisp_text/main.c | 74 -------- .../gdisp/{gdisp_images => images}/gfxconf.h | 26 +-- .../gdisp/{gdisp_images => images}/main.c | 4 +- .../{gdisp_images => images}/test-pal8.bmp | Bin .../{gdisp_images => images}/test-pal8.h | 0 .../gfxconf.h | 27 +-- .../main.c | 1 + .../testanim.gif | Bin .../testanim.h | 0 demos/modules/gwin/basic/gfxconf.h | 18 +- demos/modules/gwin/basic/main.c | 4 +- demos/modules/gwin/button/gfxconf.h | 58 ++---- demos/modules/gwin/button/main.c | 29 +++ demos/modules/gwin/checkbox/gfxconf.h | 58 ++---- demos/modules/gwin/checkbox/main.c | 29 +++ demos/modules/gwin/console/gfxconf.h | 29 ++- demos/modules/gwin/console/main.c | 4 +- demos/modules/gwin/graph/gfxconf.h | 25 +-- demos/modules/gwin/graph/main.c | 1 + demos/modules/gwin/list/gfxconf.h | 160 ++++------------- demos/modules/gwin/list/main.c | 31 +++- demos/modules/gwin/radio/gfxconf.h | 58 ++---- demos/modules/gwin/radio/main.c | 29 +++ demos/modules/gwin/slider/gfxconf.h | 58 ++---- demos/modules/gwin/slider/main.c | 29 +++ demos/modules/gwin/widgets/gfxconf.h | 55 +++--- demos/modules/gwin/widgets/main.c | 1 + 49 files changed, 441 insertions(+), 792 deletions(-) rename demos/modules/gdisp/{gdisp_basics => basics}/gfxconf.h (79%) rename demos/modules/gdisp/{gdisp_basics => basics}/main.c (94%) rename demos/modules/gdisp/{gdisp_circles => circles}/gfxconf.h (82%) rename demos/modules/gdisp/{gdisp_circles => circles}/main.c (95%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/font_Apple12.h (100%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/font_FreePixel10.h (100%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/font_GeosansLight11.h (100%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/font_GeosansLight11_aa.h (100%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/font_babyblue11_aa.h (100%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/font_hellovetica11.h (100%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/font_hellovetica11_aa.h (100%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/font_pf_ronda_seven11_aa.h (100%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/gfxconf.h (95%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/main.c (98%) rename demos/modules/gdisp/{gdisp_fonts => fonts}/userfonts.h (100%) create mode 100644 demos/modules/gdisp/fonts_cyrillic/gfxconf.h create mode 100644 demos/modules/gdisp/fonts_cyrillic/main.c rename demos/modules/gdisp/{gdisp_fonts_cyrillic => fonts_cyrillic}/userfonts.h (100%) delete mode 100644 demos/modules/gdisp/gdisp_fonts_cyrillic/gfxconf.h delete mode 100644 demos/modules/gdisp/gdisp_fonts_cyrillic/main.c delete mode 100644 demos/modules/gdisp/gdisp_images/results_650x493.png delete mode 100644 demos/modules/gdisp/gdisp_text/gfxconf.h delete mode 100644 demos/modules/gdisp/gdisp_text/main.c rename demos/modules/gdisp/{gdisp_images => images}/gfxconf.h (75%) rename demos/modules/gdisp/{gdisp_images => images}/main.c (97%) rename demos/modules/gdisp/{gdisp_images => images}/test-pal8.bmp (100%) rename demos/modules/gdisp/{gdisp_images => images}/test-pal8.h (100%) rename demos/modules/gdisp/{gdisp_images_animated => images_animated}/gfxconf.h (74%) rename demos/modules/gdisp/{gdisp_images_animated => images_animated}/main.c (99%) rename demos/modules/gdisp/{gdisp_images_animated => images_animated}/testanim.gif (100%) rename demos/modules/gdisp/{gdisp_images_animated => images_animated}/testanim.h (100%) diff --git a/demos/modules/gdisp/gdisp_basics/gfxconf.h b/demos/modules/gdisp/basics/gfxconf.h similarity index 79% rename from demos/modules/gdisp/gdisp_basics/gfxconf.h rename to demos/modules/gdisp/basics/gfxconf.h index 8adc7c8d..ff365590 100644 --- a/demos/modules/gdisp/gdisp_basics/gfxconf.h +++ b/demos/modules/gdisp/basics/gfxconf.h @@ -31,9 +31,10 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -41,15 +42,6 @@ /* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT FALSE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gdisp/gdisp_basics/main.c b/demos/modules/gdisp/basics/main.c similarity index 94% rename from demos/modules/gdisp/gdisp_basics/main.c rename to demos/modules/gdisp/basics/main.c index f875028b..48d4a652 100644 --- a/demos/modules/gdisp/gdisp_basics/main.c +++ b/demos/modules/gdisp/basics/main.c @@ -33,7 +33,7 @@ int main(void) { coord_t width, height; coord_t i, j; - /* Initialize and clear the display */ + // Initialize and clear the display gfxInit(); // Get the screen size @@ -46,7 +46,7 @@ int main(void) { gdispDrawLine(5, 30, width-50, height-40, Red); for(i = 5, j = 0; i < width && j < height; i += 7, j += i/20) - gdispDrawPixel (i, j, White); + gdispDrawPixel(i, j, White); while(TRUE) { gfxSleepMilliseconds(500); diff --git a/demos/modules/gdisp/gdisp_circles/gfxconf.h b/demos/modules/gdisp/circles/gfxconf.h similarity index 82% rename from demos/modules/gdisp/gdisp_circles/gfxconf.h rename to demos/modules/gdisp/circles/gfxconf.h index 8858cf02..cb698fce 100644 --- a/demos/modules/gdisp/gdisp_circles/gfxconf.h +++ b/demos/modules/gdisp/circles/gfxconf.h @@ -31,29 +31,25 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE +#define GFX_USE_GMISC TRUE -/* Features for the GDISP sub-system. */ +/* Features for the GDISP subsystem. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT FALSE #define GDISP_NEED_CIRCLE TRUE #define GDISP_NEED_ELLIPSE TRUE #define GDISP_NEED_ARC TRUE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE -#define GFX_USE_GMISC TRUE +/* Features for the GMISC subsystem */ #define GMISC_NEED_FIXEDTRIG TRUE #define GMISC_NEED_FASTTRIG TRUE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gdisp/gdisp_circles/main.c b/demos/modules/gdisp/circles/main.c similarity index 95% rename from demos/modules/gdisp/gdisp_circles/main.c rename to demos/modules/gdisp/circles/main.c index b8b90478..9253439d 100644 --- a/demos/modules/gdisp/gdisp_circles/main.c +++ b/demos/modules/gdisp/circles/main.c @@ -32,7 +32,7 @@ int main(void) { coord_t width, height; - /* Initialize and clear the display */ + // Initialize and clear the display gfxInit(); // Get the screen size diff --git a/demos/modules/gdisp/gdisp_fonts/font_Apple12.h b/demos/modules/gdisp/fonts/font_Apple12.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts/font_Apple12.h rename to demos/modules/gdisp/fonts/font_Apple12.h diff --git a/demos/modules/gdisp/gdisp_fonts/font_FreePixel10.h b/demos/modules/gdisp/fonts/font_FreePixel10.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts/font_FreePixel10.h rename to demos/modules/gdisp/fonts/font_FreePixel10.h diff --git a/demos/modules/gdisp/gdisp_fonts/font_GeosansLight11.h b/demos/modules/gdisp/fonts/font_GeosansLight11.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts/font_GeosansLight11.h rename to demos/modules/gdisp/fonts/font_GeosansLight11.h diff --git a/demos/modules/gdisp/gdisp_fonts/font_GeosansLight11_aa.h b/demos/modules/gdisp/fonts/font_GeosansLight11_aa.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts/font_GeosansLight11_aa.h rename to demos/modules/gdisp/fonts/font_GeosansLight11_aa.h diff --git a/demos/modules/gdisp/gdisp_fonts/font_babyblue11_aa.h b/demos/modules/gdisp/fonts/font_babyblue11_aa.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts/font_babyblue11_aa.h rename to demos/modules/gdisp/fonts/font_babyblue11_aa.h diff --git a/demos/modules/gdisp/gdisp_fonts/font_hellovetica11.h b/demos/modules/gdisp/fonts/font_hellovetica11.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts/font_hellovetica11.h rename to demos/modules/gdisp/fonts/font_hellovetica11.h diff --git a/demos/modules/gdisp/gdisp_fonts/font_hellovetica11_aa.h b/demos/modules/gdisp/fonts/font_hellovetica11_aa.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts/font_hellovetica11_aa.h rename to demos/modules/gdisp/fonts/font_hellovetica11_aa.h diff --git a/demos/modules/gdisp/gdisp_fonts/font_pf_ronda_seven11_aa.h b/demos/modules/gdisp/fonts/font_pf_ronda_seven11_aa.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts/font_pf_ronda_seven11_aa.h rename to demos/modules/gdisp/fonts/font_pf_ronda_seven11_aa.h diff --git a/demos/modules/gdisp/gdisp_fonts/gfxconf.h b/demos/modules/gdisp/fonts/gfxconf.h similarity index 95% rename from demos/modules/gdisp/gdisp_fonts/gfxconf.h rename to demos/modules/gdisp/fonts/gfxconf.h index a0bba31c..ffb3a7e7 100644 --- a/demos/modules/gdisp/gdisp_fonts/gfxconf.h +++ b/demos/modules/gdisp/fonts/gfxconf.h @@ -31,9 +31,10 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS FALSE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -73,6 +74,5 @@ #define GDISP_INCLUDE_FONT_UI2 TRUE #define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE -#define GDISP_INCLUDE_USER_FONTS TRUE - #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gdisp/gdisp_fonts/main.c b/demos/modules/gdisp/fonts/main.c similarity index 98% rename from demos/modules/gdisp/gdisp_fonts/main.c rename to demos/modules/gdisp/fonts/main.c index e9cdf003..0384b737 100644 --- a/demos/modules/gdisp/gdisp_fonts/main.c +++ b/demos/modules/gdisp/fonts/main.c @@ -36,7 +36,7 @@ int main(void) { const char *line1, *line2; char buf[8]; - /* Initialize and clear the display */ + // Initialize and clear the display gfxInit(); // Get the screen size diff --git a/demos/modules/gdisp/gdisp_fonts/userfonts.h b/demos/modules/gdisp/fonts/userfonts.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts/userfonts.h rename to demos/modules/gdisp/fonts/userfonts.h diff --git a/demos/modules/gdisp/fonts_cyrillic/gfxconf.h b/demos/modules/gdisp/fonts_cyrillic/gfxconf.h new file mode 100644 index 00000000..713c89b4 --- /dev/null +++ b/demos/modules/gdisp/fonts_cyrillic/gfxconf.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + +/* The operating system to use - one of these must be defined */ +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE + +/* GFX subsystems to turn on */ +#define GFX_USE_GDISP TRUE + +/* Features for the GDISP subsystem */ +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_TEXT TRUE +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_ELLIPSE TRUE +#define GDISP_NEED_ANTIALIAS TRUE +#define GDISP_NEED_UTF8 TRUE +#define GDISP_NEED_TEXT_KERNING TRUE + +/* GDISP - fonts to include */ +#define GDISP_INCLUDE_USER_FONTS TRUE + +#endif /* _GFXCONF_H */ + diff --git a/demos/modules/gdisp/fonts_cyrillic/main.c b/demos/modules/gdisp/fonts_cyrillic/main.c new file mode 100644 index 00000000..bd504722 --- /dev/null +++ b/demos/modules/gdisp/fonts_cyrillic/main.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gfx.h" + +int main(void) { + font_t font1; + + // Initialize uGFX and the underlying system + gfxInit(); + + // Get the fonts we want to use + font1 = gdispOpenFont("Archangelsk Regular 12"); + + // Demonstrate our other fonts + gdispDrawString(10, 10, "привет мир", font1, Yellow); + + // Wait forever + while(TRUE) { + gfxSleepMilliseconds(500); + } +} + diff --git a/demos/modules/gdisp/gdisp_fonts_cyrillic/userfonts.h b/demos/modules/gdisp/fonts_cyrillic/userfonts.h similarity index 100% rename from demos/modules/gdisp/gdisp_fonts_cyrillic/userfonts.h rename to demos/modules/gdisp/fonts_cyrillic/userfonts.h diff --git a/demos/modules/gdisp/gdisp_fonts_cyrillic/gfxconf.h b/demos/modules/gdisp/gdisp_fonts_cyrillic/gfxconf.h deleted file mode 100644 index a282a5f8..00000000 --- a/demos/modules/gdisp/gdisp_fonts_cyrillic/gfxconf.h +++ /dev/null @@ -1,169 +0,0 @@ -/** - * This file has a different license to the rest of the GFX system. - * You can copy, modify and distribute this file as you see fit. - * You do not need to publish your source modifications to this file. - * The only thing you are not permitted to do is to relicense it - * under a different license. - */ - -/** - * Copy this file into your project directory and rename it as gfxconf.h - * Edit your copy to turn on the GFX features you want to use. - */ - -#ifndef _GFXCONF_H -#define _GFXCONF_H - -/* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS FALSE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE - -/* GFX subsystems to turn on */ -#define GFX_USE_GDISP TRUE -#define GFX_USE_TDISP FALSE -#define GFX_USE_GWIN FALSE -#define GFX_USE_GEVENT FALSE -#define GFX_USE_GTIMER FALSE -#define GFX_USE_GQUEUE FALSE -#define GFX_USE_GINPUT FALSE -#define GFX_USE_GADC FALSE -#define GFX_USE_GAUDIN FALSE -#define GFX_USE_GAUDOUT FALSE -#define GFX_USE_GMISC FALSE - -/* Features for the GDISP subsystem */ -#define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE TRUE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_CONVEX_POLYGON FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_QUERY FALSE -#define GDISP_NEED_IMAGE FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE -#define GDISP_NEED_ANTIALIAS TRUE -#define GDISP_NEED_UTF8 TRUE -#define GDISP_NEED_TEXT_KERNING TRUE - -/* GDISP - fonts to include */ -#define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS24 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS32 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 FALSE -#define GDISP_INCLUDE_FONT_FIXED_10x20 FALSE -#define GDISP_INCLUDE_FONT_FIXED_7x14 FALSE -#define GDISP_INCLUDE_FONT_FIXED_5x8 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE - -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 FALSE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE -#define GDISP_INCLUDE_USER_FONTS TRUE - -/* GDISP image decoders */ -#define GDISP_NEED_IMAGE_NATIVE FALSE -#define GDISP_NEED_IMAGE_GIF FALSE -#define GDISP_NEED_IMAGE_BMP FALSE -#define GDISP_NEED_IMAGE_JPG FALSE -#define GDISP_NEED_IMAGE_PNG FALSE -#define GDISP_NEED_IMAGE_ACCOUNTING FALSE - -/* Optional image support that can be turned off */ -/* - #define GDISP_NEED_IMAGE_BMP_1 TRUE - #define GDISP_NEED_IMAGE_BMP_4 TRUE - #define GDISP_NEED_IMAGE_BMP_4_RLE TRUE - #define GDISP_NEED_IMAGE_BMP_8 TRUE - #define GDISP_NEED_IMAGE_BMP_8_RLE TRUE - #define GDISP_NEED_IMAGE_BMP_16 TRUE - #define GDISP_NEED_IMAGE_BMP_24 TRUE - #define GDISP_NEED_IMAGE_BMP_32 TRUE -*/ - -/* Features for the TDISP subsystem. */ -#define TDISP_NEED_MULTITHREAD FALSE - -/* Features for the GWIN subsystem. */ -#define GWIN_NEED_WINDOWMANAGER FALSE -#define GWIN_NEED_CONSOLE FALSE -#define GWIN_NEED_GRAPH FALSE -#define GWIN_NEED_WIDGET FALSE -#define GWIN_NEED_BUTTON FALSE -#define GWIN_NEED_SLIDER FALSE -#define GWIN_NEED_CHECKBOX FALSE -#define GWIN_NEED_IMAGE FALSE -#define GWIN_NEED_RADIO FALSE -#define GWIN_NEED_LIST FALSE - -/* Features for the GEVENT subsystem. */ -#define GEVENT_ASSERT_NO_RESOURCE FALSE - -/* Features for the GTIMER subsystem. */ -/* NONE */ - -/* Features for the GQUEUE subsystem. */ -#define GQUEUE_NEED_ASYNC FALSE -#define GQUEUE_NEED_GSYNC FALSE -#define GQUEUE_NEED_FSYNC FALSE - -/* Features for the GINPUT subsystem. */ -#define GINPUT_NEED_MOUSE FALSE -#define GINPUT_NEED_KEYBOARD FALSE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE - -/* Features for the GADC subsystem. */ -/* NONE */ - -/* Features for the GAUDIN subsystem. */ -/* NONE */ - -/* Features for the GAUDOUT subsystem. */ -/* NONE */ - -/* Features for the GMISC subsystem. */ -#define GMISC_NEED_ARRAYOPS FALSE -#define GMISC_NEED_FASTTRIG FALSE -#define GMISC_NEED_FIXEDTRIG FALSE - -/* Optional Parameters for various subsystems */ -/* - #define GDISP_NEED_UTF8 FALSE - #define GDISP_NEED_TEXT_KERNING FALSE - #define GDISP_NEED_ANTIALIAS FALSE - #define GEVENT_MAXIMUM_SIZE 32 - #define GEVENT_MAX_SOURCE_LISTENERS 32 - #define GTIMER_THREAD_WORKAREA_SIZE 512 - #define GADC_MAX_LOWSPEED_DEVICES 4 - #define GWIN_BUTTON_LAZY_RELEASE FALSE - #define GWIN_CONSOLE_USE_BASESTREAM FALSE - #define GWIN_CONSOLE_USE_FLOAT FALSE - #define GWIN_NEED_IMAGE_ANIMATION FALSE -*/ - -/* Optional Low Level Driver Definitions */ -/* - #define GDISP_USE_CUSTOM_BOARD FALSE - #define GDISP_SCREEN_WIDTH 320 - #define GDISP_SCREEN_HEIGHT 240 - #define GDISP_USE_FSMC - #define GDISP_USE_GPIO - #define TDISP_COLUMNS 16 - #define TDISP_ROWS 2 -*/ - -#endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/gdisp_fonts_cyrillic/main.c b/demos/modules/gdisp/gdisp_fonts_cyrillic/main.c deleted file mode 100644 index dd39a5d5..00000000 --- a/demos/modules/gdisp/gdisp_fonts_cyrillic/main.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "gfx.h" - -int main(void) { - font_t font1; - - // Initialize uGFX and the underlying system - gfxInit(); - - // Get the fonts we want to use - font1 = gdispOpenFont("Archangelsk Regular 12"); - - // Demonstrate our other fonts - gdispDrawString(10, 10, "привет мир", font1, Yellow); - - // Wait forever - while(TRUE) { - gfxSleepMilliseconds(500); - } -} - diff --git a/demos/modules/gdisp/gdisp_images/results_650x493.png b/demos/modules/gdisp/gdisp_images/results_650x493.png deleted file mode 100644 index 66dcd6e30fef92f1bbe834dd9e6db034db6567d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32345 zcmX_GcRbbK|F8Izip=aiZ*?QCJ&Ws7WK^HxV`Yzw>`g_u+)J12apNW`+1aCPE|-g3 zT(0cxW{>Ogd;5HU-|rtD*In;>&UwFH&vg#m$UukT3ip+B=gu+Q*M&YhckV*$xpU{& z=`I4V)SC?p#^I)nn_wfajNA>Y93=J9n-1?C*T1 zN1@%hbDX7vEl#%M{U9W|H>99QmfVsped!^4l4r1*D)gHCgfK8MI`zc}UN zS)}Zzf+|uRzm@+g-_?BmG3)lbKF2F|v)va=!@;6280WiIs9fbXsB-BPY50nUW9l%IH+Jk7p}O`Nq(4;KYj?9Js8W5VZrXP$jchtIi}*T*Vt{I)PZpX>@VZ}qq+&?($Ve79Q0%U z0t>~+n2KU=^_`H$cu5R)^~lGpF1!vM)VpHDrq&+}_B(B$Oix}aS#n$UTnX|Ct=otw zrm5+BujW?0+DJWi=Lyb9-Iw1T+#R+3PI;a{Sfg3%R9_;5m$VQb>!>yMSA>hXC*=t% zUF-~9vezlGND}!{$}}ZlWb~Z($>CwS)pYPg|M{!?5fLxDd`GuybHW9s4EI_sM``Mx z>loy?_V4w``OVGs;3mw+7(SPB?9I=0g()s6`_Kes(~OOEge8QQay+tTT#L#sRlB8E zW$$qRK~Re8eQaXivkJSRWbhbWX0csQ$Jg}o%kr%$mHJ~DIX8$hGWNmZumR6bhP54Q zTxXR(XPuN%IV+`!wYt?{LcQKgtERCf0MVV=c;x%CS@Ottup~Wfy}^pe`kP9s=L(xb zpNf*J^nwva_ypEPHOUFl;Lzqy_DPP${y_37K2PA8&oG5RY7rj0ezRr2Mb6YW&uC%2 z7M!HOiz0J)Bqw~5OllKIocqq$+|mDMe{SBoL~r#ZBL98~Y0GBceanV%>2heDUJ@bb zLEP)mkG}@O2Hg+NIV-rl+Z-(X39C1z$>04GHt5y$V$jCO!&&}=#7^QTYS44jAEWxa zgzezW)k@CcOGgi|KUd_O?K_$VAM{5&jd+>!weLgNpx>XnfzC^Ufq@51f%a`L19x{( zgUd)l{%V>+K80xeak1XxK6!sCrAeUaRtc37x=g_b|0!POTc%DE2Prh>WGa4eTP-#0 zTI0(m%aKcjZq%d@o6phBI(Z$e16#e1RW3D|ahm6-6A@N|_f2*TJqbsu+ znJhgU_P$#DSk%MtK%2yU3ON?F4Wlr>R4U#-N|@4}87;9J-nZ&06evC3N9!QCDfyx& z2gwbaLxin`lBu30&nasQjV_g>utb0HQ^du)8v2J1Ntwzx1X;gDzVsV@HtZdtYy+hc zBBs@RsDCkZvux*dPK$RtcyKYo|09QcbPgHu)1+uW*yH{bBPk`U#^5x;(;R(bb}>AD z_GpWhYwwq%%vz?D-9fcgR}8tSEvUJp$-3EhD*Tw8c=VKXFt5T(-d7|EyhPZ}ufsLE zDfgT6Ogp-DAmUvG72?=M@5H&dz{m4n54*Q^Tb%D$G`&^pWYp74RS1ejjcQr);U6l~ zFAJ|r0I35xZ*EV&1F>0 zvd`<|z`VOBitH)hqrL5SUxQ6+rL>-IJWRU&`I)`a8_&xvF4H3r8IK|9^u`lGP0#3K z+2G_5W%o~r!z~W3y_14L1y6(zSBwhn#+`3Do8w+SLbr=LDD4 zg5J~r;BY?RKnt;izpD;E{F{WnW2~aP6@4T)`p_x;N_< zy7w-v0Xl+cUv(UuG23c~==OdtiL-jOdiy7bZE}d52j9k0Ci6(WnDeZ0dM))0cmjRn z7IR2=79;j4^tb!=2fmchy-R{?ZzmN!g6VS8-mY5S1I--88AjP}OqceKqNN@)#j;jK z%@H2fZf&E-Wc)%ug)~cAgdK=jgiXA92^BplS9;dr(UzZpoO@{Jr0N6}6n`JK5z2&!&&sr~=Ig7M!fVhz z2>!jlrCzwI>|;inmF}dKA6*M1UGk|9_Y-I!?hkISsUNvv-8*SB^faoa9jcu@G@6M& zb4IY#rE*J>$?z_bT1qKp+zA%EZiQ8&)8=EyDo9-hAm7S6GeA>wtkg)_mf6$BhIwi# z%;s(0JV&gGwTh+_&jrt~o$}C`YmvDMZ2PZ~P@Xr@(=m){Q_3;to{*j+uC-f~(o|_( zv2lZFdWr~d8q&@jVPD?RlQ+k`XNYOnaJwVSRxQZ#m?_Zgo)*4irteRO?Occ}aUk?( zlSijCx$774a>DHz>fUd8`CPh7e|(jSa_Kt%$f;ZtXPSQhwxpKYbn)1D6dgj>?1t4lI<4aIr{H}ZB6dYEFi6FPb8NWFMpud$fa`KaW2 z_ehqosrN<(SUF9k+pNE*|LflGXv#la)KxIo!IK7Oui*qHR!rj|(Vy-|*%teSwe0TZo_cwv zq)selNc?%0AX$_eg$+mHXT#qU$^=@OeYBcR%r6QaSW*sXyc^V}g3W>&Al%iRnS)wF zoO0X`K{H!n0*z8M`l2(VO>Je?htpFlVb%iS2Nx+v-{7rn0?kQnXmjocx^{&yDnI2g zq5@4f;$Ma)zW^DaL1-rsE?d~jMN~3FXi73iZ0dHp*pyWI?O+4`C?MEqif|$jiZsCH_vrdH(R2exj`%JIxyBY`&apf6Y#m7q+gdR?03T? z*q^OER4A+Q*%vddq!#rOL(CoA6hTSMv9^xI?+wE;g)q$r#!(IX(wd%?KKzPIxud@> zw@a1?vgJ~4(X|_F$(%$FJL_ujP8lt4kMPJGU>NO(30BxNfpFA*r(t6F3sLcYC_OGo zY5|-mwfLodYra9OgTtF0%Td9BU94d5afEOPvolBh!S4ia;brBfXlFWyJkybFhpTf$ zZJv3FHFBiJHQlY0$1;utd()6R&z=e$$eYt+<)I%gPFwC@!sJ)P)xRXkGqkUj7S(en z{>{M@ThJ=QSp5q@L)WfG*S>zZwVLwoI8yMKx$K}d3VdiCnsQtteF>E&G5cuCelTA6 zKJ2evC3DfMhV0#2-rD7RU%EQL%wWmS0j~xx-3k3YcuAQ|Q!;qT7RgBYU0_@zz+7hN zm~(~qsP;0<+&!YDjW!^n9ovEJ`y*LEvC-UDXTG%seaaG+(8SK?gv1)1pv1 zHiqj|QbHA@EO*}$NumK?Sb%Y4trmInNM_s48+PC9CFyClGZYkP>#4!}BnIRGJ}OHk z>Vj`G_2~<{zP+73R?dv7;eTCo&9i1tGo?rgE!K>tK^z^9Urnz8vl8yf3Uexa65(bJ z%(T8b`ttae4;Kxprad|FEw#G`b$hH9=l0rU0!}m%2!15TK3Rf{nlb(pHRF8M>IILr zLTfO(hB;WH&J>T;@gVZR_dI`GwDI8`r)$%)fo3oUr!&BK;_BQdQ#PVW3hPu0@~u4$ z>jxUof||EUoqvn6d8&9^z1}U58f({$zmVQETYg-(_aQ{uL!`ywHT|I%ujY*2vg{E} zp!4YJVBV>q^LRmt?DEx;8_=n9**BmA3_PN4I)d~%4BCR%lBDr&RGRL-F)ZPAB zav#E=?WA0)U}GG?oEtOL#|#e&yviCwr%7`!X19v}pGTQO5&3-sKV#a22K_))N+D?t z2;C6-Io;*7v>2lhE#(CM+moaq?9wJqg)ZNp`3?C#nUSPJ+jL2BJzh=Y$2?stKlxUh zusYdUn3?$yUq84wyFV`nwb6juoJy%Dz6LHlrHoR%a8F@{BXY`v?k=+JesfP+H=P1Q z+sDnQu#=ItDLZ=2%|1^Jk)n=_0q)lycupo$JMI*DEGd{QR@1@SW_7b`we*{cnH@AY z9V2Hvws7w~w>E}1#hIou<(ct{KidjBmU&_Zj5WfgT1$^Vl&EWup72N`Y(q}@CN6s1 zCsdQ(OWKm|*eb9h=xk{11fbr{3CuslSv0gnT`FfrnPNm93JPBdKjx>*Ugty5+0&M? ze%HVT#}F8qDg^q{MA5h$VRXN@<|YqoY{fjq-rK(avu)zQ>^JqiI^>2}w$ARmYg)UX z7oX*ahDXkPzzsT^_%AD$r|txOMbjVKr6G>oD;wlaXbxYF7i@KBmCS$DwwQP5zH)Ajs$5^>OpBYN{l+I-neBuK8RtX4L+gbrhX>Ch zXBN3*(Yk13Og{Fc z4GW}F3_sm&@wz%Ma$urC*p_8+EV*l5jPl?(anA8N@!ge7ubeK`CkDY5Hkxkg$;M0? zO=NJTSj60;PBoqw4X3kF&woChojQM`)_N?BD^c#5X1S&#n;cuhTl(A1w%WH*Y>4$rUzznWviq2+!t6qTvp)t_(sK zCN6A22ShA($GlltA77k)kghR;}S;!rrmo+ zV@AgEPxTQ(Pv|W^$!_@iq%Zlx-u&fbg`pYbk49FrFwU72z}&xFL=DkDv+E{dN%--4aBIK?PQxzix+$}FnpIfVD;-fGL1Yfri z{q_CQ>vA5y8zKFvSN0>+KAZ*)ru*fiR|A7I@afQOrHQN@2_DJC?jyZ;4fEBKIiVj+ z2vhF+wW#M4G)HWeIPiEuE@Qxwvs7dJ_|^RO+;RHwPmZ?rW954`DMc`*V$~!utf77P zAZxsRK$dyb5Z1uHCl-=kzGD9AIE)z|p!E3U?w#Ui>dnrwkyLl>bC(Q zsa^ER9(yr4M}!CBRhAI5Vt!n}Urja`C}~$W1P3`@$2hVz-dhMQs^O}OH|whpBdcq7 z=K0IxdEyj!Vs9$5tt0Z>%>=Amca}r7$Pz~fb;Nx1Eowq-LBLkSdAwQU zO-XYlrz(?lj1!L>eXgSZc+I%@iXvMoLkc@xvqJ=>w(NjAWtAtlz>K~lD2o1F3U^Fv zsX7A`Oz7a8;f!*l*Lo#PPh{|B5D;3|LA0G96Q98vCHbtvwUiqVKly}t)9+E-Xz?n8 zRK9HE;Qmc@P3E7YLj$@#9sDt$Hd5^5YG}vw z#=UDlMx|{+H*yS=EyR18)S$Haj0>5@^UX6&_8uui2G8}dYx;PzS$H8VrOm2C_)fDH zQ<#WWGnJ+3osh}m?-KQ-pH?rxVPdUrAFZh##|ynrT$q}YXdid9(gt2a9mKo881#r4 zwqi=g1w}v4rfE8OawL4>v+%_6NqwW*#Z3g!eupPUo1qxqCa&Da}^aggkg%ql-_RTL5Q=5zps{{zA@pAHpvnc=*t45 zap^a$deQMFSz=aFIk%@I(?x;}TtH1oqsR^0pv(fa%C%L%^Rh?J072t}RA#k&!VE^~;WWz(KdirjDNYn3N0MGijT36s(+ZoF;8wrPWAChI|BNEt+{Qb zugn?YU5tA2SVOFTSIyL8`>iO9Oz5g{Y6`kv_{#1H zu1JfZFDj`mTHItV$|DnNr)P;;Yj_%Y?q*`^2UI>|-QMe8>IcM{!As3ly0>cF40P~y zy1w^5sJ?)?34{*rb^zOC#_NGDma*v$OvgtC9i(*r>S#g1Zb+NX&5?rD;iZXhKR^2f z5)3G{jr2Qpb^13)N>&GUmxDsB^cKre`Kiue=Nf0GjTU7;o9w!Nm7SWq3D%jE+Cgm9 zs&DB-hMP!LjVIT@FD}rpPQD>_4G;~dRT&@^VHOG_U+-02 zS}lVhQ?g&nt`b813C%+lR#C-T)&jD$nB~JGFPh05_h;25lyWZ0cV??jjZL}TK|-1P zNNBsXYipI?lDyAkos>g!tgsKP?Z^H|PKz+F9`oKJcQNDP+fm8Ls|dcp!x*E^D)S#y zK{1~4m(4Giv65AGZ|$ybTs32sCweyD*aPA~K zW@AUJy4yE}5@oWVPb^%Vm5iKnADw-$8{)p~`#$iSz|vzZapI1?=j=<{lqi#`qWTQv zQmgG)t!w1-DzJLa?W+m)-N#y{GW&N^dVktZOhlNYK(ona4Ys z!=221)mirg@2a}oC+W5fSklaEwi7+M)9Rmnm+oeVQ4B?jYN558M+-BIlemR_1nl<`XwEG;=+KoL=uW$tnz9~)%7-d747)?IG92KNwV(a|eVkc}Z}(l?3# zLf5danX0b297>D7MAyQ|3`A}he20ew1h051dT_rY zfeDaS;cXLw4D|v{Fi_Yn5!s9|Ds%3^RZV8;m^2=>Kvf(3<#y@&cRW=!uSqLxJPV{& zqwU$=yl5LG+b``~iLf+liiX{YV2Yt>9yWnS&g=}3nd3}Ob+a3_&bd5a85(o&V_6L+ zrU}}<{D?q2yd73p)Q+!~8E?~dV7YL=vS-#LZ3#*dD zT>2lom%{TQncVQHZe3QmhR|_X{8rLs*kp>O<6Od2y$=^sn}I06+^&)SDwIQra&HUT zX2W75ZK{q|&}uS&WnwOC=BJ~%`AuCWc;4K!D(o%TqFSH*v}xF++#wxoQE#5|%}nUl zNJ-+aOhV82`l@~F2D03Fiha!MdFDr6k|Z%opm z`1sA5vd^QcPyC5Ul}Galw~6!n8VcAR4f(EexfgcJE5FLyjzYhKEw<~yR@G0Rx{nHe zRd9d*-RzMabuYWz)BlU>n7?inpXyB_BVQ7qjzJI3w!n^12I+90&013rGVtS5x~0O1 zM)6(h@7kj&uqU1*CFbq%`LAgRnK3>`ms$}S(J6d7{Wg4y_Wkg<8f0--*c#=YT2x%E z*OLV4#=8cN*Sp3hE+`3HIR4%6&PtGD^X@lHj=wx3q5G#>l7*ne%Sqexzr18=PG>vI zqdm>|Th{%4KX|>?OrLti9^LsGOPKqe{K5;gp26GwgC=Z5PANV3Aucj@&O8id-p2R` z8!%uPLEq(LUtc~k6lAJw{*&=U&t&6`B-%{W(K~id|0ya9=QF(x8GE(8TkcJV->%ts zd#5U&NMk{&i`n+ISZT22@M&E18RPl6yCzeIWFh`M?U1^mroOg)ebRrRUusrW%}R=} zx+3EjIB8W<5ri=A^$adqlw8%3+Ah}d;PB4`J5|u8)!AX5XkNUn#pr zr-ZBB2|l6UV0HWxS~5i`n80U6V{t3gmPQZG4PV3Q6Hk_XDzZLDzDiYyAE6*fK;Z zZ+kc`)UamT8ZJUH`LyHN zi&bx$hj#Cx7F#VHQips41tdz|sFTd!#J%KCP+0V|iutj8^~hw!vQu3>y%V&r+ITFx zVcWS`6GWFlrr;d0xTI9E`2j9dbdbr2>(s5UkNkSdk!JSYN62!g$sp6hkrSb-BgL(B z;m1O8Cni#HgpyQkp1V4XjUhkld`sD}MahT8JI8OM>Wg=KOs96`pKBCp*nj?RjR6x& z@25~}@27Y?$+U0(bi4eKo577Jbmv#$g5C1lbL%0!;hS}8|*h*H7>%l_o*i;^z+tYQ)6)`uExK_o2$4Yte+oTVRkb5 z9b07kt@!GQ>oXIDv~3^i2Z9;dT`TpJbrt@jDwbf@U|^BDvHFEg4c5pf-+iUB%PSR- z^xq=?HmmA#F(>c4;r#lf)7@s$N=tYi`BFbCs=r;Y>3kl~Mad`lE_q#33)fnaJcRgG zySANtBh~ViDRPx50-`G$jPA=8LieM^>f;4`bAoazTyp3`LQ9_%JvQwjd;!h7Jb73C z3#)g?eLX*<@4=(or}m%Ct7D(kSAQA~DvTcv&U-BzQiYNYn!XqKVOeDBWnAYxe#EeQ z)-5Mhf+&wF7?(?RBvvPLsQA2h$gaQt)jc%-;r{Evs?O)mMDN1N)widfJ1wW`4}P4g z{}%g2v^Pk&)9V{#Q=4-zrI%oBGR5Tl%l=j6(oTl#>VTQ0E8*`P=gnBvJ)2vBf0jGE zrfmClsnPtY%KI9k-?>Q=aw`fkg_g}t!>*%78_vVJE2;+{hJz1`oevI@yiOtg*j6do zq|VImDFy#DiW*jjndZ0=@8yJlPHGrvs%RK(y6ThMv0i_FHnpz%s#|@}_P6@3irXsK zp+1%F$9{Kwf+)#O-d`{&#~xP0{QJ=<=OA#+E;Qtv1l0_38XD z_~6EOsPk2~BjtbgUz6a2SA2%Icf1;lC5O(hF3Zxcwjb3a_21{f;e$L!ni@-F?%#v` zyCIF{B?PVgt62YzFrPMMmFK5c8xYO$Srf}QdyP83cXR{)BCfw$_iK|^nXbz&ox}}j zFPFUmipRIZbJ^Fj-8b1(Dy8v8O|kpz-xikDnAJgF8|s&|tc#8MB^W~Z zb?lfgbd*{);byw$B@$$cZ7d!Pl{?;>vWVVjuFakZRiKcqasD0(-bEYodFjLn3v}bU z$ON%tU>CH1upZX*CUmG|8f$EcrxI3|d?$TZ_Z=N46&fE-66ODyGYOG=JgJJ#Tn*ZL z*eo9;fOlJ2B)O$1UQ@d`sW9n3!D!jBe~MMUIq4rWL8{~T=X0pv2*q)tK$8|nfwJCQ z8!A0HgukuFBuxw*iww!OB{tLr^|B&BqxrQO zC8j@1;oJ$vESnTr$IJo^DpP&Iqll!`?gMx9?f>t9BcdZU9H); zYOmVCI_SLMUUtXPs;-*i;dBx!bu zV#ZVL_)Ui&mBFY1mJ5=P*!TrIoc2louJTF19PHg_LXr*+L`;!%p#o(G(>tHH@I`jCv-D$u z^tq$E$ei+!)+?V)s>^jX-(WKMR+Z72%>VdG@taxmVnjwg$4wT!AuW|`i{2`qY<312 zRc1tlR;(Hm@O=zua^?up9RP~VKytivA%W)>u6f;m;U~%>Ca)~D`|p0ooov1k0*31G1)5@Yl z(Lz>n93Gm-CxR->%|{2rkXj)d&^-5wfXYq}5$W>KNgW0i9#02^I<+4eHl+xKLfKAt zoY!_g2haCiX0_jG6Ae_kVM=-k1M$N^E5YI`QpN8-Tar=|F>OQr{0{QQ&R`c_SOtnx zJA&?>4UEQ(4KBJ!Qy)C3!3tMD)fYWF*4jHbfuNQS3k3Ws1xT&?>QwVLNGP_=x@?I{ z8w-c}%XV(W=P*i)tDazna4#A2Y8XO!_b885PV@)Qm4A_|>EwB*t%8 zupymGTSYk7-35k^2M}#3+t^1KpKS{Eg)w6~avg^S!8yil^7^7HRk1o1q5i`OU3fs?qjdE%6loStWjvv|77 zv+sJd#yqHA57`J&q*z}VK>p}j3_q+yHuGeUgo4%ow}vMbQc%rJ28Q;J%UdJE=?0*x zmBU1^d717;p?SxXM|R@CugB4~jzVI&qjQ+gKUzTu_@1sMDf+a?w;36s+P%rgfeH%6gO$`Tjyq4BLeAt>FCVdQ=3Jhke&1Msk2g9_c z8&^W$+~$5hwZJm+z}tzET=1i5D9^D7X5-m1W=i22Gc$90^HG0ouA+5pgY*qknBhH; zK_=2jRs3>aeHH2u%N%>1JS?*XhZ=%Ylrc;3F)UL+^}uF&`8Juk&eyNf+U)e^A+`GT z^Z4}IY@8vnqfu(#&_ulJvrb)5T^XkuW(juoGAdmgnoCCHDX{xea)8bzT`03Dsps;{ zW?AGwO9me9&LSoE{~sv`KO$$s?q|gqWvMdcDzfG(b~3c%zS*CYzx6VEt0G(hXXZw@ zi^6J9ONigFvoQK@gQD#F2|V->TaxZImAEB)5&R%irLC+=@KQdp6oY=`$oBA#i)hNn zdrQ5bI;KcJ1W|$1V$W1={u9+Cr_Rg_V`$7Wun5dTVh(I_vBDTuM+4D7 z08y=XIQigym9II~U^;nxeS2$rY8cj718_ziMh_Lr0eN z`TxQXx9XJ12w59cXQ+~JKS#`?|1OAM8zleB$b2Po#l!* zBNX!h_eBZyG2L#=Xr~;-*$1d4t5<;yVF@-poVaos=U>(VlZZT>9Ymge)vD6T zOu$d!~gH-7YCZGrp@G64Jg@%FhgHU^Z^c0TmB0;He>)g!9p-VqvAm0 zx|NVv15x&VP{!RhCo7Co3)7~xBU`ra%`l{mXo_sYj<-Vc1L#a;Ay>PzF(h_lIp*I7 zKR40wA?DF)mNLaYUiAPG<^na8i7IBP!)8t{78lrFVmwSYkfRuMyx%fzF ztMSCLIcG<3;6K&gkOE%;Tl9a4#h)Da(604_X2H$VM;;$J(;H|2lD`MSd230_WI9pj z380%2EFuti%)727_{SJsaqYKxSe)QL;w+Q+gzS5jK0JOqk5>?RJP1@e^qDBjZGhM^ zjfZEe{!<)CRmeZp$CdTjg+u?nFB>l=^yN1+>_{w&>(1VD7SI_=1xHsEMuI7p&n%g) zz3lm$0lrQbunT7$N^t~0s#SYoW}yYxj0qpJgaOz^v=+4xFP^d1%f01Pq;iur+D}~C z1p%N35|!Roh<8^A8V;3#z>P5wOyO(A5!&1^_YN1uZ=O!TQi+r~2^%NWDzd~mu4K7g z_pnMZ>%Wy_`U_+5vq@QpY)-(5DzDa#0T(&i=}Y+Ui20qyHRbtK!Q}odDFHzyjjRgY z6EzRGt47$?kr7xr(+Q@)avPFaD9bK)?KZ8k9W7Mvvirw${H?_MbaK#Kq_&5w3mYs! zo`nkRPu~avmxcB_iEP$!X#=qETm*lU8IE&$K4~ddwQ3x)Q^&jaT{Z|DwrF-b{l8k~ zcgO$p=$b&1AyYIOXLS>O+e92K^^cH>VHOPJ=Y%ve2c6#ZFSxAb2rCP4!1sbO@bK0y zlQSNBh!{1dF&62D2qSvw^Y~CYDCT2f0E+YbKq>5T4l2gBKBD7zfaRchDiwv0SaFsz zcVt@^A`eG$2D2w{NBTt-SI!c+peioBK&>iMTw54scOh}OpPRUcB}gAA#6{T5OklD(!BYQU1=H^9|C1EjEdTd+KP5#!bY z9sr(WuFXRe|K`;*5S*@5;TA__Jptam4j{I+urUpu6)w(HmffYFhjs0DpW29^@(Kfh zXyjvy&;Gj-<>bgFf;uB%TcBK*I#LJSpj84&?vBmxkx)LjxpaJMTb3_Y%HIZ0=7|Od zI5SnTuF{?JcyW#(XEs;;{f3PDbunmcouM)=a``_p+sYY&d zYfD@M_W$A>Sui@mhkXb?jXc9t^`rkn#Q5g|Ud3?jPX%kKTsJP+b&N#FcoT(`yrlVZ zN6UZ%La2$SC&j?5S>dDtH1k`ON!t<*1k3RoQA8l<81IzPq3~^k-xyg`GM$#Iz`=Zu z8derKe!RTS~Hft*Uh0OI|*^fdZ}qp#P*X%|lx}!XWFqP9EfF{r9)$ zj)3G{YMgLyhJwer+I2ye0&qMemgF0R_S?$|zoi5Tt7BNKd7!bbFwWJ=lYO$dhX&UE zq~3Q;Llft)fJGNZsU)3MDc9K37htE{{2cOAL z-pOe3p8N*Qv81O);KsYfkypfW?GsY%e#W+Y>CDUIH^YGPgXKxE#{t{!imI3>Zgm0^ zq-+U-3Am;4fVXJl@e@!`Nz$9rArMezhAO#0hos-%!GVGtSQ=Ni0NM#Y{B~5j>Qgn( zOVHTO&?Z-%HGtv~LjQf`8%-tNo9{&UxfG>x?F}Pm9z@Pe;t*$S%ayH*xKjb|fkRc2 zmU<1wjAun+;q9vtJ@uII!Sc9Iu6iS3j}nA3PuqoHAHRoLh0_HZ&WT`Z-#A- zMCFwW?D@dcp*5S%jguI|dPt0VK_gKdD5c+=uZ)I4s&PiDad#`rAA8F^TD(Zm_Ss^I7Qg{h_f~1?6f-_e7oN~KmAIsv%RYms+Z+FDS|yH)~TL% z*Emw%Yt0czH-?H@Dqx)2EY)Q&OF%CLD{q-i-P{er@z5x($%L(LlB(o4+~=LiRq(S# zzbMQmccov5jRBgs6`8lq-9B>{N>^v=?*VpU3IYy~j!r`JE=D^d+WxuHat%Y_ZqK}; z4ZLE#Q+Q_GItNEsU%>F>BQZxd-}FJWdzHYR3uj1WmiBjvzdm>&( zbzJS4W*ZK`XA-7hd0cWVYGqE&JIO$pqH;RyRDEV`e%b)Y!~L4`wUKOzu`B-DH`dte z*+y&ExZyYe34m$a?9Y?|ZKWa{8SB`f3g8%aNqWUISPKhOMmr=HS9s=o6oCptP~Qh_u79caA6^f642Xz4!)>`(U<~&N zjJavAL8`CsBJP4*RK;brJdH%4F!Fxi$u)UpL@&Z-(fRXo`!irJ`Bxu;j&uMJ zl0&ThOV@H&(d}1Xe7-fRkO_Ae{{q|^rAa-OW!2(y1#w;;> zGuyQ$6!dy(^G*5M&Ux{K8yA$+H_R_;*u6H zt98b^%9*3o@ZX;uO9qQyII<-xu*W&`UJ%~=PsXzY0Auxo z*)=9Z0B)>n94y}U*LF8-CK6OgJM-;{D*(WwvSsmTPm$dqbKjtCuK{Dx;i1N@1{6>k1TN2#e?85_ z$B|`n3@X8H8=1FwpjRK?bUS`~MDaNQGQ27oBK~YsVeMu9-UV^9WO7awMenSGSRibf zftu1=mEOZI*Z^_Or7Z!-L$-&d&nrueWvvUPZP0#Aa4v1uSa)8)f1e$3R7t7hpJbfe zdk6q3PaKW{3IepHhYd`6+CC@Y!A7!k$zWBTKx+SQ~So1 zxucaBzl8Y4w!Xqbb2NsJu20lHr1Xu#hrq>9{`wsxq zfcFuE39@*&z?f~F33yW|D?DcmS^^{>5~MY^WwmvLm|;EMzjdhnfr{IHDnLkY+C5;> zEU|scRrf%WiNu~jP2-3Gz^HRO$)Dv`_iSwL+qObnI9C<{kD)-XjXu*iD|L;irF#Cg zgpPizP-I?!CLXTkk5Ixa@iya%fa*wu#J<8)Dk~J&A6C{%u`_L zTe220zCM)__L7IRb3hoQiUDo&98Sf8#o0K3NU=C~;Eqq%pe?^$((a^+#$s{qiaut#N zln{EvWee9WihFTALHH=caB=UJ(l&?ONoOiC9U83e_%AXPNonFKsisBrtg%v70)RM9 z29!Q+6da1U*wWUKm!0h;jK3ML-E7owU4RtPD0h~9aKja=GSiLQ){Vz~g;6Fp@@0zL z|0%15we`<0mAxoIQu_dFsI9}E&v_AiQ*|~co}Q68xKT%}=NBLy*m|VyO+~8Y-miZu zF$rQkdj~v*1Pfs~u_09kJEtq&u^0DR^I@7A<@2thk?JB|$xPfR8 zIt<1(&TMT5=xRfiOx;RbAPfPxEnb{GPHXe&5LFsK3(Her!yIbo#r6U^6RC~%1yL%! z{i*ppXl(Ks_3HXKu;_K<`NK9lUYecEZ+0B-WuHlJtNm%X*NrEjddRk34ev-n4s-0b z92?o|BywsOh*%V^t^XGS4SHkF!KE<)Uww4C(skPkJ)Jtsax@w_fOCxb89Z?tpkJ|$ zYR>YnCE5*b^u!Y?iq+!ypZ~mc~MN( zc@+l|W&@OClmyFd26`lvLCZtbMGz<~Ir{9g*7ub!lhnjRG11wEkM|l`SxYS_wPPvn zMAr(tBG{-2Ef3u9sWHaLFjKLTDSFS_Q^dHFTI}O9B)gCzV^9wFOV~Pq6af+2(MW(3Qn>2*Jo6Dmnnp16TvB z(auy}>no^Ik_9L{3!A#j!OQcTcSd^p?MR>fM$6$=_(n}5fXmJw((&+0I;6ao?PVsN zYZ5Hk%)Q_|fXM;(-6ERE6FcevV5FfaEP-1QNCMEh2!1!~ONv+}* zu%>OcEpgv6x+nhPj;+3~vAzb&%LWwg$K2^Q78vV&Wfxv$09NxZYcVj9hj5&sfE#Jc zvl0!m#k)_bbi`_t_4BO24{ktW+fe|e*Tq(Utv(N9byikh1i~i>hK{q*P(`IIfI5UD znN&hTYi=H<^x0q2+&pchR?Un- zv8-@rx~r`24zwO%VZ~zfSv(BLepYx7)aL!t`U|>o>5TMyh&&-D9SsM0{PpyQm3dWe zRWC&FULs{}u6gC2OI(d8r|ZDlXki%i8x9dsNR{BGMISge6n4uiY}2{fgBKu@*l;(B zXwPP)rm3H(RZ44*?P2+qp8?~S+Z_nec`y`TV_DRP7zDRI9jgQjfESo3AO;aJj<_S^ zA}Ac^DjH<7S(grV#paCk%Q-zj$TO({dJ4=82S~uik%c*WuTp`n&u^VhS(&(tU`oF~ zjAv*AP~Tltm~Opr5iS96htq6Hz^8sC3z?0ER7yhlqSyZh79`eF_VsP~!QCdXQks;W z94D}80+C}g6JqOo!G;0wYoOPJ_dyiTeIU*GH}n@{fj{lmed5QCU#(lOcNK*V3GQI- zEnNpvec-Tc?8Pc;+cKc>Qh1`Dp5<;Lcm#K}-_FDZgUX-bvPYfPYp7gZ06?F7V~*94 z;^;YUJS=~1)pWTdKYDxqNfb~L5^TQbkx<8BMK2hnBC7OkVPaT$;w~!-)3NTTLRmL5DZvmy#A#Cu1$xmPwVJn@IW!&b>8r_cRu=WJo)ao{z?-&H?=$oord?o;c7Ycm) zp-OLzvg%b_o$g3Zprs^+m}4J~SG^02Tga^LEUSRm8QDE8gMys}Yf&*}Pyn5{<Wg(ngD&6!ubeNm!~st^MdXn#ik)r6oJA@*x?q5hQY#M&FAZ5uE*y?6+Hv%N%A}SOE@Pyy+bInRcpov5QsyK^aAaIm14YTvVU?hGG zQ%#QdWp?L&gSXwM1yYdCvdci?jJ$Dq1MsAnjaNu$^Q=@T%-HdQvGlUcFYy z^R@{Rcfg%tD*e}R7{@OmW^m@| z@kUuqt)6p0sMRTN07|JJG9T;6%l+wK^EvH|^jeWnh_K=sz!kZza3~}Q$ikgvqbEN( z3b=~?gVG(oy93R;3{{CJ#N1-}x1fOir<;zMit_cLtZ*@HVC9&`@x7veyy8=ibJFnu zzJ!cmb^CzXO*O3F1Qe*4t+ZF~S!sce)MIrdIl9)=YGc}YA(@J{j#a!PMy@M3(8*VG z1OX7w`1t>*8cdXsdO{|!qI+&fVbVdBD2~u0azaqU*`-z2 zk5(uk_O6CT>-40I=;ysjruAOg1v!~b6Au<{n+l%ZTy20!w;<)ou6foDtjVl!oIYS9 z;ef4`1gtm&?heklTiHPLcV;>&tBAqN(osjbpn3{UI$ztWMDX1I$@-%qUkl4j64UQh z0y}(sYAVn3)&&+jtcOizM$f{BJLCI9&ApEV3VO zLlxo>P@#bLRNPTrcQs6n0m7N3jk}vK*wlywMW5^apqWZIbS(m@jQ~=AS_CjFd3Fri zuL=@-joh0{8X=&o{;#R)j;FGVUR!gshakiMY6BZy8-e znW5}a>1JlntnBRU&3kV5-t=FeJokCd`JLbRe!stSo=4!R$c@mUJ>JyPGBFG%RNg-d zabV7nilZlKnUFD|d~t3&D5b2y9regDvC6XcAg#)-&c}p=9ax9_5=J8vi@cnu^u7qd z*iM!xB^qmup|e1KW4$2ZhiMcc0Y@gUslNGSWD9g5=$>B&0{HI+K=qLjlFi-qqwLVN z*{?rH)QnvhF$+dmcwR9kI`MSznyjui-MN?d4ID(duXb;!?|iU74j4;Gh4(PNXPIaW zK!pMtBF_vmE8r$cy0V1xvoryi9D@No00C|Z{g=`36Qt$P`k#C^fEqh_-9s~SX@PGD zsNIu5*P{mwcoWcQ0hQu1OJp$PdkhAiP~7;ME+7y*`Pq`WE!pMkK=#N^{f?{p(C=8j z-w78FgdZF_>1wADEBJRF5YBiy& zwqKqYrErm@|Eig;+Qa!5rdF6LCM#>-j+ppfVxsq4_x&d~_LdZlWZJ_X0kC=$r~Qf0 ziv)VEJlqR{mqzY80l5Nr+HwC%ydJ15!O#MCnN>28OTB}(0Ta)cE@RN0taL90%8fnu zqip&IhBhmxuspO)1_Yi;53L;#S12@wJ)Oy6d{t7y$z<_Qc+LW9T2nhNj6tTs(BK

2s5dO9@S@uQN+Xn`rK6M&s*aPzXw{l{zFzQ{x0K7iXiJ2xrRUk5_G(N(yeh< zeK7<$Cr6>t;Y6Pl4CRh^r1KeFfS5K-MNDwzn;k`+cJSQ2=}iT477(L*ALynVG;>85 zTA4g3TX0a6DSBX&Smwlp9m7+PP{o**ae~2@7kS35FQWz)d;9o}Wr{u<)}H%4frEJo zevN_|sz$%$Cq!1eG{}@>cy$Id_ScqsVYh)COCXj^#luu1mFBVBqdmi`9{}f`th$ad zDY~#WL=DP76d0OOaGnHhkut;xp=zd&#Tjosi3EKe*69r4Csu`)T0k#=pPY^{hH_%( z_c8Voat?IDBi+x-Vdf&$)ekk2gE9~YPF*MHcI3idDK!We4~B~eNQpxn62?62 zhLvRO|Aj?94#%i?5J7Kpqz*Z9e;xK!`V{KTO2)uWZyf()4%{+$ggeOaQK1q}4U(=S zhIn0UIUFgFW$PqmApZbBK?PfN@bO!eqg(z)+$1UbkJaAQ10%1@z*a+l_*B|27L3a! z8?mI+Z6+f{Rldn`TLhThk_VKwx{D4adIjZ{z495eo{&002rm<4n~`)IoQpSk?4ekI zAZ8ukjZbPyMz2qou3;znYEFm%6$~9tp@@^13+s9R&Y+2_2X2dmCpW-ZG0%FHDh#0r zuA&J3swDzR^L!gZi*()LQNcW7wFNQ36EMN^U%EXTcf6wzWJn}(kOp}XXKqR&wBXeX zu8bGTjEP$^=}6EzNzKV@>r-1uulYobM_N{+%I~tQI_Q=foo_+g9_G)6shTg}31A+3 zf&o|1C$`XKm2-)MU-IKW7f*ZX@>oJ^2i{h+8VVaPziF-8#0&x=C=79Bgp?T*DG|f$ z*DKy7x5J>q%U!o;c#IicHBGRK94Z1Svw|9(Z;Dfdy4YM>*XEA7nH#fdh}j(!JfYJH zxBXsEg3g)t!g;YdP&aDj`6O6}3K3=tY+ojJBa+*Bq@Y{2&*28Fu3B6xIEUlizk1+e z9>83J)aOM^rBfo8%#LnjorHXoW;$SEISltS!V)IfT>G9em$ zr}PXipw2KsO2`8rQUnj(%e~5{%kJK}@@~fOM4MPoZwy7b2%JY3(1=l5J$nMnx%)0nn5W@J*YPkLDXPKe^ zop&c{ceP=2)aH)3xm%X{J6Ikv!ZgMNRs{+82vC-z46}oF-^{m=yABGy4uA4VIJ~Fs zvjfD>t<{;XmDcW7_i0qQicC=+ex8eC9+Cl~;^!5lGBl3wDSsA7NxFg34a80McPIy* zB@d!`&L&gD0<-@U#Z@Rba(mEY-QuuZ?^*ArPhy13HZ8fvui~64z70Bmx1Ah1mN)&y7 z9M<;3O=B-!ub3iGn7o^j{xc1-_liAi)p(j3TT&hz^$DcIPw}1NXF9i5gL0$AKK+S2 zBV^NRrZt(a$)8Tvw15Pi6fPX2B#_no=;BTbHzxk21&C2^)CC^eu=>lJvO;VmdZc#j}5#pN|2v!zqnGRmkkxqpEt}YVQ1P*(-3Sgc6 zD=#FL2wmAe#;fEQHQmPfCm=5hKo*32;88QG(O`qu_FsY9v1pRW?^`*nm4cfqpG=X- zx`O%q0rj0M`O{;87*B!vpwFZC@7-c=I!A#N;@ZRIFD?tHu=RcbD{m5qxsBG^$z7}K zMxqJPdUwLG_Y~!mS@nxgjk0=48CCrxD<=OF zHiIS&pawu{PQ%_y7Tl|LCj2H!7eC-+4NRhCHZFPy(PxHGwNCMt02Q6$G<=a7Ev#Pg zxZH5i)dX_|(ik%i7xk9+awVAu60Z9v(~#U*6X1VD1S@j6_}7esZc6fY$G1fiJLmp2 zWy$ZmrxS~83pDd^DLyFywd2;$&hNM@{#LUt2_G4zh>2*4q^7)!>zNME=J5fAq(-W5 zTeFqu@WfQn_HCTl%&YXVeqxPBq-I57++VjicgiTTqK-E*Cv+ZPHZW$V{w_C@Z^+Zj z@MacYyAx0YUb5Hb)nuhk{jp#sHZRKwY%j+l4vt92a*L!cD-{Z09gTL4c zil{efYHO>Ngcy4~F6SP7ueR(yA&vhtaDw<-m)Vqs3**15OD_KP;PH%pbE{^Lx9dGD ze@(Q|XYCBk{#lQA63(|q;Tr%4>^|o!wjD~lvoffFhdsbQt9;kP@&<~O=5K8$oXp>} zePt{@_NIvPGpf{ICxc%+><%in-o9itu%qYFxfCEC0(&D*_yJ6yG^Kw^b;t){i^$jS3oBN;-? zzari5prnQHmbHRfLuRI?46Y!_oIQ=Q3KLkS7qsw?jTeCc{R_70*Vf+n-n=B!YozMW zs?q}zrV1S$8&^^?x}n_M`*sSSb?e}o?2wg5+X*U$f-=pccRNo;P$bmAd<|u_GAbU{`;d$`s37DVF)=gB@&VYfC7~`7(NvP%NPkjDfLZcZ zb?FmDS(NMw-Qw}TvW3n}Pa9rAYF){@Mwz7==NnsBe=-J*RGr z?7avSWQyLs>j(hig(@`e?E+%Lung}8EeOnZ4~TOdA4-KDiwxlIGJxa(W91lX`6P-< zA6>yA21}?>mCLsP6p5S`KV-!Wi`2eBQ#53uGd57z<)X`+q-aiTwR}qB2j`Z8&Ro27 zn_=QQmBWUWWik%H55NOV!CSNZuB!x{4=}B4GKB zko!3W@67WZ4gjUsVJDTawDyPq8g-GFkdo|XdaY)Bc5fjfjt}_WK6W*FmbJyOw;3PXxep3IIm|m09He?^XfIbXa=9eOn(M2#gq%x^g4Z>j z;x``^XWgH=T6F%oT;dg*5IB=AgIYyS!4I*pJh4PDl&>vCa1a$!@K znozCG6*Qb(aIZ!Zxi*|v{P-f^?G<1`O29|U&qTlW#0d5*YnufUooVZgb-9igvd~M+#OKI^cFDUGd)kE{3nF%` zcW2m?6RrP1jo4r~HwUEdph-5J3Pa5|?=!7cV+y68kRvW@S$>bw4FF zQm@6LWn?qwuc9rv+T6|WIA{CTARbo_i)2>K112s6nBro+KA-r}SPOYjJmrPLVe=Yo)xt&^(g^=|V4|D#Tow{Gg@e};V?Er0Dw+*F{z zYp?vj&ABb?3D0UvQ4OH9xb(~5E9J_TT znBbu(jPC`s6-H+vRmt@lrMt9xkKcaAtRj~a_ecaIj+9Z26C?-OlA!0+`{F`MqF$>A z)k;r5QNP>Hv^2yM)Iyc`!{*0_AFK?I;}be+P6Y=ili1H zbd64n?c^0SFle7gZGlQ^G^@D{E`?@c5@5_-)+!$4r2iy8U>4owsjS~#GEZBtK9;}; zHm6nleORWvEc|T6=;I*a&-DVM;AMKJl#*^~HIJPX#gu*0=#shJ;#IeTBBhi@Iq?}~ z*x?L`d9(l9J1D$U+}I6dPJr8XtVt$TGE$>-oABk#(8w{>!zIZLd14Fz!ZH0 zuU<%Y?3%}o#LI4#Z>+ae$c<*F;vjnWL*4Y((^O642KG~;UG_$>k*qe}63rhtaIJO> zG72YWlmIhZLS3sv`*UaWwQ5$5_OgcGsf6y3(gzS%!7r%F`L6W~){?otiRQ&IlQ{FW zJqa+COutTL|1%ThdC$r?m1GH}=Dz#5Y^4}r%9Q@@AA8H`XQ}b<&88%NlRj3EPXCnr z3lvDX;LproOo-SaX;RQOT=9z}LH{J9L~1b<`oWVMar#RFN_Ug!Dx?K}cU9ozM`k36 zqBiLU2A$&omo=LZ0xjl^A0A@1R92QJwb*H>o8 zaxVf77pSCbxJs&kUh`P}ALg<{0JASZn4a(`QZ$tfATKZfWPlE?9tR4f3x9=seUH|61AFQn99;?qAHQsFRCKaV-ic zB`5e!0J5_3>lG_+3cIUF-UL2h0KWFS2ML;xML=Zy^^`~sCufLb$eYe`yctkx|FU9f zoq86JTHI}t9sTy-#2DC`wzh{H)wune+YzS&Zu1c+AF(@FahKq#1+?$6{uuDG1Kdv> zpTYCMX&6(i3w5XlnzG?7jE1xLMoR)s< z;4t1i^tyocn{pKL1J_^0rq8FSR3-H$aK^i%_(TBiIOF)itSedRPVFUJN(49E%(iL# zGDw+e@a>Q61Ilf0Y90^eL)DmKp+E2l5KnFI>Lir}F^y);hbIGA)7476{(t~h^x{u( z2%5;SgK9s(Ui0l+AoK4%M8O1Cw`?H0zXg1a`(O#I!*!xV1g_rJJK{fwNxwgUm(Js2 z@FN%mh`}bD(cgeTUT{Amx`m0)SKx0SXvbKhXI10Ywy{;ypB*@b)jfr%nX5{H-%s4j z`DL#&tVr!71ka;AuFWfT`Ln*&&Hkg;0XrPVZGw!-apx`1iEW-~lbAKbNYH;*P7-~Q zn78M$Z)bYo9#Vw5O#dAF@2Besfa|f|@GlimU8)K-@*45j<|q6;ph`tX%Ck%MoWGVZ zrv!ol9a#PT!A9QcI(yHf<=SzVM<=vW4#=a;>*_neG!&=Rz*3J)F(isVE{>_gXNL@O zWS|{XzQOdf1aDtdljBt;NDH1!*s#Ki{_#sN*1b&hbpq~%%A!Pmz`3^o9qO_?E8^o< zY-9wRL17v!eA%z0)&wt60MbTjeal#ey*&{+jjv@uOw<4(7Yb|=?tG&zw{W+E$T>Ba zL&=dH>&pa|pmTE8J|QlRSMNqH;hyI24L!loA7DFj33zn^&=sV(=krW2t3dm_FQG&| zqcm|Dr|qAB^fp!_7&MCoQX>5jY}xh7!g=Q_L5Khaf{Fq;Gxtyga_-zY36$q7r5i zrqa@Wtl}N7{Zw9x$Sv2NIG}t5Dj^i!+Dk2m;f0bt2S$mKzB!t24gb{f5JL1jgsDsE z6yv2>jQXdbFBC<6E;`eCq!~Y+VpKwGtQPa7_4ReO@giZe<`;6^ukY1x;{T2$1;-uP zAy*#nN3a`mQtp<50 z-Ea7uG74P!XQGDJFaT5dr>vcmn?_7f5~35aLGcggHOMBF!G%=IV+hPXPV@0cTzv%b zpaPW~9JfmR;8d#lSobdmzB;GY-n3}$_*%X`34dP@^zAM-+$B1#(KOq=f9Z{0wF-9= zOH9Fg6P&{Fg9aG+dCkj~VJ$-Rz73wYVWhL=A%mIxRNfB^c(?%-0V;nGCnw}3&XukI zgMki{+eQ0?GjjzIlt|E3$#Ex?tCj!V2(&~nK^)1EK-$+apb2G%7%%qf&J-kH6>2{5*1U}hI8_QLxtuhF85-OV=X=JA2|m;jH-QfD)A*&?2rX)07oT)%XVdc(Ygn@jryQ^j*J!jPpc!V^8pU?At+@**9&-hb#kT$KV$Nb`Q9I%= zdr}x4a3rgF2Q}LVfW1y<((ly{k)Y4;_C#|y;?POY^al!uHHU({VNX5nrJ4)&d)5rF zRrDSZwR&*I0WUWRabTC=UI1?$JHv8Un64?t5uDqReh@HGjhpyC^Aaj!3Vhr{yk<>X z>tXq`{L`kT2vbTNuoCl4WaHlFFJa!YFl*9ErXoVG{i!;@=NU*_I`i@_Y*YvA2}8uN zG+Oi-1(G`Wb9Atb^Jmaz(=D|3R>A?fC=xl^U^ZCM@^eCT1=jG4G{JBc83=T&NBMK1RipdEC;1 zN!h6_eQy}+)ab4rb2?Vx(_|%yVobMAeeo7NYd0`%Y&*MY-dpF1Q2}erTWto^&dY-Z z9_+$)43sr=mVLD!WjL#5K3VOhRGw??zH3eZTWuS{&qeD1F*I0wHGcqOa_WGILR_fO z#3WcA8H{xwohOWyYyM$tXfJ*rTEM1*HSrsDkF=vec8A9~=FQ`}|6B0DinX{$*^{RuXUTrvbuLUbJq#oQB+_M&8 zI=$!G;s)pgzGVmKMeeY^9J@-&(?5FxXh`HjKPM+AFUS;GXXNlRx%&_6;gC2`d5XTD z>NNv9i~#w;&lUYUyqS%E_cU}fHG~o)#5I=Re9ZpcTg8A;Z9BN!SM_lm$J7AuO?TT4 zH$W)>e%C&5Ha(8UQ5t`!1vD<-NW*7(3@45apmaa@AKdsC~Wzp~hMx5-d{)q!XI({ult=n+&y@ z@s1A?FXr$N#QsfK1wYu$?p_Kgh=g9VHrE248~PBUxq?3*2G@JP%Baji>29MdqXb2i zntP#t`dGDuXyxF~h7}d0vJ-aYpjH1$?-XcJB4Y}*{xF#u3M3VI;82O9`AZv5?Jxsk z7RZW?b0I5lGUr7b9ekrGo=8r1yf1IqG*Qe!1GN51LxHSl_Ez%*bnP)hc)?~Pwbd6B zrQ9N*B>94pl*}Ewp#7&L)yiuahnEk5(=Fyk89TpP$Qn1;x?ej;;G*K^V~K^wqAN0V zIW;^$KL~&CD`mlrlh!qSMIdC%q%~cF;Lfh#&R=k=r6|Lf|4NFKg|ucvwVaaXL$yv6 zl}hYwd}E(a07;0Jad(#o$MMgo&bP$4-+k?+ig)bdMtUVh{B zS6)(%q10J3A3Ugs(}rROcvss01*==Z}S9>lMibuQ;dus`2= z-7?Xm^5uc9%&HyMrc%y7B@DuhT4PV&%>7W{DLj4G_=Tb zu7m)xX_Vq+&SF-LzA*K=l7Z!=?r zTGZ-FzA)t`{n0;3%%%m(m>VI7o=5QSXfiDPg~zn1fAc zujcp}HPjwL8a=*@BLv)wSG`hgD`Kuvt&;=3n$Hn!p&rHGyNek5EoF2+uuM;G=K#CD zlIvQF1q9T$rlu0>j+5aF75Dh9NO8i?UYJTu%kJr7US8Jy^|dKRIt18%Mbq9F6@u+< z6TdzR35g1WiZc*55rNMjU^3-qb_%>Ymj=gGfwT!ueX>A!8OeDo9fUyi>fL2;O=5M` z#>p7pfab=KejT%GLJG8c2(6%_hq9{Fw;ZE}HSpUtSST<_Lm1ZC?B_*-ZVvC4f~w(w z0h}3-NsWXc(G4WA9NrZNKr#V7Tpe&byf?yL07ot%0uV0Adm{l8OZa^W>_8hcQ2nZ^ z0M)MT#@AGkRX^8jQ6MR?Kl>MQ6LQ4?wknKuf*;`CLG?a=wvxaB(I`0gmylF6QEvww z{e}Zs1E?KBm_2S^PVfOtBN3jrp{PZPbj3le281c0eZp*W;K64==dIg}EynR;Bs3uX z$Z(eKi;1wAGZe*-2215C|v(SKeBv__3! zbVg4dpPVTcgm4MNpzJIVEAql-m2@)l?`^=k#GCd}#p~pZauQ zaJ`pUObYK={`%r=Yh9jMX3%8>rk93l<5jsaiVz1jP3V62n)yns*Pt_iU+sa@ra(Qf z$>Ha*@*g%z#qr`A1Z#69Y1w@NQ+hM} z3i%?V>Oq;d|4LWARw+wh9M&gOhW&;T-K(nxV-zZ>0Gr&|1XYCD|oX6pg zs-(>4$z~wUet869ped#Ua6nFIPIJH%k;6lr=GXCaADTsF5IuQ1(4m_AI>R|CMZ^(N z-8`9QbVxUQvms72^y@YT8*M+>I9zI*d*j4|Hv7COO8l7sw@4C|#|iKx{@4hV15Z*9Im;-FPl_ndRD46n>v&OTy#WVoVOuC>3X z^HVt1&Umg?*CnmGy1%3>kfGrRMTS{NFa^Km&UI=*C&Ke_()Ea>?q>?;!4DRmKUfSMN^igZan|GB z!?fyKyftN+S5_XBdsml+PjB(pO>5@0ESb9)x{P!#x;Rmf=!~rNKRLfOu<bzXo_R6mpE5agBWJb9j%vJ&9YX#6&HM^_yxG$9k06d^Jau zxUp)im3%RuO{a?9J5xVy<0_Rt+j}f8U2LOL_FbF(qR&oGq3=2fFM(8F&Pi1)Fm0+< zV98WDmXXq_QVYBv z*fTXVn`HPtXLl?~1-ZW$^vT6h*y+=!MXuFBeENxG2-g^?92kdUW68$7nu!1Xy6B}4 z#znQpI7O^bG`rv&V{~jWuo?f=NPSyx?nvK5++^5j&$+Ro|Mpz}J;Ux5zc(vH>BlZx z_5j{^zStd`@HW^}A8ZixHh33qt`|W>9kGncuGzTZVR(2zZ1A+i?YuZOXGDhBX@~2% zQd?P6iq`jvYTn(-kP0)SY7D6+5TkU7t2$pvVwkoZBw4yAsm(EbW@{Evqnci4S8hY1`UI6 zZP4hl(UzCz%{h4AZ)u`x;-PK+)V4)3Pj=7di+O&1>d;9zv*RZsrsX6mJl%frlr zDM9Ug%T0(p=E3mx@CQL{RX20bz7+`@z3(&D;~Ojg>`b~^ewN=T`HdP6;;_KNrp^u_ zu~c7GwaVEP7X|aw!XV1>XKDW3Pe?cXq_5oHke0qezVYwJ6~9IKH43RrqM&*a2yx(x zYUtKMf&{QY0cWBC&jZC+#&OA;0}DHb?FGm3AmTh0w~k-lsvdLo zRd5m=4i@=xup_Z`K<^WN*Ee=-a$qd-tXM=~gP&k|KzsWqE78+ee6Z&ydZieK1l zyI(>1?n-HWni!K_EJIXaJdA%*MUkEUTvK`d6IRwq69N?piYWJ4Sn+{_V&6lA87;%} zt&b+6r)S3r`kW~WK5E%2WLEG?AD=2X-tA4J-MY28Wn*5K1st+3|ENP~-uv45iim&X z$LW$k1yXp>v{i06n5(Cuofmg!4XLF2W6xBMf>)H=Wj-_V>2*fS#P>S?tXwSJSU>k_ z)|j9M^M=UYO{ihEYt5+hoQGOHk@&0RkI$ZmT`gM4ev-m1y@62^LY^NXJy)d`= zZS8)1$-YInUYX6djC=UtC@JT;2!*K0uJ)xzulEZVy1d^F^?OSq&d$}lKjlpb+v$s8 z*&$%4r&@dMX}IzT;ma?1|qe z58f70U@WcHVX$*f6Yt826z^K|aes|IwWhd!c52RrO=fkekQ{lpHr`Afnw2d10xr%~ zRhXsBxvcV5bWM{E&Pn=JiaTrOAJf%;B#*OY`2GXbMZNs!rOc|lASC~%uFA7q9ukGj zw3k0l(b~}XkBYwE03S^$%$9aXPx70tAg>+>5(`Ka8*Di_Ny!%kIS)$pDhhT!pS-ho zsvZG0N3GX6dmUDTW7v`#cS6a%-}NYVomKIANxbY!;c;)yy!or9)0g3SvZ}|G^q5cO zWem2Y7vBB8+w7UVCj-0k#%Y703cRWHnd_~^wYZvEiKP+w4d)n;`0a+)jQR`O!B>{p zkMpmLHl)?n)A|*;J@{p@BXQ>NBF5w5$0i4j?G2%y#dfk~?3-63TG8gpya=;L_Y{R6 z&NhV&iw_1hyv}%XXZzo_&+Z+Tg5$wUhKO9zt@9n=*W)j5A&!n+7^u4{2Co9rmQ~nw1g?6 zzx!jSxh>tiWOCQiyl`yQ(cJ-FlB={<9)?xP;A^SQbLJL?uUeA76gL#9k?_!mKk)AC zeA8dj-@9P-!YYB@|C!sn8&3;5DaM%DJDl`tYPS=VW$$q;E}63Qj|z{z>pd*pN9{lP zhpmE2XY?7@@+X2bYAa|e^=+k$RndaN29t2K=S{Q%S>5&F zCTvygzX?a@%unl^c4HHN5% zLlPYMRb|{1$T4eZK>`PtDgV=v7y!RdiTPFeJ6Kz%VZJrg}de9afFR8QCCL0D{VJw z^<1tTf!FjZhbx6^95>{W!MFZxIU>^y*N-o1c)Q_PMOIl|lV4pHU6Y?)mKi^^XsjS`T{b=v@HxDZ#Y@3LcdNvxuE8Un54E-0WK4Sd%F)Kup?m7iwfjUZ8gn9u+ideZf}hO4Hv96%V;t4vTNm z7!h7RI9oLOj0SeY^cE>ca^X;y+YSFE`rZXD+p_QP;4^TK9^cYu)gQT4Rd$-Kj{45KA1=e?Rqu>FH*H>*U5w)^3-_%0>GDl@^)N%t zkn3~*8$xetK`f~G^X$y(NzQlm;G?kV*%8JfZK;MH$X2^2)=ngNZ_FN)Ba zqwSyxqImFex4@fg`RC=PxBr=+-e#o!#(Vxyww-hSZUxQr(fc6dt!oyN2zDsGN4=S~ zs+x5N6C4;_n@scSS8=rKH zJzp1UHGk??Hg9OcR zZy3*zi^-H52S1$$hidsBts>jD7mdRx~?;D90Hh^MZh_@x#zTETblBdb9Eo*gwQG z-`%NKPO_0H;JeLX>C7cr9q#8b*0=wiI@$d{GV8NXf`*>oG~!&Yu6m*{9CCAtbeK=* zPAO`h8SXwL%{vr$)0K1i*Z#Y_Q29{0VJCJv=l22;!cs#2sqT#LvHv&z4}+7SqL7sH zzURA9!-3iYWAK8daf=C(w1wKF!_Z=x!XRf$l}Gipaj$0OQtB>}$?B_7HCgm5f2G`A zyGqIkJMKyO3f^gNSQhd?t@p6kyJ0mU8}X@CazeaDLU8Slz4(n&<+T0%o&TjE*bA~L zY~(C>i+D)-4r%hrYnOeSIc)b8OAqX?8}_BQ^)D(%_wK+B!|bnddPvymj*MN)E=+uI zeKnXjZzQ!~1+GS6cg#F|^z_oruvKm~UcCzW)JJ{tdxtw22fo@`HWkV;Ycb$+@c$^u LsmT_=?)(1_N!uob diff --git a/demos/modules/gdisp/gdisp_text/gfxconf.h b/demos/modules/gdisp/gdisp_text/gfxconf.h deleted file mode 100644 index 76127ef9..00000000 --- a/demos/modules/gdisp/gdisp_text/gfxconf.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu - * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _GFXCONF_H -#define _GFXCONF_H - -/* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS FALSE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE - -/* GFX sub-systems to turn on */ -#define GFX_USE_GDISP TRUE - -/* Features for the GDISP sub-system. */ -#define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE - -/* GDISP - fonts to include */ -#define GDISP_INCLUDE_FONT_DEJAVUSANS10 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS24 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS32 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 FALSE -#define GDISP_INCLUDE_FONT_FIXED_10x20 FALSE -#define GDISP_INCLUDE_FONT_FIXED_7x14 FALSE -#define GDISP_INCLUDE_FONT_FIXED_5x8 FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE -#define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE - -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS TRUE - -#endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/gdisp_text/main.c b/demos/modules/gdisp/gdisp_text/main.c deleted file mode 100644 index 7ea3405e..00000000 --- a/demos/modules/gdisp/gdisp_text/main.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu - * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "gfx.h" - -int main(void) { - coord_t width; - font_t font1, font2, font3, font4; - const char *msg; - - /* Initialize and clear the display */ - gfxInit(); - - // Get the screen size - width = gdispGetWidth(); - - // Get the fonts we want to use - font1 = gdispOpenFont("UI2"); - font2 = gdispOpenFont("UI2 Double"); - font3 = gdispOpenFont("UI2 Narrow"); - font4 = gdispOpenFont("LargeNumbers"); - - // Display large numbers on the right (measuring the string) - msg = "123456"; - gdispDrawString(width-gdispGetStringWidth(msg, font4)-3, 3, msg, font4, Green); - - // Display the font name under it. - msg = gdispGetFontName(font4); - gdispDrawString(width-gdispGetStringWidth(msg, font1)-3, 20, msg, font1, Green); - - // Demonstrate our other fonts - gdispDrawString(10, 10, "Writing with Font 'UI2'", font1, Yellow); - gdispFillString(10, 35, "Writing with Font 'UI2 Double'", font2, Red, White); - gdispDrawStringBox(0, 50, width, 40, "Writing with Font 'UI2 Narrow'", font3, Red, justifyCenter); - gdispFillStringBox(0, 90, width, 40, "Filled Centered", font3, Pink, Gray, justifyCenter); - - // Clean up the fonts - gdispCloseFont(font1); - gdispCloseFont(font2); - gdispCloseFont(font3); - gdispCloseFont(font4); - - // Wait forever - while(TRUE) { - gfxSleepMilliseconds(500); - } -} - diff --git a/demos/modules/gdisp/gdisp_images/gfxconf.h b/demos/modules/gdisp/images/gfxconf.h similarity index 75% rename from demos/modules/gdisp/gdisp_images/gfxconf.h rename to demos/modules/gdisp/images/gfxconf.h index 9e37988c..694bad28 100644 --- a/demos/modules/gdisp/gdisp_images/gfxconf.h +++ b/demos/modules/gdisp/images/gfxconf.h @@ -31,9 +31,10 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -41,25 +42,7 @@ /* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT FALSE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_CONVEX_POLYGON FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE #define GDISP_NEED_IMAGE TRUE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE - -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 FALSE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE /* GDISP image decoders */ #define GDISP_NEED_IMAGE_NATIVE FALSE @@ -69,3 +52,4 @@ #define GDISP_NEED_IMAGE_PNG FALSE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gdisp/gdisp_images/main.c b/demos/modules/gdisp/images/main.c similarity index 97% rename from demos/modules/gdisp/gdisp_images/main.c rename to demos/modules/gdisp/images/main.c index c581f942..b87f663c 100644 --- a/demos/modules/gdisp/gdisp_images/main.c +++ b/demos/modules/gdisp/images/main.c @@ -44,7 +44,8 @@ static gdispImage myImage; int main(void) { coord_t swidth, sheight; - gfxInit(); // Initialize the display + // Initialize uGFX and the underlying system + gfxInit(); // Get the display dimensions swidth = gdispGetWidth(); @@ -67,3 +68,4 @@ int main(void) { return 0; } + diff --git a/demos/modules/gdisp/gdisp_images/test-pal8.bmp b/demos/modules/gdisp/images/test-pal8.bmp similarity index 100% rename from demos/modules/gdisp/gdisp_images/test-pal8.bmp rename to demos/modules/gdisp/images/test-pal8.bmp diff --git a/demos/modules/gdisp/gdisp_images/test-pal8.h b/demos/modules/gdisp/images/test-pal8.h similarity index 100% rename from demos/modules/gdisp/gdisp_images/test-pal8.h rename to demos/modules/gdisp/images/test-pal8.h diff --git a/demos/modules/gdisp/gdisp_images_animated/gfxconf.h b/demos/modules/gdisp/images_animated/gfxconf.h similarity index 74% rename from demos/modules/gdisp/gdisp_images_animated/gfxconf.h rename to demos/modules/gdisp/images_animated/gfxconf.h index ab91a9e7..e0158441 100644 --- a/demos/modules/gdisp/gdisp_images_animated/gfxconf.h +++ b/demos/modules/gdisp/images_animated/gfxconf.h @@ -31,9 +31,10 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -41,25 +42,7 @@ /* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT FALSE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_CONVEX_POLYGON FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE #define GDISP_NEED_IMAGE TRUE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE - -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 FALSE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE /* GDISP image decoders */ #define GDISP_NEED_IMAGE_NATIVE FALSE @@ -67,6 +50,6 @@ #define GDISP_NEED_IMAGE_BMP FALSE #define GDISP_NEED_IMAGE_JPG FALSE #define GDISP_NEED_IMAGE_PNG FALSE -#define GDISP_NEED_IMAGE_ACCOUNTING FALSE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gdisp/gdisp_images_animated/main.c b/demos/modules/gdisp/images_animated/main.c similarity index 99% rename from demos/modules/gdisp/gdisp_images_animated/main.c rename to demos/modules/gdisp/images_animated/main.c index 58558185..9b2b5d2c 100644 --- a/demos/modules/gdisp/gdisp_images_animated/main.c +++ b/demos/modules/gdisp/images_animated/main.c @@ -115,3 +115,4 @@ int main(void) { return 0; } + diff --git a/demos/modules/gdisp/gdisp_images_animated/testanim.gif b/demos/modules/gdisp/images_animated/testanim.gif similarity index 100% rename from demos/modules/gdisp/gdisp_images_animated/testanim.gif rename to demos/modules/gdisp/images_animated/testanim.gif diff --git a/demos/modules/gdisp/gdisp_images_animated/testanim.h b/demos/modules/gdisp/images_animated/testanim.h similarity index 100% rename from demos/modules/gdisp/gdisp_images_animated/testanim.h rename to demos/modules/gdisp/images_animated/testanim.h diff --git a/demos/modules/gwin/basic/gfxconf.h b/demos/modules/gwin/basic/gfxconf.h index 3ef9c784..1e6784fd 100644 --- a/demos/modules/gwin/basic/gfxconf.h +++ b/demos/modules/gwin/basic/gfxconf.h @@ -31,9 +31,10 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE +#define GFX_USE_OS_CHIBIOS FALSE #define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -42,15 +43,10 @@ /* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT FALSE #define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE + +/* Features for the GWIN subsystem. */ +#define GWIN_NEED_WINDOWMANAGER TRUE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gwin/basic/main.c b/demos/modules/gwin/basic/main.c index c46e6969..eee22f29 100644 --- a/demos/modules/gwin/basic/main.c +++ b/demos/modules/gwin/basic/main.c @@ -37,7 +37,7 @@ int main(void) { /* Initialize and clear the display */ gfxInit(); - gdispClear(Lime); + gdispClear(White); /* Create two windows */ { @@ -60,7 +60,7 @@ int main(void) { gwinClear(GW2); gwinDrawLine(GW1, 5, 30, 150, 110); - for(i=5, j=0; i < 200 && j < 150; i+=3, j+=i/20) + for(i = 5, j = 0; i < 200 && j < 150; i += 3, j += i/20) gwinDrawPixel(GW1, i, j); /* diff --git a/demos/modules/gwin/button/gfxconf.h b/demos/modules/gwin/button/gfxconf.h index 256ba2ed..6d0aa41d 100644 --- a/demos/modules/gwin/button/gfxconf.h +++ b/demos/modules/gwin/button/gfxconf.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,62 +30,35 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 TRUE -//#define GFX_USE_OS_POSIX TRUE +/* The operating system to use - one of these must be defined */ +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE #define GFX_USE_GWIN TRUE +#define GFX_USE_GINPUT TRUE #define GFX_USE_GEVENT TRUE #define GFX_USE_GTIMER TRUE -#define GFX_USE_GINPUT TRUE /* Features for the GDISP sub-system. */ -#define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_CONVEX_POLYGON FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_IMAGE TRUE -#define GDISP_NEED_MULTITHREAD TRUE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_TEXT TRUE -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE +/* GDISP fonts to include */ +#define GDISP_INCLUDE_FONT_UI2 TRUE -/* GDISP image decoders */ -#define GDISP_NEED_IMAGE_NATIVE FALSE -#define GDISP_NEED_IMAGE_GIF FALSE -#define GDISP_NEED_IMAGE_BMP FALSE -#define GDISP_NEED_IMAGE_JPG FALSE -#define GDISP_NEED_IMAGE_PNG FALSE - -/* Features for the GWIN sub-system. */ +/* Features for the GWIN subsystem. */ #define GWIN_NEED_WINDOWMANAGER TRUE -#define GWIN_NEED_CONSOLE FALSE -#define GWIN_NEED_GRAPH FALSE #define GWIN_NEED_WIDGET TRUE #define GWIN_NEED_BUTTON TRUE -#define GWIN_NEED_SLIDER FALSE -#define GWIN_NEED_CHECKBOX FALSE -#define GWIN_NEED_LABEL FALSE -#define GWIN_NEED_IMAGE FALSE -#define GWIN_NEED_RADIO FALSE -/* Features for the GINPUT sub-system. */ +/* Features for the GINPUT subsystem. */ #define GINPUT_NEED_MOUSE TRUE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gwin/button/main.c b/demos/modules/gwin/button/main.c index 1ed2ac43..f210d84c 100644 --- a/demos/modules/gwin/button/main.c +++ b/demos/modules/gwin/button/main.c @@ -1,3 +1,32 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "gfx.h" static GListener gl; diff --git a/demos/modules/gwin/checkbox/gfxconf.h b/demos/modules/gwin/checkbox/gfxconf.h index 0864b6f9..9bcda6be 100644 --- a/demos/modules/gwin/checkbox/gfxconf.h +++ b/demos/modules/gwin/checkbox/gfxconf.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,62 +30,35 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 TRUE -//#define GFX_USE_OS_POSIX TRUE +/* The operating system to use - one of these must be defined */ +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE #define GFX_USE_GWIN TRUE +#define GFX_USE_GINPUT TRUE #define GFX_USE_GEVENT TRUE #define GFX_USE_GTIMER TRUE -#define GFX_USE_GINPUT TRUE /* Features for the GDISP sub-system. */ -#define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_CONVEX_POLYGON FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_IMAGE TRUE -#define GDISP_NEED_MULTITHREAD TRUE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_TEXT TRUE -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE +/* GDISP fonts to include */ +#define GDISP_INCLUDE_FONT_UI2 TRUE -/* GDISP image decoders */ -#define GDISP_NEED_IMAGE_NATIVE FALSE -#define GDISP_NEED_IMAGE_GIF FALSE -#define GDISP_NEED_IMAGE_BMP FALSE -#define GDISP_NEED_IMAGE_JPG FALSE -#define GDISP_NEED_IMAGE_PNG FALSE - -/* Features for the GWIN sub-system. */ +/* Features for the GWIN subsystem. */ #define GWIN_NEED_WINDOWMANAGER TRUE -#define GWIN_NEED_CONSOLE FALSE -#define GWIN_NEED_GRAPH FALSE #define GWIN_NEED_WIDGET TRUE -#define GWIN_NEED_BUTTON FALSE -#define GWIN_NEED_SLIDER FALSE #define GWIN_NEED_CHECKBOX TRUE -#define GWIN_NEED_LABEL FALSE -#define GWIN_NEED_IMAGE FALSE -#define GWIN_NEED_RADIO FALSE -/* Features for the GINPUT sub-system. */ +/* Features for the GINPUT subsystem. */ #define GINPUT_NEED_MOUSE TRUE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gwin/checkbox/main.c b/demos/modules/gwin/checkbox/main.c index c6094323..23d3cb17 100644 --- a/demos/modules/gwin/checkbox/main.c +++ b/demos/modules/gwin/checkbox/main.c @@ -1,3 +1,32 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "gfx.h" static GListener gl; diff --git a/demos/modules/gwin/console/gfxconf.h b/demos/modules/gwin/console/gfxconf.h index 90dbc7cb..c1307302 100644 --- a/demos/modules/gwin/console/gfxconf.h +++ b/demos/modules/gwin/console/gfxconf.h @@ -31,9 +31,10 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS FALSE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -43,24 +44,14 @@ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE +/* GDISP fonts to include */ +#define GDISP_INCLUDE_FONT_UI2 TRUE +#define GDISP_INCLUDE_FONT_DEJAVUSANS12 TRUE -/* Features for the GWIN sub-system. */ +/* Features for the GWIN subsystem. */ +#define GWIN_NEED_WINDOWMANAGER TRUE #define GWIN_NEED_CONSOLE TRUE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gwin/console/main.c b/demos/modules/gwin/console/main.c index 2175ce04..0efd1c99 100644 --- a/demos/modules/gwin/console/main.c +++ b/demos/modules/gwin/console/main.c @@ -41,7 +41,7 @@ int main(void) { /* Set some fonts */ font1 = gdispOpenFont("UI2"); - font2 = gdispOpenFont("UI2 Double"); + font2 = gdispOpenFont("DejaVu Sans 12"); gwinSetDefaultFont(font1); /* create the three console windows */ @@ -75,7 +75,7 @@ int main(void) { /* Output some data on the first console */ for(i = 0; i < 10; i++) { - gwinPrintf(GW1, "Hello ChibiOS/GFX!\r\n"); + gwinPrintf(GW1, "Hello uGFX!\r\n"); } /* Output some data on the second console */ diff --git a/demos/modules/gwin/graph/gfxconf.h b/demos/modules/gwin/graph/gfxconf.h index 51c5bdc4..e829605a 100644 --- a/demos/modules/gwin/graph/gfxconf.h +++ b/demos/modules/gwin/graph/gfxconf.h @@ -31,33 +31,22 @@ #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE #define GFX_USE_GWIN TRUE -#define GFX_USE_GMISC TRUE /* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT FALSE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE -/* Features for the GWIN sub-system. */ +/* Features for the GWIN subsystem. */ +#define GWIN_NEED_WINDOWMANAGER TRUE #define GWIN_NEED_GRAPH TRUE -/* Turn on fast trig */ -#define GMISC_NEED_FASTTRIG TRUE - #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gwin/graph/main.c b/demos/modules/gwin/graph/main.c index c5b7b352..4dd67ae8 100644 --- a/demos/modules/gwin/graph/main.c +++ b/demos/modules/gwin/graph/main.c @@ -100,3 +100,4 @@ int main(void) { } } + diff --git a/demos/modules/gwin/list/gfxconf.h b/demos/modules/gwin/list/gfxconf.h index cf5f8690..19d395c0 100644 --- a/demos/modules/gwin/list/gfxconf.h +++ b/demos/modules/gwin/list/gfxconf.h @@ -1,150 +1,64 @@ -/** - * This file has a different license to the rest of the GFX system. - * You can copy, modify and distribute this file as you see fit. - * You do not need to publish your source modifications to this file. - * The only thing you are not permitted to do is to relicense it - * under a different license. - */ - -/** - * Copy this file into your project directory and rename it as gfxconf.h - * Edit your copy to turn on the GFX features you want to use. +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _GFXCONF_H #define _GFXCONF_H /* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS FALSE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_LINUX TRUE -//#define GFX_USE_OS_OSX FALSE +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE -/* GFX subsystems to turn on */ +/* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE -#define GFX_USE_TDISP FALSE #define GFX_USE_GWIN TRUE +#define GFX_USE_GINPUT TRUE #define GFX_USE_GEVENT TRUE #define GFX_USE_GTIMER TRUE -#define GFX_USE_GQUEUE TRUE -#define GFX_USE_GINPUT TRUE -#define GFX_USE_GADC FALSE -#define GFX_USE_GAUDIN FALSE -#define GFX_USE_GAUDOUT FALSE -#define GFX_USE_GMISC FALSE -/* Features for the GDISP subsystem */ +/* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE TRUE -#define GDISP_NEED_ARC FALSE #define GDISP_NEED_CONVEX_POLYGON TRUE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_QUERY FALSE -#define GDISP_NEED_IMAGE FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE -/* GDISP - builtin fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE - -/* GDISP image decoders */ -#define GDISP_NEED_IMAGE_NATIVE FALSE -#define GDISP_NEED_IMAGE_GIF FALSE -#define GDISP_NEED_IMAGE_BMP FALSE -#define GDISP_NEED_IMAGE_JPG FALSE -#define GDISP_NEED_IMAGE_PNG FALSE -#define GDISP_NEED_IMAGE_ACCOUNTING FALSE - -/* Optional image support that can be turned off */ -/* - #define GDISP_NEED_IMAGE_BMP_1 TRUE - #define GDISP_NEED_IMAGE_BMP_4 TRUE - #define GDISP_NEED_IMAGE_BMP_4_RLE TRUE - #define GDISP_NEED_IMAGE_BMP_8 TRUE - #define GDISP_NEED_IMAGE_BMP_8_RLE TRUE - #define GDISP_NEED_IMAGE_BMP_16 TRUE - #define GDISP_NEED_IMAGE_BMP_24 TRUE - #define GDISP_NEED_IMAGE_BMP_32 TRUE -*/ - -/* Features for the TDISP subsystem. */ -#define TDISP_NEED_MULTITHREAD FALSE +/* GDISP fonts to include */ +#define GDISP_INCLUDE_FONT_UI2 TRUE /* Features for the GWIN subsystem. */ #define GWIN_NEED_WINDOWMANAGER TRUE -#define GWIN_NEED_CONSOLE FALSE -#define GWIN_NEED_GRAPH FALSE #define GWIN_NEED_WIDGET TRUE -#define GWIN_NEED_BUTTON FALSE -#define GWIN_NEED_SLIDER FALSE -#define GWIN_NEED_CHECKBOX FALSE -#define GWIN_NEED_IMAGE FALSE -#define GWIN_NEED_RADIO FALSE #define GWIN_NEED_LIST TRUE -/* Features for the GEVENT subsystem. */ -#define GEVENT_ASSERT_NO_RESOURCE FALSE - -/* Features for the GTIMER subsystem. */ -/* NONE */ - -/* Features for the GQUEUE subsystem. */ -#define GQUEUE_NEED_ASYNC TRUE -#define GQUEUE_NEED_GSYNC FALSE -#define GQUEUE_NEED_FSYNC FALSE - /* Features for the GINPUT subsystem. */ #define GINPUT_NEED_MOUSE TRUE -#define GINPUT_NEED_KEYBOARD FALSE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE - -/* Features for the GADC subsystem. */ -/* NONE */ - -/* Features for the GAUDIN subsystem. */ -/* NONE */ - -/* Features for the GAUDOUT subsystem. */ -/* NONE */ - -/* Features for the GMISC subsystem. */ -#define GMISC_NEED_ARRAYOPS FALSE -#define GMISC_NEED_FASTTRIG FALSE -#define GMISC_NEED_FIXEDTRIG FALSE - -/* Optional Parameters for various subsystems */ -/* - #define GDISP_MAX_FONT_HEIGHT 16 - #define GEVENT_MAXIMUM_SIZE 32 - #define GEVENT_MAX_SOURCE_LISTENERS 32 - #define GTIMER_THREAD_WORKAREA_SIZE 512 - #define GADC_MAX_LOWSPEED_DEVICES 4 - #define GWIN_BUTTON_LAZY_RELEASE FALSE - #define GWIN_CONSOLE_USE_BASESTREAM FALSE - #define GWIN_CONSOLE_USE_FLOAT FALSE - #define GWIN_NEED_IMAGE_ANIMATION FALSE -*/ - -/* Optional Low Level Driver Definitions */ -/* - #define GDISP_USE_CUSTOM_BOARD FALSE - #define GDISP_SCREEN_WIDTH 320 - #define GDISP_SCREEN_HEIGHT 240 - #define GDISP_USE_FSMC - #define GDISP_USE_GPIO - #define TDISP_COLUMNS 16 - #define TDISP_ROWS 2 -*/ #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gwin/list/main.c b/demos/modules/gwin/list/main.c index 21afa544..e99c2448 100644 --- a/demos/modules/gwin/list/main.c +++ b/demos/modules/gwin/list/main.c @@ -1,3 +1,32 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "gfx.h" static GListener gl; @@ -32,7 +61,7 @@ int main(void) { // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("UI2")); gwinSetDefaultStyle(&WhiteWidgetStyle, FALSE); - gdispClear(Red); + gdispClear(White); // Attach the mouse input gwinAttachMouse(0); diff --git a/demos/modules/gwin/radio/gfxconf.h b/demos/modules/gwin/radio/gfxconf.h index 4bb82816..0e41b7ae 100644 --- a/demos/modules/gwin/radio/gfxconf.h +++ b/demos/modules/gwin/radio/gfxconf.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,62 +30,35 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 TRUE -//#define GFX_USE_OS_POSIX TRUE +/* The operating system to use - one of these must be defined */ +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE #define GFX_USE_GWIN TRUE +#define GFX_USE_GINPUT TRUE #define GFX_USE_GEVENT TRUE #define GFX_USE_GTIMER TRUE -#define GFX_USE_GINPUT TRUE /* Features for the GDISP sub-system. */ -#define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_CONVEX_POLYGON FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_IMAGE TRUE -#define GDISP_NEED_MULTITHREAD TRUE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_TEXT TRUE -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE +/* GDISP fonts to include */ +#define GDISP_INCLUDE_FONT_UI2 TRUE -/* GDISP image decoders */ -#define GDISP_NEED_IMAGE_NATIVE FALSE -#define GDISP_NEED_IMAGE_GIF FALSE -#define GDISP_NEED_IMAGE_BMP FALSE -#define GDISP_NEED_IMAGE_JPG FALSE -#define GDISP_NEED_IMAGE_PNG FALSE - -/* Features for the GWIN sub-system. */ +/* Features for the GWIN subsystem. */ #define GWIN_NEED_WINDOWMANAGER TRUE -#define GWIN_NEED_CONSOLE FALSE -#define GWIN_NEED_GRAPH FALSE #define GWIN_NEED_WIDGET TRUE -#define GWIN_NEED_BUTTON FALSE -#define GWIN_NEED_SLIDER FALSE -#define GWIN_NEED_CHECKBOX FALSE -#define GWIN_NEED_LABEL FALSE -#define GWIN_NEED_IMAGE FALSE #define GWIN_NEED_RADIO TRUE -/* Features for the GINPUT sub-system. */ +/* Features for the GINPUT subsystem. */ #define GINPUT_NEED_MOUSE TRUE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gwin/radio/main.c b/demos/modules/gwin/radio/main.c index c64b2068..b7504535 100644 --- a/demos/modules/gwin/radio/main.c +++ b/demos/modules/gwin/radio/main.c @@ -1,3 +1,32 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "gfx.h" #define GROUP1 0 // this will be the first radio button group diff --git a/demos/modules/gwin/slider/gfxconf.h b/demos/modules/gwin/slider/gfxconf.h index af5eeaa8..5442c508 100644 --- a/demos/modules/gwin/slider/gfxconf.h +++ b/demos/modules/gwin/slider/gfxconf.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,62 +30,35 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 TRUE -//#define GFX_USE_OS_POSIX TRUE +/* The operating system to use - one of these must be defined */ +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE #define GFX_USE_GWIN TRUE +#define GFX_USE_GINPUT TRUE #define GFX_USE_GEVENT TRUE #define GFX_USE_GTIMER TRUE -#define GFX_USE_GINPUT TRUE /* Features for the GDISP sub-system. */ -#define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_CONVEX_POLYGON FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_IMAGE TRUE -#define GDISP_NEED_MULTITHREAD TRUE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_TEXT TRUE -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE +/* GDISP fonts to include */ +#define GDISP_INCLUDE_FONT_UI2 TRUE -/* GDISP image decoders */ -#define GDISP_NEED_IMAGE_NATIVE FALSE -#define GDISP_NEED_IMAGE_GIF FALSE -#define GDISP_NEED_IMAGE_BMP FALSE -#define GDISP_NEED_IMAGE_JPG FALSE -#define GDISP_NEED_IMAGE_PNG FALSE - -/* Features for the GWIN sub-system. */ +/* Features for the GWIN subsystem. */ #define GWIN_NEED_WINDOWMANAGER TRUE -#define GWIN_NEED_CONSOLE FALSE -#define GWIN_NEED_GRAPH FALSE #define GWIN_NEED_WIDGET TRUE -#define GWIN_NEED_BUTTON FALSE #define GWIN_NEED_SLIDER TRUE -#define GWIN_NEED_CHECKBOX FALSE -#define GWIN_NEED_LABEL FALSE -#define GWIN_NEED_IMAGE FALSE -#define GWIN_NEED_RADIO FALSE -/* Features for the GINPUT sub-system. */ +/* Features for the GINPUT subsystem. */ #define GINPUT_NEED_MOUSE TRUE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gwin/slider/main.c b/demos/modules/gwin/slider/main.c index 4532ba01..ed936f12 100644 --- a/demos/modules/gwin/slider/main.c +++ b/demos/modules/gwin/slider/main.c @@ -1,3 +1,32 @@ +/* + * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu + * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #include "gfx.h" static GListener gl; diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index 0bf8443a..ed6be366 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2012, 2013, Joel Bodenmann aka Tectu * Copyright (c) 2012, 2013, Andrew Hannam aka inmarket + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,62 +30,52 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -//#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 TRUE -//#define GFX_USE_OS_POSIX TRUE +/* The operating system to use - one of these must be defined */ +#define GFX_USE_OS_CHIBIOS FALSE +#define GFX_USE_OS_WIN32 FALSE +#define GFX_USE_OS_LINUX FALSE +#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE #define GFX_USE_GWIN TRUE +#define GFX_USE_GINPUT TRUE #define GFX_USE_GEVENT TRUE #define GFX_USE_GTIMER TRUE -#define GFX_USE_GINPUT TRUE /* Features for the GDISP sub-system. */ -#define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_CONVEX_POLYGON TRUE -#define GDISP_NEED_SCROLL TRUE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_IMAGE TRUE -#define GDISP_NEED_MULTITHREAD TRUE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_TEXT TRUE +#define GDISP_NEED_SCROLL TRUE +#define GDISP_NEED_IMAGE TRUE -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_NEED_ANTIALIAS FALSE +/* GDISP fonts to include */ +#define GDISP_INCLUDE_FONT_UI2 TRUE /* GDISP image decoders */ -#define GDISP_NEED_IMAGE_NATIVE FALSE #define GDISP_NEED_IMAGE_GIF TRUE -#define GDISP_NEED_IMAGE_BMP FALSE -#define GDISP_NEED_IMAGE_JPG FALSE -#define GDISP_NEED_IMAGE_PNG FALSE +#define GDISP_NEED_IMAGE_BMP TRUE -/* Features for the GWIN sub-system. */ +/* Features for the GWIN subsystem. */ #define GWIN_NEED_WINDOWMANAGER TRUE #define GWIN_NEED_CONSOLE TRUE #define GWIN_NEED_GRAPH TRUE #define GWIN_NEED_WIDGET TRUE +#define GWIN_NEED_LABEL TRUE #define GWIN_NEED_BUTTON TRUE #define GWIN_NEED_SLIDER TRUE #define GWIN_NEED_CHECKBOX TRUE -#define GWIN_NEED_LABEL TRUE #define GWIN_NEED_IMAGE TRUE #define GWIN_NEED_RADIO TRUE #define GWIN_NEED_LIST TRUE -#define GWIN_NEED_IMAGE_ANIMATION TRUE -#define GWIN_NEED_LIST_IMAGES TRUE -/* Features for the GINPUT sub-system. */ +/* Features for the GINPUT subsystem. */ #define GINPUT_NEED_MOUSE TRUE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE + +/* Optional parameters for various subsystems */ +#define GWIN_NEED_LIST_IMAGES TRUE #endif /* _GFXCONF_H */ + diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c index dde955f3..2b14d79e 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -382,3 +382,4 @@ int main(void) { } return 0; } + From 2cb8e08c525e140a20982cb14e59ebd7782f2792 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 28 Oct 2013 01:00:02 +0100 Subject: [PATCH 129/160] uncommented GOS selection in GDISP and GWIN demos --- demos/modules/gdisp/basics/gfxconf.h | 10 +++++----- demos/modules/gdisp/circles/gfxconf.h | 10 +++++----- demos/modules/gdisp/fonts/gfxconf.h | 10 +++++----- demos/modules/gdisp/fonts_cyrillic/gfxconf.h | 10 +++++----- demos/modules/gdisp/images/gfxconf.h | 10 +++++----- demos/modules/gdisp/images_animated/gfxconf.h | 10 +++++----- demos/modules/gwin/basic/gfxconf.h | 10 +++++----- demos/modules/gwin/button/gfxconf.h | 10 +++++----- demos/modules/gwin/checkbox/gfxconf.h | 10 +++++----- demos/modules/gwin/console/gfxconf.h | 10 +++++----- demos/modules/gwin/graph/gfxconf.h | 10 +++++----- demos/modules/gwin/list/gfxconf.h | 10 +++++----- demos/modules/gwin/radio/gfxconf.h | 10 +++++----- demos/modules/gwin/slider/gfxconf.h | 10 +++++----- demos/modules/gwin/widgets/gfxconf.h | 10 +++++----- gfxconf.example.h | 2 +- 16 files changed, 76 insertions(+), 76 deletions(-) diff --git a/demos/modules/gdisp/basics/gfxconf.h b/demos/modules/gdisp/basics/gfxconf.h index ff365590..60b8888e 100644 --- a/demos/modules/gdisp/basics/gfxconf.h +++ b/demos/modules/gdisp/basics/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/circles/gfxconf.h b/demos/modules/gdisp/circles/gfxconf.h index cb698fce..28311ccb 100644 --- a/demos/modules/gdisp/circles/gfxconf.h +++ b/demos/modules/gdisp/circles/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/fonts/gfxconf.h b/demos/modules/gdisp/fonts/gfxconf.h index ffb3a7e7..9f569e37 100644 --- a/demos/modules/gdisp/fonts/gfxconf.h +++ b/demos/modules/gdisp/fonts/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/fonts_cyrillic/gfxconf.h b/demos/modules/gdisp/fonts_cyrillic/gfxconf.h index 713c89b4..1bf1baeb 100644 --- a/demos/modules/gdisp/fonts_cyrillic/gfxconf.h +++ b/demos/modules/gdisp/fonts_cyrillic/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX subsystems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/images/gfxconf.h b/demos/modules/gdisp/images/gfxconf.h index 694bad28..0bf9f1fc 100644 --- a/demos/modules/gdisp/images/gfxconf.h +++ b/demos/modules/gdisp/images/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/images_animated/gfxconf.h b/demos/modules/gdisp/images_animated/gfxconf.h index e0158441..8cf34e87 100644 --- a/demos/modules/gdisp/images_animated/gfxconf.h +++ b/demos/modules/gdisp/images_animated/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/basic/gfxconf.h b/demos/modules/gwin/basic/gfxconf.h index 1e6784fd..411ad9cf 100644 --- a/demos/modules/gwin/basic/gfxconf.h +++ b/demos/modules/gwin/basic/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/button/gfxconf.h b/demos/modules/gwin/button/gfxconf.h index 6d0aa41d..2199e891 100644 --- a/demos/modules/gwin/button/gfxconf.h +++ b/demos/modules/gwin/button/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/checkbox/gfxconf.h b/demos/modules/gwin/checkbox/gfxconf.h index 9bcda6be..9be70462 100644 --- a/demos/modules/gwin/checkbox/gfxconf.h +++ b/demos/modules/gwin/checkbox/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/console/gfxconf.h b/demos/modules/gwin/console/gfxconf.h index c1307302..42ad5e12 100644 --- a/demos/modules/gwin/console/gfxconf.h +++ b/demos/modules/gwin/console/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/graph/gfxconf.h b/demos/modules/gwin/graph/gfxconf.h index e829605a..684d0e7a 100644 --- a/demos/modules/gwin/graph/gfxconf.h +++ b/demos/modules/gwin/graph/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/list/gfxconf.h b/demos/modules/gwin/list/gfxconf.h index 19d395c0..ab9cc008 100644 --- a/demos/modules/gwin/list/gfxconf.h +++ b/demos/modules/gwin/list/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/radio/gfxconf.h b/demos/modules/gwin/radio/gfxconf.h index 0e41b7ae..595042fb 100644 --- a/demos/modules/gwin/radio/gfxconf.h +++ b/demos/modules/gwin/radio/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/slider/gfxconf.h b/demos/modules/gwin/slider/gfxconf.h index 5442c508..8a1be49d 100644 --- a/demos/modules/gwin/slider/gfxconf.h +++ b/demos/modules/gwin/slider/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index ed6be366..43094bf5 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS FALSE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_LINUX FALSE -#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - perferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/gfxconf.example.h b/gfxconf.example.h index 1b9faca2..83e663ec 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -14,7 +14,7 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined - preferably via your makefile */ +/* The operating system to use. One of these must be defined - perferably in your Makefile */ //#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE From 17cc2da9c53191be2831f71a721b0fe2273e9807 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Mon, 28 Oct 2013 01:13:00 +0100 Subject: [PATCH 130/160] Merge changes from release v1.9 in preperation for v2.0 --- Doxygenfile | 2 +- releases.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doxygenfile b/Doxygenfile index 380b9fbd..8b583591 100644 --- a/Doxygenfile +++ b/Doxygenfile @@ -34,7 +34,7 @@ PROJECT_NAME = uGFX # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 1.8 +PROJECT_NUMBER = 2.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/releases.txt b/releases.txt index ad00e8d1..32a838e9 100644 --- a/releases.txt +++ b/releases.txt @@ -10,7 +10,7 @@ FEATURE: New driver interface for GDISP FEATURE: Multiple display support FEATURE: Multiple controller support FEATURE: Add gdispFlush() for those controllers that need it -FEATURE: Add GDISP_NEED_AUTOFLUSH to automatically flush when required. +FEATURE: Add GDISP_NEED_AUTOFLUSH and GDISP_NEED_TIMERFLUSH to automatically flush when required. *** changes after 1.8 *** FEATURE: GWIN list boxes. From 602cba0e62d9ed38a80a47fe5a698ce21d01517a Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 28 Oct 2013 10:44:05 +1000 Subject: [PATCH 131/160] Remove 3rd party boing demo as it is replaced by the new hardware independant GDISP streaming demo. --- demos/3rdparty/boing/gfxconf.h | 41 ------------- demos/3rdparty/boing/main.c | 109 --------------------------------- 2 files changed, 150 deletions(-) delete mode 100644 demos/3rdparty/boing/gfxconf.h delete mode 100644 demos/3rdparty/boing/main.c diff --git a/demos/3rdparty/boing/gfxconf.h b/demos/3rdparty/boing/gfxconf.h deleted file mode 100644 index 0afcd45b..00000000 --- a/demos/3rdparty/boing/gfxconf.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * This file has a different license to the rest of the GFX system. - * You can copy, modify and distribute this file as you see fit. - * You do not need to publish your source modifications to this file. - * The only thing you are not permitted to do is to relicense it - * under a different license. - */ - -#ifndef _GFXCONF_H -#define _GFXCONF_H - -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE - -/* GFX sub-systems to turn on */ -#define GFX_USE_GDISP TRUE - -/* Features for the GDISP sub-system. */ -#define GDISP_NEED_VALIDATION FALSE -#define GDISP_NEED_CLIP FALSE -#define GDISP_NEED_TEXT FALSE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE - -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 FALSE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE - -#endif /* _GFXCONF_H */ diff --git a/demos/3rdparty/boing/main.c b/demos/3rdparty/boing/main.c deleted file mode 100644 index 96ba5c9d..00000000 --- a/demos/3rdparty/boing/main.c +++ /dev/null @@ -1,109 +0,0 @@ -/* Derived from the 2011 IOCCC submission by peter.eastman@gmail.com - * http://www.ioccc.org/2011/eastman/eastman.c - * -- - * Public Domain -- but you're looking at this for ideas of techniques - * and methods, not trying to cut&paste an entire application, anyway. - * -- - * When you need to blit an entire screenfull of data to an LCD - * display, the basic idea is to exploit the auto-increment feature of - * the display controller when it writes to screen memory. You start - * by resetting the 'cursor' to the 0,0 position, and then stream - * width*height pixels out. - * -- - * Chris Baird,, April 2013 - * - * Modified Andrew Hannam (inmarket) 2013-04-29 New GFX support - */ - -#include -#include "gfx.h" -#include "ssd2119.h" - -#define Lightgrey (HTML2COLOR(0xC0C0C0)) -#define Midgrey (HTML2COLOR(0x606060)) -#define Darkgrey (HTML2COLOR(0x303030)) - - -/* ---------------------------------------------------------------------- */ -/* As of early April 2013, the /gfx extension tries to keep the low-level - * stuff away from our filthy paws. So Code Duplication. - * (Possibly to be replaced with gdispStartStream(), gdispWriteStream() - * and gdispStopStream() in the future.) - */ - -#define GDISP_REG (*((volatile uint16_t *) 0x60000000)) /* DC = 0 */ -#define GDISP_RAM (*((volatile uint16_t *) 0x60100000)) /* DC = 1 */ - -inline void write_index (uint16_t index) { GDISP_REG = index; } -inline void write_data (uint16_t data) { GDISP_RAM = data; } - -#define write_reg(reg, data) { write_index(reg); write_data(data); } - -void reset_cursor (void) -{ - write_reg (SSD2119_REG_X_RAM_ADDR, 0); - write_reg (SSD2119_REG_Y_RAM_ADDR, 0); -} - -#define StartStream() { write_index (SSD2119_REG_RAM_DATA); } -#define WriteStream(x) { write_data (x); } -#define StopStream() /* NOP */ - - -/* ---------------------------------------------------------------------- */ - -void main (void) -{ - uint16_t xx, yy, colour; - - gfxInit(); - - uint16_t width = (uint16_t)gdispGetWidth(); - uint16_t height = (uint16_t)gdispGetHeight(); - - float i=height/5+height%2+1, floorstart=height/5-1, spherespin=0.0, - l=width/2, m=height/4, n=.01*width, o=0.0, rotspeed=0.1, h, f, g; - - while (TRUE) - { - reset_cursor (); - StartStream (); - - for (xx=yy=0; - h = (m-yy)/i, f=-.3*(g=(l-xx)/i)+.954*h, yywidth-floorstart) - colour = Darkgrey; /* side wall */ - else - colour = Lightgrey; /* back wall */ - - if (yy > height-floorstart) - if (xx < height-yy || height-yy > width-xx) /* floor */ - colour = Darkgrey; - else - colour = Midgrey; - - if (g*(g+.6)+.09+h*h < 1) - colour >>= 1; /* ball shadow; make it darker */ - } - - WriteStream (colour); /* pixel to the LCD */ - } - - StopStream(); - spherespin += rotspeed; - m += o; - o = m > height-1.75*floorstart ? -.04*height : o+.002*height; - n = (l+=n)width-i ? rotspeed=-rotspeed,-n : n; - } -} - -/* ---------------------------------------------------------------------- */ From db09e33dff7110861ce2fa586b04c05626e3f7e8 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 28 Oct 2013 10:46:25 +1000 Subject: [PATCH 132/160] Fix spelling error and migrate demo gfxconf.h changes to all demos including the new streaming and multiple display demos --- demos/3rdparty/bubbles/gfxconf.h | 9 +- demos/3rdparty/notepad-2/gfxconf.h | 9 +- demos/3rdparty/tdisp_f4_discovery/gfxconf.h | 6 ++ demos/applications/mandelbrot/gfxconf.h | 20 ++--- demos/applications/notepad/gfxconf.h | 14 +--- demos/benchmarks/gfxconf.h | 21 ++--- demos/modules/gadc/gfxconf.h | 77 ++--------------- demos/modules/gaudin/gfxconf.h | 84 ++----------------- demos/modules/gdisp/basics/gfxconf.h | 6 +- demos/modules/gdisp/circles/gfxconf.h | 6 +- demos/modules/gdisp/fonts/gfxconf.h | 22 ++--- demos/modules/gdisp/fonts_cyrillic/gfxconf.h | 10 +-- demos/modules/gdisp/images/gfxconf.h | 6 +- demos/modules/gdisp/images_animated/gfxconf.h | 6 +- .../gfxconf.h | 16 +--- .../main.c | 0 .../{gdisp_streaming => streaming}/gfxconf.h | 22 +---- .../{gdisp_streaming => streaming}/main.c | 0 .../ginput/touch_driver_test/gfxconf.h | 21 ++--- demos/modules/gtimer/gfxconf.h | 9 +- demos/modules/gwin/basic/gfxconf.h | 6 +- demos/modules/gwin/button/gfxconf.h | 6 +- demos/modules/gwin/checkbox/gfxconf.h | 6 +- demos/modules/gwin/console/gfxconf.h | 6 +- demos/modules/gwin/graph/gfxconf.h | 6 +- demos/modules/gwin/list/gfxconf.h | 6 +- demos/modules/gwin/radio/gfxconf.h | 6 +- demos/modules/gwin/slider/gfxconf.h | 6 +- demos/modules/gwin/widgets/gfxconf.h | 6 +- demos/modules/tdisp/gfxconf.h | 9 +- gfxconf.example.h | 2 +- 31 files changed, 115 insertions(+), 314 deletions(-) rename demos/modules/gdisp/{gdisp_multiple_displays => multiple_displays}/gfxconf.h (88%) rename demos/modules/gdisp/{gdisp_multiple_displays => multiple_displays}/main.c (100%) rename demos/modules/gdisp/{gdisp_streaming => streaming}/gfxconf.h (55%) rename demos/modules/gdisp/{gdisp_streaming => streaming}/main.c (100%) diff --git a/demos/3rdparty/bubbles/gfxconf.h b/demos/3rdparty/bubbles/gfxconf.h index 344a986e..1ecfc544 100644 --- a/demos/3rdparty/bubbles/gfxconf.h +++ b/demos/3rdparty/bubbles/gfxconf.h @@ -9,10 +9,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/3rdparty/notepad-2/gfxconf.h b/demos/3rdparty/notepad-2/gfxconf.h index 7f436596..869b2ab2 100644 --- a/demos/3rdparty/notepad-2/gfxconf.h +++ b/demos/3rdparty/notepad-2/gfxconf.h @@ -9,10 +9,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* GFX operating system to use */ -#define GFX_USE_OS_CHIBIOS TRUE -//#define GFX_USE_OS_WIN32 TRUE -//#define GFX_USE_OS_POSIX TRUE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/3rdparty/tdisp_f4_discovery/gfxconf.h b/demos/3rdparty/tdisp_f4_discovery/gfxconf.h index 6d69b3c8..42399ef5 100644 --- a/demos/3rdparty/tdisp_f4_discovery/gfxconf.h +++ b/demos/3rdparty/tdisp_f4_discovery/gfxconf.h @@ -14,6 +14,12 @@ #ifndef _GFXCONF_H #define _GFXCONF_H +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE + /* GFX subsystems to turn on */ #define GFX_USE_GDISP FALSE #define GFX_USE_TDISP TRUE diff --git a/demos/applications/mandelbrot/gfxconf.h b/demos/applications/mandelbrot/gfxconf.h index c2c56714..99a04b5c 100644 --- a/demos/applications/mandelbrot/gfxconf.h +++ b/demos/applications/mandelbrot/gfxconf.h @@ -30,26 +30,16 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE /* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP FALSE -#define GDISP_NEED_TEXT FALSE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE #endif /* _GFXCONF_H */ diff --git a/demos/applications/notepad/gfxconf.h b/demos/applications/notepad/gfxconf.h index 95d5dc5e..7ffb22fa 100644 --- a/demos/applications/notepad/gfxconf.h +++ b/demos/applications/notepad/gfxconf.h @@ -30,14 +30,14 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS TRUE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE -#define GFX_USE_GWIN FALSE #define GFX_USE_GEVENT TRUE #define GFX_USE_GTIMER TRUE #define GFX_USE_GINPUT TRUE @@ -47,14 +47,8 @@ #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE #define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE #define GDISP_NEED_CONTROL TRUE #define GDISP_NEED_MULTITHREAD TRUE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE /* Builtin Fonts */ #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA TRUE diff --git a/demos/benchmarks/gfxconf.h b/demos/benchmarks/gfxconf.h index 36a6c5b9..aaacd3a2 100644 --- a/demos/benchmarks/gfxconf.h +++ b/demos/benchmarks/gfxconf.h @@ -30,10 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -42,22 +43,10 @@ #define GDISP_NEED_VALIDATION FALSE #define GDISP_NEED_CLIP FALSE #define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE #define GDISP_NEED_CONTROL TRUE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE /* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE #define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE #endif /* _GFXCONF_H */ diff --git a/demos/modules/gadc/gfxconf.h b/demos/modules/gadc/gfxconf.h index ff306763..297265b5 100644 --- a/demos/modules/gadc/gfxconf.h +++ b/demos/modules/gadc/gfxconf.h @@ -35,96 +35,29 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE -#define GFX_USE_TDISP FALSE #define GFX_USE_GWIN TRUE -#define GFX_USE_GEVENT FALSE #define GFX_USE_GTIMER TRUE -#define GFX_USE_GINPUT FALSE #define GFX_USE_GADC TRUE -#define GFX_USE_GAUDIN FALSE -#define GFX_USE_GAUDOUT FALSE -#define GFX_USE_GMISC FALSE /* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE #define GDISP_NEED_CONTROL TRUE #define GDISP_NEED_MULTITHREAD TRUE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE /* GDISP - builtin fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE #define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE - -/* Features for the TDISP subsystem. */ -#define TDISP_NEED_MULTITHREAD FALSE /* Features for the GWIN sub-system. */ -#define GWIN_NEED_BUTTON FALSE #define GWIN_NEED_CONSOLE TRUE -#define GWIN_NEED_GRAPH FALSE - -/* Features for the GEVENT sub-system. */ -#define GEVENT_ASSERT_NO_RESOURCE FALSE - -/* Features for the GTIMER sub-system. */ -/* NONE */ - -/* Features for the GINPUT sub-system. */ -#define GINPUT_NEED_MOUSE FALSE -#define GINPUT_NEED_KEYBOARD FALSE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE - -/* Features for the GADC sub-system. */ -/* NONE */ - -/* Features for the GAUDIN sub-system. */ -/* NONE */ - -/* Features for the GAUDOUT sub-system. */ -/* NONE */ - -/* Features for the GMISC sub-system. */ -#define GMISC_NEED_ARRAYOPS FALSE - -/* Optional Parameters for various sub-systems */ -/* - #define GDISP_MAX_FONT_HEIGHT 16 - #define GEVENT_MAXIMUM_SIZE 32 - #define GEVENT_MAX_SOURCE_LISTENERS 32 - #define GTIMER_THREAD_WORKAREA_SIZE 512 - #define GADC_MAX_LOWSPEED_DEVICES 4 -*/ - -/* Optional Low Level Driver Definitions */ -/* - #define GDISP_USE_CUSTOM_BOARD FALSE - #define GDISP_SCREEN_WIDTH 320 - #define GDISP_SCREEN_HEIGHT 240 - #define GDISP_USE_FSMC - #define GDISP_USE_GPIO - #define GDISP_VMT_NAME1(x) x##YourDriver1 - #define GDISP_VMT_NAME2(x) x##YourDriver2 - #define TDISP_COLUMNS 16 - #define TDISP_ROWS 2 -*/ #endif /* _GFXCONF_H */ diff --git a/demos/modules/gaudin/gfxconf.h b/demos/modules/gaudin/gfxconf.h index a17e4fd9..9525a020 100644 --- a/demos/modules/gaudin/gfxconf.h +++ b/demos/modules/gaudin/gfxconf.h @@ -35,96 +35,22 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE -#define GFX_USE_TDISP FALSE #define GFX_USE_GWIN TRUE -#define GFX_USE_GEVENT FALSE #define GFX_USE_GTIMER TRUE -#define GFX_USE_GINPUT FALSE #define GFX_USE_GADC TRUE #define GFX_USE_GAUDIN TRUE -#define GFX_USE_GAUDOUT FALSE -#define GFX_USE_GMISC FALSE /* Features for the GDISP sub-system. */ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT FALSE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE #define GDISP_NEED_MULTITHREAD TRUE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE - -/* GDISP - builtin fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 FALSE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE - -/* Features for the TDISP subsystem. */ -#define TDISP_NEED_MULTITHREAD FALSE - -/* Features for the GWIN sub-system. */ -#define GWIN_NEED_BUTTON FALSE -#define GWIN_NEED_CONSOLE FALSE -#define GWIN_NEED_GRAPH FALSE - -/* Features for the GEVENT sub-system. */ -#define GEVENT_ASSERT_NO_RESOURCE FALSE - -/* Features for the GTIMER sub-system. */ -/* NONE */ - -/* Features for the GINPUT sub-system. */ -#define GINPUT_NEED_MOUSE FALSE -#define GINPUT_NEED_KEYBOARD FALSE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE - -/* Features for the GADC sub-system. */ -/* NONE */ - -/* Features for the GAUDIN sub-system. */ -/* NONE */ - -/* Features for the GAUDOUT sub-system. */ -/* NONE */ - -/* Features for the GMISC sub-system. */ -#define GMISC_NEED_ARRAYOPS FALSE - -/* Optional Parameters for various sub-systems */ -/* - #define GDISP_MAX_FONT_HEIGHT 16 - #define GEVENT_MAXIMUM_SIZE 32 - #define GEVENT_MAX_SOURCE_LISTENERS 32 - #define GTIMER_THREAD_WORKAREA_SIZE 512 - #define GADC_MAX_LOWSPEED_DEVICES 4 -*/ - -/* Optional Low Level Driver Definitions */ -/* - #define GDISP_USE_CUSTOM_BOARD FALSE - #define GDISP_SCREEN_WIDTH 320 - #define GDISP_SCREEN_HEIGHT 240 - #define GDISP_USE_FSMC - #define GDISP_USE_GPIO - #define GDISP_VMT_NAME1(x) x##YourDriver1 - #define GDISP_VMT_NAME2(x) x##YourDriver2 - #define TDISP_COLUMNS 16 - #define TDISP_ROWS 2 -*/ #endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/basics/gfxconf.h b/demos/modules/gdisp/basics/gfxconf.h index 60b8888e..a37ef1e7 100644 --- a/demos/modules/gdisp/basics/gfxconf.h +++ b/demos/modules/gdisp/basics/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/circles/gfxconf.h b/demos/modules/gdisp/circles/gfxconf.h index 28311ccb..4bb605ac 100644 --- a/demos/modules/gdisp/circles/gfxconf.h +++ b/demos/modules/gdisp/circles/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/fonts/gfxconf.h b/demos/modules/gdisp/fonts/gfxconf.h index 9f569e37..64481774 100644 --- a/demos/modules/gdisp/fonts/gfxconf.h +++ b/demos/modules/gdisp/fonts/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -43,18 +43,13 @@ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE #define GDISP_NEED_ANTIALIAS TRUE /* GDISP - fonts to include */ +#define GDISP_INCLUDE_USER_FONTS TRUE +#define GDISP_INCLUDE_FONT_UI1 FALSE +#define GDISP_INCLUDE_FONT_UI2 TRUE +#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE #define GDISP_INCLUDE_FONT_DEJAVUSANS10 TRUE #define GDISP_INCLUDE_FONT_DEJAVUSANS12 FALSE #define GDISP_INCLUDE_FONT_DEJAVUSANS16 FALSE @@ -70,9 +65,6 @@ #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA FALSE #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE #endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/fonts_cyrillic/gfxconf.h b/demos/modules/gdisp/fonts_cyrillic/gfxconf.h index 1bf1baeb..dab77ba1 100644 --- a/demos/modules/gdisp/fonts_cyrillic/gfxconf.h +++ b/demos/modules/gdisp/fonts_cyrillic/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE -//#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX subsystems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/images/gfxconf.h b/demos/modules/gdisp/images/gfxconf.h index 0bf9f1fc..6cd78b37 100644 --- a/demos/modules/gdisp/images/gfxconf.h +++ b/demos/modules/gdisp/images/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/images_animated/gfxconf.h b/demos/modules/gdisp/images_animated/gfxconf.h index 8cf34e87..cc38ed36 100644 --- a/demos/modules/gdisp/images_animated/gfxconf.h +++ b/demos/modules/gdisp/images_animated/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h b/demos/modules/gdisp/multiple_displays/gfxconf.h similarity index 88% rename from demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h rename to demos/modules/gdisp/multiple_displays/gfxconf.h index 71c16864..60467f93 100644 --- a/demos/modules/gdisp/gdisp_multiple_displays/gfxconf.h +++ b/demos/modules/gdisp/multiple_displays/gfxconf.h @@ -30,10 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS TRUE +//* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -42,15 +43,6 @@ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE #define GDISP_INCLUDE_FONT_UI2 TRUE diff --git a/demos/modules/gdisp/gdisp_multiple_displays/main.c b/demos/modules/gdisp/multiple_displays/main.c similarity index 100% rename from demos/modules/gdisp/gdisp_multiple_displays/main.c rename to demos/modules/gdisp/multiple_displays/main.c diff --git a/demos/modules/gdisp/gdisp_streaming/gfxconf.h b/demos/modules/gdisp/streaming/gfxconf.h similarity index 55% rename from demos/modules/gdisp/gdisp_streaming/gfxconf.h rename to demos/modules/gdisp/streaming/gfxconf.h index b38be854..4038a3fd 100644 --- a/demos/modules/gdisp/gdisp_streaming/gfxconf.h +++ b/demos/modules/gdisp/streaming/gfxconf.h @@ -9,35 +9,21 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -//#define GFX_USE_OS_CHIBIOS TRUE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE -//#define GFX_USE_OS_POSIX FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE #define GFX_USE_GMISC TRUE /* Features for the GDISP sub-system. */ -#define GDISP_NEED_AUTOFLUSH FALSE #define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP FALSE -#define GDISP_NEED_TEXT FALSE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE #define GDISP_NEED_STREAMING TRUE -/* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_UI2 FALSE - #define GFX_USE_GMISC TRUE -#define GMISC_NEED_FIXEDTRIG FALSE -#define GMISC_NEED_FASTTRIG FALSE #define GMISC_NEED_INVSQRT TRUE //#define GDISP_INVSQRT_MIXED_ENDIAN TRUE //#define GDISP_INVSQRT_REAL_SLOW TRUE diff --git a/demos/modules/gdisp/gdisp_streaming/main.c b/demos/modules/gdisp/streaming/main.c similarity index 100% rename from demos/modules/gdisp/gdisp_streaming/main.c rename to demos/modules/gdisp/streaming/main.c diff --git a/demos/modules/ginput/touch_driver_test/gfxconf.h b/demos/modules/ginput/touch_driver_test/gfxconf.h index 6e8cc8e1..9b2de86c 100644 --- a/demos/modules/ginput/touch_driver_test/gfxconf.h +++ b/demos/modules/ginput/touch_driver_test/gfxconf.h @@ -30,10 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE @@ -46,22 +47,10 @@ #define GDISP_NEED_VALIDATION TRUE #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE FALSE -#define GDISP_NEED_ELLIPSE FALSE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE #define GDISP_NEED_MULTITHREAD TRUE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE /* Builtin Fonts */ -#define GDISP_INCLUDE_FONT_SMALL FALSE -#define GDISP_INCLUDE_FONT_LARGER FALSE -#define GDISP_INCLUDE_FONT_UI1 FALSE #define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE /* Features for the GWIN sub-system. */ #define GWIN_NEED_BUTTON TRUE diff --git a/demos/modules/gtimer/gfxconf.h b/demos/modules/gtimer/gfxconf.h index 1c4a31f8..8786fafe 100644 --- a/demos/modules/gtimer/gfxconf.h +++ b/demos/modules/gtimer/gfxconf.h @@ -30,10 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GTIMER TRUE diff --git a/demos/modules/gwin/basic/gfxconf.h b/demos/modules/gwin/basic/gfxconf.h index 411ad9cf..70149055 100644 --- a/demos/modules/gwin/basic/gfxconf.h +++ b/demos/modules/gwin/basic/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/button/gfxconf.h b/demos/modules/gwin/button/gfxconf.h index 2199e891..5376bd52 100644 --- a/demos/modules/gwin/button/gfxconf.h +++ b/demos/modules/gwin/button/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/checkbox/gfxconf.h b/demos/modules/gwin/checkbox/gfxconf.h index 9be70462..f9060599 100644 --- a/demos/modules/gwin/checkbox/gfxconf.h +++ b/demos/modules/gwin/checkbox/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/console/gfxconf.h b/demos/modules/gwin/console/gfxconf.h index 42ad5e12..3ada3b89 100644 --- a/demos/modules/gwin/console/gfxconf.h +++ b/demos/modules/gwin/console/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/graph/gfxconf.h b/demos/modules/gwin/graph/gfxconf.h index 684d0e7a..c09bfc6e 100644 --- a/demos/modules/gwin/graph/gfxconf.h +++ b/demos/modules/gwin/graph/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/list/gfxconf.h b/demos/modules/gwin/list/gfxconf.h index ab9cc008..40b509ff 100644 --- a/demos/modules/gwin/list/gfxconf.h +++ b/demos/modules/gwin/list/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/radio/gfxconf.h b/demos/modules/gwin/radio/gfxconf.h index 595042fb..7c3e441e 100644 --- a/demos/modules/gwin/radio/gfxconf.h +++ b/demos/modules/gwin/radio/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/slider/gfxconf.h b/demos/modules/gwin/slider/gfxconf.h index 8a1be49d..fc8d356e 100644 --- a/demos/modules/gwin/slider/gfxconf.h +++ b/demos/modules/gwin/slider/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index 43094bf5..602a559c 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -30,11 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ -//#define GFX_USE_OS_CHIBIOS FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE -//#define GFX_USE_OS_OSX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_GDISP TRUE diff --git a/demos/modules/tdisp/gfxconf.h b/demos/modules/tdisp/gfxconf.h index 1f323be3..371a9f44 100644 --- a/demos/modules/tdisp/gfxconf.h +++ b/demos/modules/tdisp/gfxconf.h @@ -30,10 +30,11 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use - one of these must be defined */ -#define GFX_USE_OS_CHIBIOS TRUE -#define GFX_USE_OS_WIN32 FALSE -#define GFX_USE_OS_POSIX FALSE +/* The operating system to use. One of these must be defined - preferably in your Makefile */ +//#define GFX_USE_OS_CHIBIOS FALSE +//#define GFX_USE_OS_WIN32 FALSE +//#define GFX_USE_OS_LINUX FALSE +//#define GFX_USE_OS_OSX FALSE /* GFX sub-systems to turn on */ #define GFX_USE_TDISP TRUE diff --git a/gfxconf.example.h b/gfxconf.example.h index 83e663ec..74d7f768 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -14,7 +14,7 @@ #ifndef _GFXCONF_H #define _GFXCONF_H -/* The operating system to use. One of these must be defined - perferably in your Makefile */ +/* The operating system to use. One of these must be defined - preferably in your Makefile */ //#define GFX_USE_OS_CHIBIOS FALSE //#define GFX_USE_OS_WIN32 FALSE //#define GFX_USE_OS_LINUX FALSE From 26f4bec2be1ebfc8edf66d33cb8edb04d3b1049a Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 28 Oct 2013 10:47:17 +1000 Subject: [PATCH 133/160] No doxygen comments in any C file now. They are all in the h files --- src/gwin/slider.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gwin/slider.c b/src/gwin/slider.c index 0956ca8a..a4ac5d95 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -322,7 +322,7 @@ void gwinSliderDraw_Std(GWidgetObject *gw, void *param) { #undef gsw } -#if GDISP_NEED_IMAGE || defined(__DOXYGEN__) +#if GDISP_NEED_IMAGE void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { #define gsw ((GSliderObject *)gw) #define gi ((gdispImage *)param) From 9e5ed28f98e7b0b3dbd46df7a62568dbaffab92a Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 28 Oct 2013 10:48:09 +1000 Subject: [PATCH 134/160] New ILI9341 driver - not working fully yet (some display issues) --- drivers/gdisp/ILI9341/ILI9341.h | 87 ++++ .../gdisp/ILI9341/board_ILI9341_mikromedia.h | 130 ++++++ .../gdisp/ILI9341/board_ILI9341_template.h | 154 ++++++++ drivers/gdisp/ILI9341/gdisp_lld.c | 373 ++++++++++++++++++ drivers/gdisp/ILI9341/gdisp_lld.mk | 2 + drivers/gdisp/ILI9341/gdisp_lld_config.h | 36 ++ 6 files changed, 782 insertions(+) create mode 100644 drivers/gdisp/ILI9341/ILI9341.h create mode 100644 drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h create mode 100644 drivers/gdisp/ILI9341/board_ILI9341_template.h create mode 100644 drivers/gdisp/ILI9341/gdisp_lld.c create mode 100644 drivers/gdisp/ILI9341/gdisp_lld.mk create mode 100644 drivers/gdisp/ILI9341/gdisp_lld_config.h diff --git a/drivers/gdisp/ILI9341/ILI9341.h b/drivers/gdisp/ILI9341/ILI9341.h new file mode 100644 index 00000000..bace6907 --- /dev/null +++ b/drivers/gdisp/ILI9341/ILI9341.h @@ -0,0 +1,87 @@ + +#define LCD_VERTICAL_MAX 320 +#define LCD_HORIZONTAL_MAX 240 + +#define ILI9341_DEVICE_CODE_READ_REG 0x00 +#define ILI9341_SOFT_RESET_REG 0x01 +#define ILI9341_IDENTINFO_R_REG 0x04 +#define ILI9341_STATUS_R_REG 0x09 +#define ILI9341_POWERMODE_R_REG 0x0A +#define ILI9341_MADCTL_R_REG 0x0B +#define ILI9341_PIXFORMAT_R_REG 0x0C +#define ILI9341_IMGFORMAT_R_REG 0x0D +#define ILI9341_SIGMODE_R_REG 0x0E +#define ILI9341_SD_RESULT_R_REG 0x0F +#define ILI9341_SLEEP_ENTER_REG 0x10 +#define ILI9341_SLEEP_OUT_REG 0x11 +#define ILI9341_PARTIALMODE_REG 0x12 +#define ILI9341_NORDISPMODE_REG 0x13 +#define ILI9341_INVERSIONOFF_REG 0x20 +#define ILI9341_INVERSIONON_REG 0x21 +#define ILI9341_GAMMASET_REG 0x26 +#define ILI9341_DISPLAYOFF_REG 0x28 +#define ILI9341_DISPLAYON_REG 0x29 +#define ILI9341_COLADDRSET_REG 0x2A +#define ILI9341_PAGEADDRSET_REG 0x2B +#define ILI9341_MEMORYWRITE_REG 0x2C +#define ILI9341_COLORSET_REG 0x2D +#define ILI9341_MEMORYREAD_REG 0x2E +#define ILI9341_PARTIALAREA_REG 0x30 +#define ILI9341_VERTSCROLL_REG 0x33 +#define ILI9341_TEAREFFECTLINEOFF_REG 0x34 +#define ILI9341_TEAREFFECTLINEON_REG 0x35 +#define ILI9341_MEMACCESS_REG 0x36 +#define ILI9341_VERSCRSRART_REG 0x37 +#define ILI9341_IDLEMODEOFF_REG 0x38 +#define ILI9341_IDLEMODEON_REG 0x39 +#define ILI9341_PIXFORMATSET_REG 0x3A +#define ILI9341_WRITEMEMCONTINUE_REG 0x3C +#define ILI9341_READMEMCONTINUE_REG 0x3E +#define ILI9341_SETTEATSCAN_REG 0x44 +#define ILI9341_GETSCANLINE_REG 0x45 +#define ILI9341_WRITEBRIGHT_REG 0x51 +#define ILI9341_READBRIGHT_REG 0x52 +#define ILI9341_WRITECTRL_REG 0x53 +#define ILI9341_READCTRL_REG 0x54 +#define ILI9341_WRITECABC_REG 0x55 +#define ILI9341_READCABC_REG 0x56 +#define ILI9341_WRITECABCMB_REG 0x5E +#define ILI9341_READCABCMB_REG 0x5F +#define ILI9341_RGB_ISCTL_REG 0xB0 +#define ILI9341_FRAMECTL_NOR_REG 0xB1 +#define ILI9341_FRAMECTL_IDLE_REG 0xB2 +#define ILI9341_FRAMECTL_PARTIAL_REG 0xB3 +#define ILI9341_INVERCTL_REG 0xB4 +#define ILI9341_BLANKPORCTL_REG 0xB5 +#define ILI9341_FUNCTONCTL_REG 0xB6 +#define ILI9341_ENTRYMODE_REG 0xB7 +#define ILI9341_BLIGHTCTL1_REG 0xB8 +#define ILI9341_BLIGHTCTL2_REG 0xB9 +#define ILI9341_BLIGHTCTL3_REG 0xBA +#define ILI9341_BLIGHTCTL4_REG 0xBB +#define ILI9341_BLIGHTCTL5_REG 0xBC +#define ILI9341_BLIGHTCTL7_REG 0xBE +#define ILI9341_BLIGHTCTL8_REG 0xBF +#define ILI9341_POWERCTL1_REG 0xC0 +#define ILI9341_POWERCTL2_REG 0xC1 +#define ILI9341_VCOMCTL1_REG 0xC5 +#define ILI9341_VCOMCTL2_REG 0xC7 +#define ILI9341_POWERCTLA_REG 0xCB +#define ILI9341_POWERCTLB_REG 0xCF +#define ILI9341_NVMEMWRITE_REG 0xD0 +#define ILI9341_NVMEMPROTECTKEY_REG 0xD1 +#define ILI9341_NVMEMSTATUS_REG 0xD2 +#define ILI9341_READID4_REG 0xD3 +#define ILI9341_READID1_REG 0xDA +#define ILI9341_READID2_REG 0xDB +#define ILI9341_READID3_REG 0xDC +#define ILI9341_POSGAMMACORRECTION_REG 0xE0 +#define ILI9341_NEGGAMMACORRECTION_REG 0xE1 +#define ILI9341_DIGGAMCTL1_REG 0xE2 +#define ILI9341_DIGGAMCTL2_REG 0xE3 +#define ILI9341_DIVTIMCTL_A_REG 0xE8 +#define ILI9341_DIVTIMCTL_B_REG 0xEA +#define ILI9341_POWONSEQCTL_REG 0xED +#define ILI9341_ENABLE_3G_REG 0xF2 +#define ILI9341_INTERFCTL_REG 0xF6 +#define ILI9341_PUMPRATIOCTL_REG 0xF7 diff --git a/drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h b/drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h new file mode 100644 index 00000000..a0eed13b --- /dev/null +++ b/drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h @@ -0,0 +1,130 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h + * @brief GDISP Graphics Driver subsystem low level driver source for the ILI9341 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->board to that structure. +#define SET_CS palSetPad(GPIOE, GPIOE_LCD_CS); +#define CLR_CS palClearPad(GPIOE, GPIOE_LCD_CS); +#define SET_RS palSetPad(GPIOE, GPIOE_LCD_RS); +#define CLR_RS palClearPad(GPIOE, GPIOE_LCD_RS); +#define SET_WR palSetPad(GPIOE, GPIOE_PMWR); +#define CLR_WR palClearPad(GPIOE, GPIOE_PMWR); +#define SET_RD palSetPad(GPIOE, GPIOE_PMRD); +#define CLR_RD palClearPad(GPIOE, GPIOE_PMRD); + +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + /* Configure the pins to a well know state */ + SET_RS; + SET_RD; + SET_WR; + CLR_CS; + + /* Hardware reset */ + palSetPad(GPIOE, GPIOE_LCD_RST); + chThdSleepMilliseconds(100); + palClearPad(GPIOE, GPIOE_LCD_RST); + chThdSleepMilliseconds(100); + palSetPad(GPIOE, GPIOE_LCD_RST); + chThdSleepMilliseconds(100); + break; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if(state) { + // reset lcd + palClearPad(GPIOE, GPIOE_LCD_RST); + } else { + palSetPad(GPIOE, GPIOE_LCD_RST); + } +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + // TODO: can probably pwm this + if(percent) { + // turn back light on + palSetPad(GPIOE, GPIOE_LCD_BLED); + } else { + // turn off + palClearPad(GPIOE, GPIOE_LCD_BLED); + } +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Short delay + * + * @param[in] dly Length of delay + * + * @notapi + */ +static inline void ili9341_delay(uint16_t dly) { + static uint16_t i; + for(i = 0; i < dly; i++) + asm("nop"); +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + palWriteGroup(GPIOE, 0x00FF, 0, index); + CLR_RS; CLR_WR; ili9341_delay(1); SET_WR; ili9341_delay(1); SET_RS; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + palWriteGroup(GPIOE, 0x00FF, 0, data); + CLR_WR; ili9341_delay(1); SET_WR; ili9341_delay(1); +} + +static inline void setreadmode(GDisplay *g) { + (void) g; + // change pin mode to digital input + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); +} + +static inline void setwritemode(GDisplay *g) { + (void) g; + // change pin mode back to digital output + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); +} + +static inline uint16_t read_data(GDisplay *g) { + CLR_RD; + value = palReadPort(GPIOE); + value = palReadPort(GPIOE); + SET_RD; + return value; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/gdisp/ILI9341/board_ILI9341_template.h b/drivers/gdisp/ILI9341/board_ILI9341_template.h new file mode 100644 index 00000000..b8f55dc1 --- /dev/null +++ b/drivers/gdisp/ILI9341/board_ILI9341_template.h @@ -0,0 +1,154 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9341/board_ILI9341_template.h + * @brief GDISP Graphic Driver subsystem board interface for the ILI9341 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +/** + * @brief Initialise the board for the display. + * + * @param[in] g The GDisplay structure + * + * @note Set the g->board member to whatever is appropriate. For multiple + * displays this might be a pointer to the appropriate register set. + * + * @notapi + */ +static inline void init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief After the initialisation. + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +/** + * @brief Set or clear the lcd reset pin. + * + * @param[in] g The GDisplay structure + * @param[in] state TRUE = lcd in reset, FALSE = normal operation + * + * @notapi + */ +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + (void) state; +} + +/** + * @brief Set the lcd back-light level. + * + * @param[in] g The GDisplay structure + * @param[in] percent 0 to 100% + * + * @notapi + */ +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + (void) percent; +} + +/** + * @brief Take exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Release exclusive control of the bus + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Send data to the index register. + * + * @param[in] g The GDisplay structure + * @param[in] index The index register to set + * + * @notapi + */ +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + (void) index; +} + +/** + * @brief Send data to the lcd. + * + * @param[in] g The GDisplay structure + * @param[in] data The data to send + * + * @notapi + */ +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + (void) data; +} + +/** + * @brief Set the bus in read mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setreadmode(GDisplay *g) { + (void) g; +} + +/** + * @brief Set the bus back into write mode + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline void setwritemode(GDisplay *g) { + (void) g; +} + +/** + * @brief Read data from the lcd. + * @return The data from the lcd + * + * @param[in] g The GDisplay structure + * + * @notapi + */ +static inline uint16_t read_data(GDisplay *g) { + (void) g; + return 0; +} + +#endif /* _GDISP_LLD_BOARD_H */ +/** @} */ diff --git a/drivers/gdisp/ILI9341/gdisp_lld.c b/drivers/gdisp/ILI9341/gdisp_lld.c new file mode 100644 index 00000000..e5c4b7d0 --- /dev/null +++ b/drivers/gdisp/ILI9341/gdisp_lld.c @@ -0,0 +1,373 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9341/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for + * the ILI9341 and compatible HVGA display + */ + +#include "gfx.h" + +#if GFX_USE_GDISP + +#if defined(GDISP_SCREEN_HEIGHT) + #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." + #undef GISP_SCREEN_HEIGHT +#endif +#if defined(GDISP_SCREEN_WIDTH) + #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." + #undef GDISP_SCREEN_WIDTH +#endif + +#define GDISP_DRIVER_VMT GDISPVMT_ILI9341 +#include "../drivers/gdisp/ILI9341/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" + +#include "board_ILI9341.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 320 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif + +#include "../drivers/gdisp/ILI9341/ILI9341.h" + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +// Some common routines and macros +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } +#define write_data16(g, data) { write_data(g, data >> 8); write_data(g, (uint8_t)data); } +#define delay(us) gfxSleepMicroseconds(us) +#define delayms(ms) gfxSleepMilliseconds(ms) + +static inline void set_cursor(GDisplay *g) { + write_index(g, 0x2A); + write_data(g, (g->p.x >> 8)); + write_data(g, (uint8_t) g->p.x); + write_data(g, (g->p.x) >> 8); + write_data(g, (uint8_t) (g->p.x)); + + write_index(g, 0x2B); + write_data(g, (g->p.y >> 8)); + write_data(g, (uint8_t) g->p.y); + write_data(g, (g->p.y) >> 8); + write_data(g, (uint8_t) (g->p.y)); + + write_index(g, 0x2C); +} + +static void set_viewport(GDisplay *g) { + write_index(g, 0x2A); + write_data(g, (g->p.x >> 8)); + write_data(g, (uint8_t) g->p.x); + write_data(g, (g->p.x + g->p.cx - 1) >> 8); + write_data(g, (uint8_t) (g->p.x + g->p.cx - 1)); + + write_index(g, 0x2B); + write_data(g, (g->p.y >> 8)); + write_data(g, (uint8_t) g->p.y); + write_data(g, (g->p.y + g->p.cy - 1) >> 8); + write_data(g, (uint8_t) (g->p.y + g->p.cy - 1)); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // No private area for this controller + g->priv = 0; + + // Initialise the board interface + init_board(g); + + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(20); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(20); + + // Get the bus for the following initialisation commands + acquire_bus(g); + + write_index(g, 0x01); //software reset + chThdSleepMilliseconds(5); + write_index(g, 0x28); + // display off + //--------------------------------------------------------- + // magic? + write_index(g, 0xcf); + write_data(g, 0x00); + write_data(g, 0x83); + write_data(g, 0x30); + + write_index(g, 0xed); + write_data(g, 0x64); + write_data(g, 0x03); + write_data(g, 0x12); + write_data(g, 0x81); + write_index(g, 0xe8); + write_data(g, 0x85); + write_data(g, 0x01); + write_data(g, 0x79); + write_index(g, 0xcb); + write_data(g, 0x39); + write_data(g, 0x2c); + write_data(g, 0x00); + write_data(g, 0x34); + write_data(g, 0x02); + write_index(g, 0xf7); + write_data(g, 0x20); + write_index(g, 0xea); + write_data(g, 0x00); + write_data(g, 0x00); + //------------power control------------------------------ + write_index(g, 0xc0); //power control + write_data(g, 0x26); + write_index(g, 0xc1); //power control + write_data(g, 0x11); + //--------------VCOM + write_index(g, 0xc5); //vcom control + write_data(g, 0x35);//35 + write_data(g, 0x3e);//3E + write_index(g, 0xc7); //vcom control + write_data(g, 0xbe); // 0x94 + //------------memory access control------------------------ + write_index(g, 0x36); + // memory access control + write_data(g, 0x48); //0048 my,mx,mv,ml,BGR,mh,0.0 + write_index(g, 0x3a); // pixel format set + write_data(g, 0x55);//16bit /pixel + //----------------- frame rate------------------------------ + write_index(g, 0xb1); + // frame rate + write_data(g, 0x00); + write_data(g, 0x1B); //70 + //----------------Gamma--------------------------------- + write_index(g, 0xf2); // 3Gamma Function Disable + write_data(g, 0x08); + write_index(g, 0x26); + write_data(g, 0x01); // gamma set 4 gamma curve 01/02/04/08 + + write_index(g, 0xE0); //positive gamma correction + write_data(g, 0x1f); + write_data(g, 0x1a); + write_data(g, 0x18); + write_data(g, 0x0a); + write_data(g, 0x0f); + write_data(g, 0x06); + write_data(g, 0x45); + write_data(g, 0x87); + write_data(g, 0x32); + write_data(g, 0x0a); + write_data(g, 0x07); + write_data(g, 0x02); + write_data(g, 0x07); + write_data(g, 0x05); + write_data(g, 0x00); + write_index(g, 0xE1); //negamma correction + write_data(g, 0x00); + write_data(g, 0x25); + write_data(g, 0x27); + write_data(g, 0x05); + write_data(g, 0x10); + write_data(g, 0x09); + write_data(g, 0x3a); + write_data(g, 0x78); + write_data(g, 0x4d); + write_data(g, 0x05); + write_data(g, 0x18); + write_data(g, 0x0d); + write_data(g, 0x38); + write_data(g, 0x3a); + write_data(g, 0x1f); + //--------------ddram --------------------- + write_index(g, 0x2a); + // column set + // size = 239 + write_data(g, 0x00); + write_data(g, 0x00); + write_data(g, 0x00); + write_data(g, 0xEF); + write_index(g, 0x2b); + // page address set + // size = 319 + write_data(g, 0x00); + write_data(g, 0x00); + write_data(g, 0x01); + write_data(g, 0x3F); + // write_index(g, 0x34); + //write_index(g, 0x35); + // tearing effect off + // tearing effect on + // write_index(g, 0xb4); // display inversion + // write_data(g, 0x00); + write_index(g, 0xb7); //entry mode set + write_data(g, 0x07); + //-----------------display--------------------- + write_index(g, 0xb6); + // display function control + write_data(g, 0x0a); + write_data(g, 0x82); + write_data(g, 0x27); + write_data(g, 0x00); + write_index(g, 0x11); //sleep out + chThdSleepMilliseconds(100); + write_index(g, 0x29); // display on + chThdSleepMilliseconds(100); + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + + /* Turn on the back-light */ + set_backlight(g, GDISP_INITIAL_BACKLIGHT); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + return TRUE; +} + +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + #if !GDISP_HARDWARE_STREAM_POS + set_cursor(g); + #endif + } + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data16(g, g->p.color); + } + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); + } + #if GDISP_HARDWARE_STREAM_POS + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { + set_cursor(g); + } + #endif +#endif + +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + set_cursor(g); + setreadmode(g); + dummy_read(g); + } + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { + return read_data(g); + } + LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { + setwritemode(g); + release_bus(g); + } +#endif + +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + case powerSleep: + case powerDeepSleep: + acquire_bus(g); + write_reg(g, 0x0010, 0x0001); /* enter sleep mode */ + release_bus(g); + break; + case powerOn: + acquire_bus(g); + write_reg(g, 0x0010, 0x0000); /* leave sleep mode */ + release_bus(g); + break; + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(g); + write_reg(g, 0x36, 0x00); /* X and Y axes non-inverted */ + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + acquire_bus(g); + write_reg(g, 0x36, 0x20); /* Invert X and Y axes */ + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + acquire_bus(g); + write_reg(g, 0x36, 0x80); /* X and Y axes non-inverted */ + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + acquire_bus(g); + write_reg(g, 0x36, 0xE0); /* Invert X and Y axes */ + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + //case GDISP_CONTROL_CONTRAST: + default: + return; + } + } +#endif + +#endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/ILI9341/gdisp_lld.mk b/drivers/gdisp/ILI9341/gdisp_lld.mk new file mode 100644 index 00000000..8c44fc85 --- /dev/null +++ b/drivers/gdisp/ILI9341/gdisp_lld.mk @@ -0,0 +1,2 @@ +GFXINC += $(GFXLIB)/drivers/gdisp/ILI9341 +GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9341/gdisp_lld.c diff --git a/drivers/gdisp/ILI9341/gdisp_lld_config.h b/drivers/gdisp/ILI9341/gdisp_lld_config.h new file mode 100644 index 00000000..8246934d --- /dev/null +++ b/drivers/gdisp/ILI9341/gdisp_lld_config.h @@ -0,0 +1,36 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/ILI9481/gdisp_lld_config.h + * @brief GDISP Graphics Driver subsystem low level driver source for + * the ILI9481 and compatible HVGA display + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_CONFIG_H +#define _GDISP_LLD_CONFIG_H + +#if GFX_USE_GDISP + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +#define GDISP_HARDWARE_STREAM_WRITE TRUE +//#define GDISP_HARDWARE_STREAM_READ TRUE +//#define GDISP_HARDWARE_STREAM_POS TRUE +#define GDISP_HARDWARE_CONTROL TRUE + +#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_CONFIG_H */ +/** @} */ From b05a29f830008ab0e9a36d8384ed7cf4ea3fb18b Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 28 Oct 2013 11:03:39 +1000 Subject: [PATCH 135/160] Rename GDISP driver files to prevent problems when compiling for multiple controllers on platforms that put all generated object files into a single directory. --- drivers/gdisp/ED060SC4/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_ED060SC4.c} | 0 drivers/gdisp/HX8347D/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_HX8347D.c} | 472 ++++++------ drivers/gdisp/ILI9320/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_ILI9320.c} | 0 drivers/gdisp/ILI9325/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_ILI9325.c} | 0 drivers/gdisp/ILI9341/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_ILI9341.c} | 0 drivers/gdisp/ILI9481/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_ILI9481.c} | 0 drivers/gdisp/Nokia6610GE12/gdisp_lld.mk | 2 +- ...{gdisp_lld.c => gdisp_lld_Nokia6610GE12.c} | 0 drivers/gdisp/Nokia6610GE8/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_Nokia6610GE8.c} | 0 drivers/gdisp/RA8875/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_RA8875.c} | 0 drivers/gdisp/S6D1121/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_S6D1121.c} | 2 +- drivers/gdisp/SSD1289/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_SSD1289.c} | 702 +++++++++--------- drivers/gdisp/SSD1306/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_SSD1306.c} | 560 +++++++------- drivers/gdisp/SSD1963/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_SSD1963.c} | 0 drivers/gdisp/SSD2119/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_SSD2119.c} | 0 drivers/gdisp/ST7565/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_ST7565.c} | 0 drivers/gdisp/TestStub/gdisp_lld.mk | 2 +- .../{gdisp_lld.c => gdisp_lld_TestStub.c} | 0 drivers/multiple/Win32/gdisp_lld.mk | 2 +- .../Win32/{gdisp_lld.c => gdisp_lld_Win32.c} | 0 drivers/multiple/X/gdisp_lld.mk | 2 +- .../multiple/X/{gdisp_lld.c => gdisp_lld_X.c} | 0 36 files changed, 886 insertions(+), 886 deletions(-) rename drivers/gdisp/ED060SC4/{gdisp_lld.c => gdisp_lld_ED060SC4.c} (100%) rename drivers/gdisp/HX8347D/{gdisp_lld.c => gdisp_lld_HX8347D.c} (97%) rename drivers/gdisp/ILI9320/{gdisp_lld.c => gdisp_lld_ILI9320.c} (100%) rename drivers/gdisp/ILI9325/{gdisp_lld.c => gdisp_lld_ILI9325.c} (100%) rename drivers/gdisp/ILI9341/{gdisp_lld.c => gdisp_lld_ILI9341.c} (100%) rename drivers/gdisp/ILI9481/{gdisp_lld.c => gdisp_lld_ILI9481.c} (100%) rename drivers/gdisp/Nokia6610GE12/{gdisp_lld.c => gdisp_lld_Nokia6610GE12.c} (100%) rename drivers/gdisp/Nokia6610GE8/{gdisp_lld.c => gdisp_lld_Nokia6610GE8.c} (100%) rename drivers/gdisp/RA8875/{gdisp_lld.c => gdisp_lld_RA8875.c} (100%) rename drivers/gdisp/S6D1121/{gdisp_lld.c => gdisp_lld_S6D1121.c} (99%) rename drivers/gdisp/SSD1289/{gdisp_lld.c => gdisp_lld_SSD1289.c} (96%) rename drivers/gdisp/SSD1306/{gdisp_lld.c => gdisp_lld_SSD1306.c} (96%) rename drivers/gdisp/SSD1963/{gdisp_lld.c => gdisp_lld_SSD1963.c} (100%) rename drivers/gdisp/SSD2119/{gdisp_lld.c => gdisp_lld_SSD2119.c} (100%) rename drivers/gdisp/ST7565/{gdisp_lld.c => gdisp_lld_ST7565.c} (100%) rename drivers/gdisp/TestStub/{gdisp_lld.c => gdisp_lld_TestStub.c} (100%) rename drivers/multiple/Win32/{gdisp_lld.c => gdisp_lld_Win32.c} (100%) rename drivers/multiple/X/{gdisp_lld.c => gdisp_lld_X.c} (100%) diff --git a/drivers/gdisp/ED060SC4/gdisp_lld.mk b/drivers/gdisp/ED060SC4/gdisp_lld.mk index fc62da03..0c78e1a7 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld.mk +++ b/drivers/gdisp/ED060SC4/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/ED060SC4 -GFXSRC += $(GFXLIB)/drivers/gdisp/ED060SC4/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c diff --git a/drivers/gdisp/ED060SC4/gdisp_lld.c b/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c similarity index 100% rename from drivers/gdisp/ED060SC4/gdisp_lld.c rename to drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c diff --git a/drivers/gdisp/HX8347D/gdisp_lld.mk b/drivers/gdisp/HX8347D/gdisp_lld.mk index 72d9cf75..581e53e7 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld.mk +++ b/drivers/gdisp/HX8347D/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/HX8347D -GFXSRC += $(GFXLIB)/drivers/gdisp/HX8347D/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c diff --git a/drivers/gdisp/HX8347D/gdisp_lld.c b/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c similarity index 97% rename from drivers/gdisp/HX8347D/gdisp_lld.c rename to drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c index ab976db0..fecf115c 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld.c +++ b/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c @@ -1,236 +1,236 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/HX8347D/gdisp_lld.c - * @brief GDISP Graphics Driver subsystem low level driver source for the HX8347D display. - */ - -#include "gfx.h" - -#if GFX_USE_GDISP - -#define GDISP_DRIVER_VMT GDISPVMT_HX8347D -#include "../drivers/gdisp/HX8347D/gdisp_lld_config.h" -#include "gdisp/lld/gdisp_lld.h" - -#include "board_HX8347D.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#ifndef GDISP_SCREEN_HEIGHT - #define GDISP_SCREEN_HEIGHT 320 -#endif -#ifndef GDISP_SCREEN_WIDTH - #define GDISP_SCREEN_WIDTH 240 -#endif -#ifndef GDISP_INITIAL_CONTRAST - #define GDISP_INITIAL_CONTRAST 50 -#endif -#ifndef GDISP_INITIAL_BACKLIGHT - #define GDISP_INITIAL_BACKLIGHT 100 -#endif - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -#include "../drivers/gdisp/HX8347D/HX8347D.h" - -#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } - -static inline void set_viewport(GDisplay* g) { - write_reg(g, HX8347D_REG_SCL, g->p.x); - write_reg(g, HX8347D_REG_SCH, g->p.x >> 8); - write_reg(g, HX8347D_REG_ECL, g->p.x + g->p.cx -1); - write_reg(g, HX8347D_REG_ECH, (g->p.x + g->p.cx -1) >> 8); - write_reg(g, HX8347D_REG_SPL, g->p.y); - write_reg(g, HX8347D_REG_SPH, g->p.y >> 8); - write_reg(g, HX8347D_REG_EPL, g->p.y + g->p.cy -1); - write_reg(g, HX8347D_REG_EPH, (g->p.y + g->p.cy -1) >> 8); - write_index(g, HX8347D_REG_SRAMWC); -} - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - // No private area for this controller - g->priv = 0; - - // Initialise the board interface - init_board(g); - - // Hardware reset - setpin_reset(g, TRUE); - gfxSleepMilliseconds(1); - setpin_reset(g, FALSE); - gfxSleepMilliseconds(5); - - // Get the bus for the following initialisation commands - acquire_bus(g); - - /* Start Initial Sequence ----------------------------------------------------*/ - write_reg(g, HX8347D_REG_STBAH, 0x00); /* Reset Power Control 1 */ - write_reg(g, HX8347D_REG_STBAL, 0x20); /* Power Control 2 */ - write_reg(g, HX8347D_REG_PTBAH, 0x0C); /* Power Control 1 */ - write_reg(g, HX8347D_REG_PTBAL, 0xC4); /* Power Control 2 */ - write_reg(g, HX8347D_REG_OPONN, 0x40); /* Source OPON_N */ - write_reg(g, HX8347D_REG_OPONI, 0x38); /* Source OPON_I */ - write_reg(g, HX8347D_REG_DC2, 0xA3); /* Display Control 2 */ - - /* Power On sequence ---------------------------------------------------------*/ - write_reg(g, HX8347D_REG_PWC2, 0x1B); /* Power Control 2 */ - write_reg(g, HX8347D_REG_PWC1, 0x01); /* Power Control 1 */ - write_reg(g, HX8347D_REG_VMH, 0x2F); /* Vcom Control 2 */ - write_reg(g, HX8347D_REG_VML, 0x57); /* Vcom Control 3 */ - write_reg(g, HX8347D_REG_VMF, 0x8D); /* Vcom Control 1 */ - - /* Gamma settings -----------------------------------------------------------*/ - write_reg(g, HX8347D_REG_VRP0, 0x01); // default setup - write_reg(g, HX8347D_REG_VRP1, 0x0e); // - write_reg(g, HX8347D_REG_VRP2, 0x11); // - write_reg(g, HX8347D_REG_VRP3, 0x1a); // - write_reg(g, HX8347D_REG_VRP4, 0x18); // - write_reg(g, HX8347D_REG_VRP5, 0x24); // - write_reg(g, HX8347D_REG_PRP0, 0x15); // - write_reg(g, HX8347D_REG_PRP1, 0x65); // - write_reg(g, HX8347D_REG_PKP0, 0x0b); // - write_reg(g, HX8347D_REG_PKP1, 0x18); // - write_reg(g, HX8347D_REG_PKP2, 0x19); // - write_reg(g, HX8347D_REG_PKP3, 0x1a); // - write_reg(g, HX8347D_REG_PKP4, 0x18); // - write_reg(g, HX8347D_REG_VRN0, 0x1b); // - write_reg(g, HX8347D_REG_VRN1, 0x27); // - write_reg(g, HX8347D_REG_VRN2, 0x25); // - write_reg(g, HX8347D_REG_VRN3, 0x2e); // - write_reg(g, HX8347D_REG_VRN4, 0x31); // - write_reg(g, HX8347D_REG_VRN5, 0x3e); // - write_reg(g, HX8347D_REG_PRN0, 0x1a); // - write_reg(g, HX8347D_REG_PRN1, 0x6a); // - write_reg(g, HX8347D_REG_PKN0, 0x07); // - write_reg(g, HX8347D_REG_PKN1, 0x05); // - write_reg(g, HX8347D_REG_PKN2, 0x06); // - write_reg(g, HX8347D_REG_PKN3, 0x0b); // - write_reg(g, HX8347D_REG_PKN4, 0x14); // - write_reg(g, HX8347D_REG_CGM, 0xcc); // - - /* Power + Osc ---------------------------------------------------------------*/ - write_reg(g, HX8347D_REG_OSCCH, 0x36); /* OSC Control 1 */ - write_reg(g, HX8347D_REG_OSCCL, 0x01); /* OSC Control 2 */ - write_reg(g, HX8347D_REG_DMODE, 0x00); /* Display Mode Control */ - write_reg(g, HX8347D_REG_PWC6, 0x88); /* Power Control 6 */ - gfxSleepMilliseconds(5); /* Delay 5 ms */ - write_reg(g, HX8347D_REG_PWC6, 0x80); /* Power Control 6 */ - gfxSleepMilliseconds(5); /* Delay 5 ms */ - write_reg(g, HX8347D_REG_PWC6, 0x90); /* Power Control 6 */ - gfxSleepMilliseconds(5); /* Delay 5 ms */ - write_reg(g, HX8347D_REG_PWC6, 0xD0); /* Power Control 6 */ - gfxSleepMilliseconds(5); /* Delay 5 ms */ - write_reg(g, HX8347D_REG_COLMOD, 0x05); /* Colmod 16Bit/Pixel */ - write_reg(g, HX8347D_REG_PCH, 0x00); /* Panel Characteristic */ - write_reg(g, HX8347D_REG_DC3, 0x38); /* Display Control 3 */ - gfxSleepMilliseconds(40); /* Delay 40 ms */ - write_reg(g, HX8347D_REG_DC3, 0x3C); /* Display Control 3 */ - write_reg(g, HX8347D_REG_MAC, 0x08); /* Memory access control */ - - // Finish Init - post_init_board(g); - - // Release the bus - release_bus(g); - - /* Turn on the backlight */ - set_backlight(g, GDISP_INITIAL_BACKLIGHT); - - /* Initialise the GDISP structure */ - g->g.Width = GDISP_SCREEN_WIDTH; - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Orientation = GDISP_ROTATE_0; - g->g.Powermode = powerOn; - g->g.Backlight = GDISP_INITIAL_BACKLIGHT; - g->g.Contrast = GDISP_INITIAL_CONTRAST; - return TRUE; -} - -#if GDISP_HARDWARE_STREAM_WRITE - LLDSPEC void gdisp_lld_write_start(GDisplay *g) { - acquire_bus(g); - set_viewport(g); - busmode16(g); - } - LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_ram16(g, g->p.color); - } - LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { - busmode8(g); - release_bus(g); - } -#endif - -#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDisplay *g) { - switch(g->p.x) { - case GDISP_CONTROL_ORIENTATION: - if (g->g.Orientation == (orientation_t)g->p.ptr) - return; - switch((orientation_t)g->p.ptr) { - case GDISP_ROTATE_0: - acquire_bus(g); - write_reg(g, HX8347D_REG_MAC, 0x08); /* Memory access control */ - release_bus(g); - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Width = GDISP_SCREEN_WIDTH; - break; - - case GDISP_ROTATE_90: - acquire_bus(g); - write_reg(g, HX8347D_REG_MAC, 0x68); /* Memory access control */ - release_bus(g); - g->g.Height = GDISP_SCREEN_WIDTH; - g->g.Width = GDISP_SCREEN_HEIGHT; - break; - - case GDISP_ROTATE_180: - acquire_bus(g); - write_reg(g, HX8347D_REG_MAC, 0xc8); /* Memory access control */ - release_bus(g); - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Width = GDISP_SCREEN_WIDTH; - break; - - case GDISP_ROTATE_270: - acquire_bus(g); - write_reg(g, HX8347D_REG_MAC, 0xa8); /* Memory access control */ - release_bus(g); - g->g.Height = GDISP_SCREEN_WIDTH; - g->g.Width = GDISP_SCREEN_HEIGHT; - break; - - default: - return; - } - g->g.Orientation = (orientation_t)g->p.ptr; - return; - - case GDISP_CONTROL_BACKLIGHT: - if ((unsigned)g->p.ptr > 100) - g->p.ptr = (void *)100; - set_backlight(g, (unsigned)g->p.ptr); - g->g.Backlight = (unsigned)g->p.ptr; - return; - - default: - return; - } - } -#endif - -#endif /* GFX_USE_GDISP */ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/HX8347D/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the HX8347D display. + */ + +#include "gfx.h" + +#if GFX_USE_GDISP + +#define GDISP_DRIVER_VMT GDISPVMT_HX8347D +#include "../drivers/gdisp/HX8347D/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" + +#include "board_HX8347D.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 320 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#include "../drivers/gdisp/HX8347D/HX8347D.h" + +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } + +static inline void set_viewport(GDisplay* g) { + write_reg(g, HX8347D_REG_SCL, g->p.x); + write_reg(g, HX8347D_REG_SCH, g->p.x >> 8); + write_reg(g, HX8347D_REG_ECL, g->p.x + g->p.cx -1); + write_reg(g, HX8347D_REG_ECH, (g->p.x + g->p.cx -1) >> 8); + write_reg(g, HX8347D_REG_SPL, g->p.y); + write_reg(g, HX8347D_REG_SPH, g->p.y >> 8); + write_reg(g, HX8347D_REG_EPL, g->p.y + g->p.cy -1); + write_reg(g, HX8347D_REG_EPH, (g->p.y + g->p.cy -1) >> 8); + write_index(g, HX8347D_REG_SRAMWC); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // No private area for this controller + g->priv = 0; + + // Initialise the board interface + init_board(g); + + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(1); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(5); + + // Get the bus for the following initialisation commands + acquire_bus(g); + + /* Start Initial Sequence ----------------------------------------------------*/ + write_reg(g, HX8347D_REG_STBAH, 0x00); /* Reset Power Control 1 */ + write_reg(g, HX8347D_REG_STBAL, 0x20); /* Power Control 2 */ + write_reg(g, HX8347D_REG_PTBAH, 0x0C); /* Power Control 1 */ + write_reg(g, HX8347D_REG_PTBAL, 0xC4); /* Power Control 2 */ + write_reg(g, HX8347D_REG_OPONN, 0x40); /* Source OPON_N */ + write_reg(g, HX8347D_REG_OPONI, 0x38); /* Source OPON_I */ + write_reg(g, HX8347D_REG_DC2, 0xA3); /* Display Control 2 */ + + /* Power On sequence ---------------------------------------------------------*/ + write_reg(g, HX8347D_REG_PWC2, 0x1B); /* Power Control 2 */ + write_reg(g, HX8347D_REG_PWC1, 0x01); /* Power Control 1 */ + write_reg(g, HX8347D_REG_VMH, 0x2F); /* Vcom Control 2 */ + write_reg(g, HX8347D_REG_VML, 0x57); /* Vcom Control 3 */ + write_reg(g, HX8347D_REG_VMF, 0x8D); /* Vcom Control 1 */ + + /* Gamma settings -----------------------------------------------------------*/ + write_reg(g, HX8347D_REG_VRP0, 0x01); // default setup + write_reg(g, HX8347D_REG_VRP1, 0x0e); // + write_reg(g, HX8347D_REG_VRP2, 0x11); // + write_reg(g, HX8347D_REG_VRP3, 0x1a); // + write_reg(g, HX8347D_REG_VRP4, 0x18); // + write_reg(g, HX8347D_REG_VRP5, 0x24); // + write_reg(g, HX8347D_REG_PRP0, 0x15); // + write_reg(g, HX8347D_REG_PRP1, 0x65); // + write_reg(g, HX8347D_REG_PKP0, 0x0b); // + write_reg(g, HX8347D_REG_PKP1, 0x18); // + write_reg(g, HX8347D_REG_PKP2, 0x19); // + write_reg(g, HX8347D_REG_PKP3, 0x1a); // + write_reg(g, HX8347D_REG_PKP4, 0x18); // + write_reg(g, HX8347D_REG_VRN0, 0x1b); // + write_reg(g, HX8347D_REG_VRN1, 0x27); // + write_reg(g, HX8347D_REG_VRN2, 0x25); // + write_reg(g, HX8347D_REG_VRN3, 0x2e); // + write_reg(g, HX8347D_REG_VRN4, 0x31); // + write_reg(g, HX8347D_REG_VRN5, 0x3e); // + write_reg(g, HX8347D_REG_PRN0, 0x1a); // + write_reg(g, HX8347D_REG_PRN1, 0x6a); // + write_reg(g, HX8347D_REG_PKN0, 0x07); // + write_reg(g, HX8347D_REG_PKN1, 0x05); // + write_reg(g, HX8347D_REG_PKN2, 0x06); // + write_reg(g, HX8347D_REG_PKN3, 0x0b); // + write_reg(g, HX8347D_REG_PKN4, 0x14); // + write_reg(g, HX8347D_REG_CGM, 0xcc); // + + /* Power + Osc ---------------------------------------------------------------*/ + write_reg(g, HX8347D_REG_OSCCH, 0x36); /* OSC Control 1 */ + write_reg(g, HX8347D_REG_OSCCL, 0x01); /* OSC Control 2 */ + write_reg(g, HX8347D_REG_DMODE, 0x00); /* Display Mode Control */ + write_reg(g, HX8347D_REG_PWC6, 0x88); /* Power Control 6 */ + gfxSleepMilliseconds(5); /* Delay 5 ms */ + write_reg(g, HX8347D_REG_PWC6, 0x80); /* Power Control 6 */ + gfxSleepMilliseconds(5); /* Delay 5 ms */ + write_reg(g, HX8347D_REG_PWC6, 0x90); /* Power Control 6 */ + gfxSleepMilliseconds(5); /* Delay 5 ms */ + write_reg(g, HX8347D_REG_PWC6, 0xD0); /* Power Control 6 */ + gfxSleepMilliseconds(5); /* Delay 5 ms */ + write_reg(g, HX8347D_REG_COLMOD, 0x05); /* Colmod 16Bit/Pixel */ + write_reg(g, HX8347D_REG_PCH, 0x00); /* Panel Characteristic */ + write_reg(g, HX8347D_REG_DC3, 0x38); /* Display Control 3 */ + gfxSleepMilliseconds(40); /* Delay 40 ms */ + write_reg(g, HX8347D_REG_DC3, 0x3C); /* Display Control 3 */ + write_reg(g, HX8347D_REG_MAC, 0x08); /* Memory access control */ + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + + /* Turn on the backlight */ + set_backlight(g, GDISP_INITIAL_BACKLIGHT); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + return TRUE; +} + +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + busmode16(g); + } + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_ram16(g, g->p.color); + } + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + busmode8(g); + release_bus(g); + } +#endif + +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(g); + write_reg(g, HX8347D_REG_MAC, 0x08); /* Memory access control */ + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_90: + acquire_bus(g); + write_reg(g, HX8347D_REG_MAC, 0x68); /* Memory access control */ + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + + case GDISP_ROTATE_180: + acquire_bus(g); + write_reg(g, HX8347D_REG_MAC, 0xc8); /* Memory access control */ + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_270: + acquire_bus(g); + write_reg(g, HX8347D_REG_MAC, 0xa8); /* Memory access control */ + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + default: + return; + } + } +#endif + +#endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/ILI9320/gdisp_lld.mk b/drivers/gdisp/ILI9320/gdisp_lld.mk index 071e7c02..d61fbc33 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.mk +++ b/drivers/gdisp/ILI9320/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/ILI9320 -GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9320/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c similarity index 100% rename from drivers/gdisp/ILI9320/gdisp_lld.c rename to drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c diff --git a/drivers/gdisp/ILI9325/gdisp_lld.mk b/drivers/gdisp/ILI9325/gdisp_lld.mk index 61565164..4dbda578 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld.mk +++ b/drivers/gdisp/ILI9325/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/ILI9325 -GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9325/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c diff --git a/drivers/gdisp/ILI9325/gdisp_lld.c b/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c similarity index 100% rename from drivers/gdisp/ILI9325/gdisp_lld.c rename to drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c diff --git a/drivers/gdisp/ILI9341/gdisp_lld.mk b/drivers/gdisp/ILI9341/gdisp_lld.mk index 8c44fc85..326b67ad 100644 --- a/drivers/gdisp/ILI9341/gdisp_lld.mk +++ b/drivers/gdisp/ILI9341/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/ILI9341 -GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9341/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c diff --git a/drivers/gdisp/ILI9341/gdisp_lld.c b/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c similarity index 100% rename from drivers/gdisp/ILI9341/gdisp_lld.c rename to drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c diff --git a/drivers/gdisp/ILI9481/gdisp_lld.mk b/drivers/gdisp/ILI9481/gdisp_lld.mk index 6af4d1f8..8c971788 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld.mk +++ b/drivers/gdisp/ILI9481/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/ILI9481 -GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9481/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c diff --git a/drivers/gdisp/ILI9481/gdisp_lld.c b/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c similarity index 100% rename from drivers/gdisp/ILI9481/gdisp_lld.c rename to drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk b/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk index 892665d5..65781667 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/Nokia6610GE12 -GFXSRC += $(GFXLIB)/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c similarity index 100% rename from drivers/gdisp/Nokia6610GE12/gdisp_lld.c rename to drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk b/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk index 28c57fd6..a61948b3 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/Nokia6610GE8 -GFXSRC += $(GFXLIB)/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c similarity index 100% rename from drivers/gdisp/Nokia6610GE8/gdisp_lld.c rename to drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c diff --git a/drivers/gdisp/RA8875/gdisp_lld.mk b/drivers/gdisp/RA8875/gdisp_lld.mk index 7ac03624..146cf255 100644 --- a/drivers/gdisp/RA8875/gdisp_lld.mk +++ b/drivers/gdisp/RA8875/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/RA8875 -GFXSRC += $(GFXLIB)/drivers/gdisp/RA8875/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/RA8875/gdisp_lld_RA8875.c diff --git a/drivers/gdisp/RA8875/gdisp_lld.c b/drivers/gdisp/RA8875/gdisp_lld_RA8875.c similarity index 100% rename from drivers/gdisp/RA8875/gdisp_lld.c rename to drivers/gdisp/RA8875/gdisp_lld_RA8875.c diff --git a/drivers/gdisp/S6D1121/gdisp_lld.mk b/drivers/gdisp/S6D1121/gdisp_lld.mk index f5f067b7..583feb41 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld.mk +++ b/drivers/gdisp/S6D1121/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/S6D1121 -GFXSRC += $(GFXLIB)/drivers/gdisp/S6D1121/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c diff --git a/drivers/gdisp/S6D1121/gdisp_lld.c b/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c similarity index 99% rename from drivers/gdisp/S6D1121/gdisp_lld.c rename to drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c index df9f01a7..cbaa7199 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld.c +++ b/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c @@ -15,7 +15,7 @@ #include "gfx.h" -#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ +#if GFX_USE_GDISP #if defined(GDISP_SCREEN_HEIGHT) #warning "GDISP: This low level driver does not support setting a screen size. It is being ignored." diff --git a/drivers/gdisp/SSD1289/gdisp_lld.mk b/drivers/gdisp/SSD1289/gdisp_lld.mk index 564610eb..fd2713bc 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.mk +++ b/drivers/gdisp/SSD1289/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/SSD1289 -GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1289/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c similarity index 96% rename from drivers/gdisp/SSD1289/gdisp_lld.c rename to drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c index f600b305..6692e7d7 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c @@ -1,351 +1,351 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD1289/gdisp_lld.c - * @brief GDISP Graphics Driver subsystem low level driver source for the SSD1289 display. - */ - -#include "gfx.h" - -#if GFX_USE_GDISP - -#define GDISP_DRIVER_VMT GDISPVMT_SSD1289 -#include "../drivers/gdisp/SSD1289/gdisp_lld_config.h" -#include "gdisp/lld/gdisp_lld.h" - -#include "board_SSD1289.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#ifndef GDISP_SCREEN_HEIGHT - #define GDISP_SCREEN_HEIGHT 320 -#endif -#ifndef GDISP_SCREEN_WIDTH - #define GDISP_SCREEN_WIDTH 240 -#endif -#ifndef GDISP_INITIAL_CONTRAST - #define GDISP_INITIAL_CONTRAST 50 -#endif -#ifndef GDISP_INITIAL_BACKLIGHT - #define GDISP_INITIAL_BACKLIGHT 100 -#endif - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -// Some common routines and macros -#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } -#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } - -static void set_cursor(GDisplay *g) { - /* - * Reg 0x004E is an 8 bit value - start x position - * Reg 0x004F is 9 bit - start y position - * Use a bit mask to make sure they are not set too high - */ - switch(g->g.Orientation) { - case GDISP_ROTATE_0: - write_reg(g, 0x4e, g->p.x & 0x00FF); - write_reg(g, 0x4f, g->p.y & 0x01FF); - break; - case GDISP_ROTATE_90: - write_reg(g, 0x4e, g->p.y & 0x00FF); - write_reg(g, 0x4f, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); - break; - case GDISP_ROTATE_180: - write_reg(g, 0x4e, (GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF); - write_reg(g, 0x4f, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); - break; - case GDISP_ROTATE_270: - write_reg(g, 0x4e, (GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF); - write_reg(g, 0x4f, g->p.x & 0x01FF); - break; - } - write_index(g, 0x22); -} - -static void set_viewport(GDisplay* g) { - /* Reg 0x44 - Horizontal RAM address position - * Upper Byte - HEA - * Lower Byte - HSA - * 0 <= HSA <= HEA <= 0xEF - * Reg 0x45,0x46 - Vertical RAM address position - * Lower 9 bits gives 0-511 range in each value - * 0 <= Reg(0x45) <= Reg(0x46) <= 0x13F - * Use a bit mask to make sure they are not set too high - */ - switch(g->g.Orientation) { - case GDISP_ROTATE_0: - write_reg(g, 0x44, (((g->p.x+g->p.cx-1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); - write_reg(g, 0x45, g->p.y & 0x01FF); - write_reg(g, 0x46, (g->p.y+g->p.cy-1) & 0x01FF); - break; - case GDISP_ROTATE_90: - write_reg(g, 0x44, (((g->p.y+g->p.cy-1) << 8) & 0xFF00 ) | (g->p.y & 0x00FF)); - write_reg(g, 0x45, (GDISP_SCREEN_HEIGHT-(g->p.x+g->p.cx)) & 0x01FF); - write_reg(g, 0x46, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); - break; - case GDISP_ROTATE_180: - write_reg(g, 0x44, (((GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (g->p.x+g->p.cx)) & 0x00FF)); - write_reg(g, 0x45, (GDISP_SCREEN_HEIGHT-(g->p.y+g->p.cy)) & 0x01FF); - write_reg(g, 0x46, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); - break; - case GDISP_ROTATE_270: - write_reg(g, 0x44, (((GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH-(g->p.y+g->p.cy)) & 0x00FF)); - write_reg(g, 0x45, g->p.x & 0x01FF); - write_reg(g, 0x46, (g->p.x+g->p.cx-1) & 0x01FF); - break; - } -} - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - // No private area for this controller - g->priv = 0; - - // Initialise the board interface - init_board(g); - - // Hardware reset - setpin_reset(g, TRUE); - gfxSleepMilliseconds(20); - setpin_reset(g, FALSE); - gfxSleepMilliseconds(20); - - // Get the bus for the following initialisation commands - acquire_bus(g); - - write_reg(g, 0x00, 0x0001); gfxSleepMicroseconds(5); - write_reg(g, 0x03, 0xA8A4); gfxSleepMicroseconds(5); - write_reg(g, 0x0C, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x0D, 0x080C); gfxSleepMicroseconds(5); - write_reg(g, 0x0E, 0x2B00); gfxSleepMicroseconds(5); - write_reg(g, 0x1E, 0x00B0); gfxSleepMicroseconds(5); - write_reg(g, 0x01, 0x2B3F); gfxSleepMicroseconds(5); - write_reg(g, 0x02, 0x0600); gfxSleepMicroseconds(5); - write_reg(g, 0x10, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x11, 0x6070); gfxSleepMicroseconds(5); - write_reg(g, 0x05, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x06, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x16, 0xEF1C); gfxSleepMicroseconds(5); - write_reg(g, 0x17, 0x0003); gfxSleepMicroseconds(5); - write_reg(g, 0x07, 0x0133); gfxSleepMicroseconds(5); - write_reg(g, 0x0B, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x0F, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x41, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x42, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x48, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x49, 0x013F); gfxSleepMicroseconds(5); - write_reg(g, 0x4A, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x4B, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x44, 0xEF00); gfxSleepMicroseconds(5); - write_reg(g, 0x45, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x46, 0x013F); gfxSleepMicroseconds(5); - write_reg(g, 0x30, 0x0707); gfxSleepMicroseconds(5); - write_reg(g, 0x31, 0x0204); gfxSleepMicroseconds(5); - write_reg(g, 0x32, 0x0204); gfxSleepMicroseconds(5); - write_reg(g, 0x33, 0x0502); gfxSleepMicroseconds(5); - write_reg(g, 0x34, 0x0507); gfxSleepMicroseconds(5); - write_reg(g, 0x35, 0x0204); gfxSleepMicroseconds(5); - write_reg(g, 0x36, 0x0204); gfxSleepMicroseconds(5); - write_reg(g, 0x37, 0x0502); gfxSleepMicroseconds(5); - write_reg(g, 0x3A, 0x0302); gfxSleepMicroseconds(5); - write_reg(g, 0x3B, 0x0302); gfxSleepMicroseconds(5); - write_reg(g, 0x23, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x24, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x25, 0x8000); gfxSleepMicroseconds(5); - write_reg(g, 0x4f, 0x0000); gfxSleepMicroseconds(5); - write_reg(g, 0x4e, 0x0000); gfxSleepMicroseconds(5); - - // Finish Init - post_init_board(g); - - // Release the bus - release_bus(g); - - /* Turn on the back-light */ - set_backlight(g, GDISP_INITIAL_BACKLIGHT); - - /* Initialise the GDISP structure */ - g->g.Width = GDISP_SCREEN_WIDTH; - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Orientation = GDISP_ROTATE_0; - g->g.Powermode = powerOn; - g->g.Backlight = GDISP_INITIAL_BACKLIGHT; - g->g.Contrast = GDISP_INITIAL_CONTRAST; - return TRUE; -} - -#if GDISP_HARDWARE_STREAM_WRITE - LLDSPEC void gdisp_lld_write_start(GDisplay *g) { - acquire_bus(g); - set_viewport(g); - #if !GDISP_HARDWARE_STREAM_POS - set_cursor(g); - #endif - } - LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_data(g, g->p.color); - } - LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { - release_bus(g); - } - #if GDISP_HARDWARE_STREAM_POS - LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { - set_cursor(g); - } - #endif -#endif - -#if GDISP_HARDWARE_STREAM_READ - LLDSPEC void gdisp_lld_read_start(GDisplay *g) { - acquire_bus(g); - set_viewport(g); - set_cursor(g); - setreadmode(g); - dummy_read(g); - } - LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { - return read_data(g); - } - LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { - setwritemode(g); - release_bus(g); - } -#endif - -#if GDISP_HARDWARE_FILLS && defined(GDISP_USE_DMA) - LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { - acquire_bus(g); - set_viewport(g); - set_cursor(g); - dma_with_noinc(g, &color, g->p.cx*g->p.cy) - release_bus(g); - } -#endif - -#if GDISP_HARDWARE_BITFILLS && defined(GDISP_USE_DMA) - LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { - pixel_t *buffer; - coord_t ycnt; - - buffer = (pixel_t *)g->p.ptr + g->p.x1 + g->p.y1 * g->p.x2; - - acquire_bus(g); - set_viewport(g); - set_cursor(g); - if (g->p.x2 == g->p.cx) { - dma_with_inc(g, buffer, g->p.cx*g->p.cy); - } else { - for (ycnt = g->p.cy; ycnt; ycnt--, buffer += g->p.x2) - dma_with_inc(g, buffer, g->p.cy); - } - release_bus(g); - } -#endif - -#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDisplay *g) { - switch(g->p.x) { - case GDISP_CONTROL_POWER: - if (g->g.Powermode == (powermode_t)g->p.ptr) - return; - switch((powermode_t)g->p.ptr) { - case powerOff: - acquire_bus(g); - write_reg(g, 0x10, 0x0000); // leave sleep mode - write_reg(g, 0x07, 0x0000); // halt operation - write_reg(g, 0x00, 0x0000); // turn off oscillator - write_reg(g, 0x10, 0x0001); // enter sleep mode - release_bus(g); - break; - case powerOn: - acquire_bus(g); - write_reg(g, 0x10, 0x0000); // leave sleep mode - write_reg(g, 0x00, 0x0001); // turn on oscillator - gfxSleepMicroseconds(5); - release_bus(g); - break; - case powerSleep: - acquire_bus(g); - write_reg(g, 0x10, 0x0001); // enter sleep mode - release_bus(g); - break; - default: - return; - } - g->g.Powermode = (powermode_t)g->p.ptr; - return; - - case GDISP_CONTROL_ORIENTATION: - if (g->g.Orientation == (orientation_t)g->p.ptr) - return; - switch((orientation_t)g->p.ptr) { - case GDISP_ROTATE_0: - acquire_bus(g); - /* ID = 11 AM = 0 */ - write_reg(g, 0x11, 0x6070); - release_bus(g); - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_90: - acquire_bus(g); - /* ID = 01 AM = 1 */ - write_reg(g, 0x11, 0x6058); - release_bus(g); - g->g.Height = GDISP_SCREEN_WIDTH; - g->g.Width = GDISP_SCREEN_HEIGHT; - break; - case GDISP_ROTATE_180: - acquire_bus(g); - /* ID = 00 AM = 0 */ - write_reg(g, 0x11, 0x6040); - release_bus(g); - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_270: - acquire_bus(g); - /* ID = 10 AM = 1 */ - write_reg(g, 0x11, 0x6068); - release_bus(g); - g->g.Height = GDISP_SCREEN_WIDTH; - g->g.Width = GDISP_SCREEN_HEIGHT; - break; - default: - return; - } - g->g.Orientation = (orientation_t)g->p.ptr; - return; - - case GDISP_CONTROL_BACKLIGHT: - if ((unsigned)g->p.ptr > 100) - g->p.ptr = (void *)100; - set_backlight(g, (unsigned)g->p.ptr); - g->g.Backlight = (unsigned)g->p.ptr; - return; - - //case GDISP_CONTROL_CONTRAST: - default: - return; - } - } -#endif - -#endif /* GFX_USE_GDISP */ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1289/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the SSD1289 display. + */ + +#include "gfx.h" + +#if GFX_USE_GDISP + +#define GDISP_DRIVER_VMT GDISPVMT_SSD1289 +#include "../drivers/gdisp/SSD1289/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" + +#include "board_SSD1289.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 320 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 50 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +// Some common routines and macros +#define dummy_read(g) { volatile uint16_t dummy; dummy = read_data(g); (void) dummy; } +#define write_reg(g, reg, data) { write_index(g, reg); write_data(g, data); } + +static void set_cursor(GDisplay *g) { + /* + * Reg 0x004E is an 8 bit value - start x position + * Reg 0x004F is 9 bit - start y position + * Use a bit mask to make sure they are not set too high + */ + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + write_reg(g, 0x4e, g->p.x & 0x00FF); + write_reg(g, 0x4f, g->p.y & 0x01FF); + break; + case GDISP_ROTATE_90: + write_reg(g, 0x4e, g->p.y & 0x00FF); + write_reg(g, 0x4f, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); + break; + case GDISP_ROTATE_180: + write_reg(g, 0x4e, (GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF); + write_reg(g, 0x4f, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); + break; + case GDISP_ROTATE_270: + write_reg(g, 0x4e, (GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF); + write_reg(g, 0x4f, g->p.x & 0x01FF); + break; + } + write_index(g, 0x22); +} + +static void set_viewport(GDisplay* g) { + /* Reg 0x44 - Horizontal RAM address position + * Upper Byte - HEA + * Lower Byte - HSA + * 0 <= HSA <= HEA <= 0xEF + * Reg 0x45,0x46 - Vertical RAM address position + * Lower 9 bits gives 0-511 range in each value + * 0 <= Reg(0x45) <= Reg(0x46) <= 0x13F + * Use a bit mask to make sure they are not set too high + */ + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + write_reg(g, 0x44, (((g->p.x+g->p.cx-1) << 8) & 0xFF00 ) | (g->p.x & 0x00FF)); + write_reg(g, 0x45, g->p.y & 0x01FF); + write_reg(g, 0x46, (g->p.y+g->p.cy-1) & 0x01FF); + break; + case GDISP_ROTATE_90: + write_reg(g, 0x44, (((g->p.y+g->p.cy-1) << 8) & 0xFF00 ) | (g->p.y & 0x00FF)); + write_reg(g, 0x45, (GDISP_SCREEN_HEIGHT-(g->p.x+g->p.cx)) & 0x01FF); + write_reg(g, 0x46, (GDISP_SCREEN_HEIGHT-1-g->p.x) & 0x01FF); + break; + case GDISP_ROTATE_180: + write_reg(g, 0x44, (((GDISP_SCREEN_WIDTH-1-g->p.x) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH - (g->p.x+g->p.cx)) & 0x00FF)); + write_reg(g, 0x45, (GDISP_SCREEN_HEIGHT-(g->p.y+g->p.cy)) & 0x01FF); + write_reg(g, 0x46, (GDISP_SCREEN_HEIGHT-1-g->p.y) & 0x01FF); + break; + case GDISP_ROTATE_270: + write_reg(g, 0x44, (((GDISP_SCREEN_WIDTH-1-g->p.y) & 0x00FF) << 8) | ((GDISP_SCREEN_WIDTH-(g->p.y+g->p.cy)) & 0x00FF)); + write_reg(g, 0x45, g->p.x & 0x01FF); + write_reg(g, 0x46, (g->p.x+g->p.cx-1) & 0x01FF); + break; + } +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // No private area for this controller + g->priv = 0; + + // Initialise the board interface + init_board(g); + + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(20); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(20); + + // Get the bus for the following initialisation commands + acquire_bus(g); + + write_reg(g, 0x00, 0x0001); gfxSleepMicroseconds(5); + write_reg(g, 0x03, 0xA8A4); gfxSleepMicroseconds(5); + write_reg(g, 0x0C, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x0D, 0x080C); gfxSleepMicroseconds(5); + write_reg(g, 0x0E, 0x2B00); gfxSleepMicroseconds(5); + write_reg(g, 0x1E, 0x00B0); gfxSleepMicroseconds(5); + write_reg(g, 0x01, 0x2B3F); gfxSleepMicroseconds(5); + write_reg(g, 0x02, 0x0600); gfxSleepMicroseconds(5); + write_reg(g, 0x10, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x11, 0x6070); gfxSleepMicroseconds(5); + write_reg(g, 0x05, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x06, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x16, 0xEF1C); gfxSleepMicroseconds(5); + write_reg(g, 0x17, 0x0003); gfxSleepMicroseconds(5); + write_reg(g, 0x07, 0x0133); gfxSleepMicroseconds(5); + write_reg(g, 0x0B, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x0F, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x41, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x42, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x48, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x49, 0x013F); gfxSleepMicroseconds(5); + write_reg(g, 0x4A, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x4B, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x44, 0xEF00); gfxSleepMicroseconds(5); + write_reg(g, 0x45, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x46, 0x013F); gfxSleepMicroseconds(5); + write_reg(g, 0x30, 0x0707); gfxSleepMicroseconds(5); + write_reg(g, 0x31, 0x0204); gfxSleepMicroseconds(5); + write_reg(g, 0x32, 0x0204); gfxSleepMicroseconds(5); + write_reg(g, 0x33, 0x0502); gfxSleepMicroseconds(5); + write_reg(g, 0x34, 0x0507); gfxSleepMicroseconds(5); + write_reg(g, 0x35, 0x0204); gfxSleepMicroseconds(5); + write_reg(g, 0x36, 0x0204); gfxSleepMicroseconds(5); + write_reg(g, 0x37, 0x0502); gfxSleepMicroseconds(5); + write_reg(g, 0x3A, 0x0302); gfxSleepMicroseconds(5); + write_reg(g, 0x3B, 0x0302); gfxSleepMicroseconds(5); + write_reg(g, 0x23, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x24, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x25, 0x8000); gfxSleepMicroseconds(5); + write_reg(g, 0x4f, 0x0000); gfxSleepMicroseconds(5); + write_reg(g, 0x4e, 0x0000); gfxSleepMicroseconds(5); + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + + /* Turn on the back-light */ + set_backlight(g, GDISP_INITIAL_BACKLIGHT); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + return TRUE; +} + +#if GDISP_HARDWARE_STREAM_WRITE + LLDSPEC void gdisp_lld_write_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + #if !GDISP_HARDWARE_STREAM_POS + set_cursor(g); + #endif + } + LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + write_data(g, g->p.color); + } + LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { + release_bus(g); + } + #if GDISP_HARDWARE_STREAM_POS + LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { + set_cursor(g); + } + #endif +#endif + +#if GDISP_HARDWARE_STREAM_READ + LLDSPEC void gdisp_lld_read_start(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + set_cursor(g); + setreadmode(g); + dummy_read(g); + } + LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { + return read_data(g); + } + LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { + setwritemode(g); + release_bus(g); + } +#endif + +#if GDISP_HARDWARE_FILLS && defined(GDISP_USE_DMA) + LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { + acquire_bus(g); + set_viewport(g); + set_cursor(g); + dma_with_noinc(g, &color, g->p.cx*g->p.cy) + release_bus(g); + } +#endif + +#if GDISP_HARDWARE_BITFILLS && defined(GDISP_USE_DMA) + LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { + pixel_t *buffer; + coord_t ycnt; + + buffer = (pixel_t *)g->p.ptr + g->p.x1 + g->p.y1 * g->p.x2; + + acquire_bus(g); + set_viewport(g); + set_cursor(g); + if (g->p.x2 == g->p.cx) { + dma_with_inc(g, buffer, g->p.cx*g->p.cy); + } else { + for (ycnt = g->p.cy; ycnt; ycnt--, buffer += g->p.x2) + dma_with_inc(g, buffer, g->p.cy); + } + release_bus(g); + } +#endif + +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + acquire_bus(g); + write_reg(g, 0x10, 0x0000); // leave sleep mode + write_reg(g, 0x07, 0x0000); // halt operation + write_reg(g, 0x00, 0x0000); // turn off oscillator + write_reg(g, 0x10, 0x0001); // enter sleep mode + release_bus(g); + break; + case powerOn: + acquire_bus(g); + write_reg(g, 0x10, 0x0000); // leave sleep mode + write_reg(g, 0x00, 0x0001); // turn on oscillator + gfxSleepMicroseconds(5); + release_bus(g); + break; + case powerSleep: + acquire_bus(g); + write_reg(g, 0x10, 0x0001); // enter sleep mode + release_bus(g); + break; + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + case GDISP_ROTATE_0: + acquire_bus(g); + /* ID = 11 AM = 0 */ + write_reg(g, 0x11, 0x6070); + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + acquire_bus(g); + /* ID = 01 AM = 1 */ + write_reg(g, 0x11, 0x6058); + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + acquire_bus(g); + /* ID = 00 AM = 0 */ + write_reg(g, 0x11, 0x6040); + release_bus(g); + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + acquire_bus(g); + /* ID = 10 AM = 1 */ + write_reg(g, 0x11, 0x6068); + release_bus(g); + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + set_backlight(g, (unsigned)g->p.ptr); + g->g.Backlight = (unsigned)g->p.ptr; + return; + + //case GDISP_CONTROL_CONTRAST: + default: + return; + } + } +#endif + +#endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/SSD1306/gdisp_lld.mk b/drivers/gdisp/SSD1306/gdisp_lld.mk index ad320292..13df4230 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld.mk +++ b/drivers/gdisp/SSD1306/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/SSD1306 -GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1306/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c diff --git a/drivers/gdisp/SSD1306/gdisp_lld.c b/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c similarity index 96% rename from drivers/gdisp/SSD1306/gdisp_lld.c rename to drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c index 390a9282..bd3e386d 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld.c +++ b/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c @@ -1,280 +1,280 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/SSD1306/gdisp_lld.c - * @brief GDISP Graphics Driver subsystem low level driver source for the SSD1306 display. - */ - -#include "gfx.h" - -#if GFX_USE_GDISP - -#define GDISP_DRIVER_VMT GDISPVMT_SSD1306 -#include "../drivers/gdisp/SSD1306/gdisp_lld_config.h" -#include "gdisp/lld/gdisp_lld.h" - -#include "board_SSD1306.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -#ifndef GDISP_SCREEN_HEIGHT - #define GDISP_SCREEN_HEIGHT 64 // This controller should support 32 (untested) or 64 -#endif -#ifndef GDISP_SCREEN_WIDTH - #define GDISP_SCREEN_WIDTH 128 -#endif -#ifndef GDISP_INITIAL_CONTRAST - #define GDISP_INITIAL_CONTRAST 100 -#endif -#ifndef GDISP_INITIAL_BACKLIGHT - #define GDISP_INITIAL_BACKLIGHT 100 -#endif -#ifdef SSD1306_PAGE_PREFIX - #define SSD1306_PAGE_WIDTH (GDISP_SCREEN_WIDTH+1) - #define SSD1306_PAGE_OFFSET 1 -#else - #define SSD1306_PAGE_WIDTH GDISP_SCREEN_WIDTH - #define SSD1306_PAGE_OFFSET 0 -#endif - -#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0) - -#include "SSD1306.h" - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -// Some common routines and macros -#define RAM(g) ((uint8_t *)g->priv) -#define write_cmd2(g, cmd1, cmd2) { write_cmd(g, cmd1); write_cmd(g, cmd2); } -#define write_cmd3(g, cmd1, cmd2, cmd3) { write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); } - -// Some common routines and macros -#define delay(us) gfxSleepMicroseconds(us) -#define delayms(ms) gfxSleepMilliseconds(ms) - -#define xyaddr(x, y) (SSD1306_PAGE_OFFSET + (x) + ((y)>>3)*SSD1306_PAGE_WIDTH) -#define xybit(y) (1<<((y)&7)) - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * As this controller can't update on a pixel boundary we need to maintain the - * the entire display surface in memory so that we can do the necessary bit - * operations. Fortunately it is a small display in monochrome. - * 64 * 128 / 8 = 1024 bytes. - */ - -LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { - // The private area is the display surface. - g->priv = gfxAlloc(GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH); - - // Fill in the prefix command byte on each page line of the display buffer - // We can do it during initialisation as this byte is never overwritten. - #ifdef SSD1306_PAGE_PREFIX - { - unsigned i; - - for(i=0; i < GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH; i+=SSD1306_PAGE_WIDTH) - RAM(g)[i] = SSD1306_PAGE_PREFIX; - } - #endif - - // Initialise the board interface - init_board(g); - - // Hardware reset - setpin_reset(g, TRUE); - gfxSleepMilliseconds(20); - setpin_reset(g, FALSE); - gfxSleepMilliseconds(20); - - acquire_bus(g); - - write_cmd(g, SSD1306_DISPLAYOFF); - write_cmd2(g, SSD1306_SETDISPLAYCLOCKDIV, 0x80); - write_cmd2(g, SSD1306_SETMULTIPLEX, GDISP_SCREEN_HEIGHT-1); - write_cmd2(g, SSD1306_SETPRECHARGE, 0x1F); - write_cmd2(g, SSD1306_SETDISPLAYOFFSET, 0); - write_cmd(g, SSD1306_SETSTARTLINE | 0); - write_cmd2(g, SSD1306_ENABLE_CHARGE_PUMP, 0x14); - write_cmd2(g, SSD1306_MEMORYMODE, 0); - write_cmd(g, SSD1306_SEGREMAP+1); - write_cmd(g, SSD1306_COMSCANDEC); - #if GDISP_SCREEN_HEIGHT == 64 - write_cmd2(g, SSD1306_SETCOMPINS, 0x12); - #else - write_cmd2(g, SSD1306_SETCOMPINS, 0x22); - #endif - write_cmd2(g, SSD1306_SETCONTRAST, (uint8_t)(GDISP_INITIAL_CONTRAST*256/101)); // Set initial contrast. - write_cmd2(g, SSD1306_SETVCOMDETECT, 0x10); - write_cmd(g, SSD1306_DISPLAYON); - write_cmd(g, SSD1306_NORMALDISPLAY); - write_cmd3(g, SSD1306_HV_COLUMN_ADDRESS, 0, GDISP_SCREEN_WIDTH-1); - write_cmd3(g, SSD1306_HV_PAGE_ADDRESS, 0, GDISP_SCREEN_HEIGHT/8-1); - - // Finish Init - post_init_board(g); - - // Release the bus - release_bus(g); - - /* Initialise the GDISP structure */ - g->g.Width = GDISP_SCREEN_WIDTH; - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Orientation = GDISP_ROTATE_0; - g->g.Powermode = powerOn; - g->g.Backlight = GDISP_INITIAL_BACKLIGHT; - g->g.Contrast = GDISP_INITIAL_CONTRAST; - return TRUE; -} - -#if GDISP_HARDWARE_FLUSH - LLDSPEC void gdisp_lld_flush(GDisplay *g) { - unsigned i; - - // Don't flush if we don't need it. - if (!(g->flags & GDISP_FLG_NEEDFLUSH)) - return; - - write_cmd(g, SSD1306_SETSTARTLINE | 0); - - for(i=0; i < GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH; i+=SSD1306_PAGE_WIDTH) - write_data(g, RAM(g)+i, SSD1306_PAGE_WIDTH); - } -#endif - -#if GDISP_HARDWARE_DRAWPIXEL - LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { - coord_t x, y; - - switch(g->g.Orientation) { - case GDISP_ROTATE_0: - x = g->p.x; - y = g->p.y; - break; - case GDISP_ROTATE_90: - x = g->p.y; - y = GDISP_SCREEN_HEIGHT-1 - g->p.x; - break; - case GDISP_ROTATE_180: - x = GDISP_SCREEN_WIDTH-1 - g->p.x; - y = GDISP_SCREEN_HEIGHT-1 - g->p.y; - break; - case GDISP_ROTATE_270: - x = GDISP_SCREEN_HEIGHT-1 - g->p.y; - x = g->p.x; - break; - } - if (g->p.color != Black) - RAM(g)[xyaddr(x, y)] |= xybit(y); - else - RAM(g)[xyaddr(x, y)] &= ~xybit(y); - g->flags |= GDISP_FLG_NEEDFLUSH; - } -#endif - -#if GDISP_HARDWARE_PIXELREAD - LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { - coord_t x, y; - - switch(g->g.Orientation) { - case GDISP_ROTATE_0: - x = g->p.x; - y = g->p.y; - break; - case GDISP_ROTATE_90: - x = g->p.y; - y = GDISP_SCREEN_HEIGHT-1 - g->p.x; - break; - case GDISP_ROTATE_180: - x = GDISP_SCREEN_WIDTH-1 - g->p.x; - y = GDISP_SCREEN_HEIGHT-1 - g->p.y; - break; - case GDISP_ROTATE_270: - x = GDISP_SCREEN_HEIGHT-1 - g->p.y; - y = g->p.x; - break; - } - return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black; - } -#endif - -#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL - LLDSPEC void gdisp_lld_control(GDisplay *g) { - switch(g->p.x) { - case GDISP_CONTROL_POWER: - if (g->g.Powermode == (powermode_t)g->p.ptr) - return; - switch((powermode_t)g->p.ptr) { - case powerOff: - case powerSleep: - case powerDeepSleep: - acquire_bus(g); - write_cmd(g, SSD1306_DISPLAYOFF); - release_bus(g); - break; - case powerOn: - acquire_bus(g); - write_cmd(g, SSD1306_DISPLAYON); - release_bus(g); - break; - default: - return; - } - g->g.Powermode = (powermode_t)g->p.ptr; - return; - - case GDISP_CONTROL_ORIENTATION: - if (g->g.Orientation == (orientation_t)g->p.ptr) - return; - switch((orientation_t)g->p.ptr) { - /* Rotation is handled by the drawing routines */ - case GDISP_ROTATE_0: - case GDISP_ROTATE_180: - g->g.Height = GDISP_SCREEN_HEIGHT; - g->g.Width = GDISP_SCREEN_WIDTH; - break; - case GDISP_ROTATE_90: - case GDISP_ROTATE_270: - g->g.Height = GDISP_SCREEN_WIDTH; - g->g.Width = GDISP_SCREEN_HEIGHT; - break; - default: - return; - } - g->g.Orientation = (orientation_t)g->p.ptr; - return; - - case GDISP_CONTROL_CONTRAST: - if ((unsigned)g->p.ptr > 100) - g->p.ptr = (void *)100; - acquire_bus(g); - write_cmd2(g, SSD1306_SETCONTRAST, (((unsigned)g->p.ptr)<<8)/101); - release_bus(g); - g->g.Contrast = (unsigned)g->p.ptr; - return; - - // Our own special controller code to inverse the display - // 0 = normal, 1 = inverse - case GDISP_CONTROL_INVERSE: - acquire_bus(g); - write_cmd(g, g->p.ptr ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY); - release_bus(g); - return; - } - } -#endif // GDISP_NEED_CONTROL - -#endif // GFX_USE_GDISP - +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gdisp/SSD1306/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the SSD1306 display. + */ + +#include "gfx.h" + +#if GFX_USE_GDISP + +#define GDISP_DRIVER_VMT GDISPVMT_SSD1306 +#include "../drivers/gdisp/SSD1306/gdisp_lld_config.h" +#include "gdisp/lld/gdisp_lld.h" + +#include "board_SSD1306.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 64 // This controller should support 32 (untested) or 64 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 128 +#endif +#ifndef GDISP_INITIAL_CONTRAST + #define GDISP_INITIAL_CONTRAST 100 +#endif +#ifndef GDISP_INITIAL_BACKLIGHT + #define GDISP_INITIAL_BACKLIGHT 100 +#endif +#ifdef SSD1306_PAGE_PREFIX + #define SSD1306_PAGE_WIDTH (GDISP_SCREEN_WIDTH+1) + #define SSD1306_PAGE_OFFSET 1 +#else + #define SSD1306_PAGE_WIDTH GDISP_SCREEN_WIDTH + #define SSD1306_PAGE_OFFSET 0 +#endif + +#define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0) + +#include "SSD1306.h" + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +// Some common routines and macros +#define RAM(g) ((uint8_t *)g->priv) +#define write_cmd2(g, cmd1, cmd2) { write_cmd(g, cmd1); write_cmd(g, cmd2); } +#define write_cmd3(g, cmd1, cmd2, cmd3) { write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); } + +// Some common routines and macros +#define delay(us) gfxSleepMicroseconds(us) +#define delayms(ms) gfxSleepMilliseconds(ms) + +#define xyaddr(x, y) (SSD1306_PAGE_OFFSET + (x) + ((y)>>3)*SSD1306_PAGE_WIDTH) +#define xybit(y) (1<<((y)&7)) + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * As this controller can't update on a pixel boundary we need to maintain the + * the entire display surface in memory so that we can do the necessary bit + * operations. Fortunately it is a small display in monochrome. + * 64 * 128 / 8 = 1024 bytes. + */ + +LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { + // The private area is the display surface. + g->priv = gfxAlloc(GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH); + + // Fill in the prefix command byte on each page line of the display buffer + // We can do it during initialisation as this byte is never overwritten. + #ifdef SSD1306_PAGE_PREFIX + { + unsigned i; + + for(i=0; i < GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH; i+=SSD1306_PAGE_WIDTH) + RAM(g)[i] = SSD1306_PAGE_PREFIX; + } + #endif + + // Initialise the board interface + init_board(g); + + // Hardware reset + setpin_reset(g, TRUE); + gfxSleepMilliseconds(20); + setpin_reset(g, FALSE); + gfxSleepMilliseconds(20); + + acquire_bus(g); + + write_cmd(g, SSD1306_DISPLAYOFF); + write_cmd2(g, SSD1306_SETDISPLAYCLOCKDIV, 0x80); + write_cmd2(g, SSD1306_SETMULTIPLEX, GDISP_SCREEN_HEIGHT-1); + write_cmd2(g, SSD1306_SETPRECHARGE, 0x1F); + write_cmd2(g, SSD1306_SETDISPLAYOFFSET, 0); + write_cmd(g, SSD1306_SETSTARTLINE | 0); + write_cmd2(g, SSD1306_ENABLE_CHARGE_PUMP, 0x14); + write_cmd2(g, SSD1306_MEMORYMODE, 0); + write_cmd(g, SSD1306_SEGREMAP+1); + write_cmd(g, SSD1306_COMSCANDEC); + #if GDISP_SCREEN_HEIGHT == 64 + write_cmd2(g, SSD1306_SETCOMPINS, 0x12); + #else + write_cmd2(g, SSD1306_SETCOMPINS, 0x22); + #endif + write_cmd2(g, SSD1306_SETCONTRAST, (uint8_t)(GDISP_INITIAL_CONTRAST*256/101)); // Set initial contrast. + write_cmd2(g, SSD1306_SETVCOMDETECT, 0x10); + write_cmd(g, SSD1306_DISPLAYON); + write_cmd(g, SSD1306_NORMALDISPLAY); + write_cmd3(g, SSD1306_HV_COLUMN_ADDRESS, 0, GDISP_SCREEN_WIDTH-1); + write_cmd3(g, SSD1306_HV_PAGE_ADDRESS, 0, GDISP_SCREEN_HEIGHT/8-1); + + // Finish Init + post_init_board(g); + + // Release the bus + release_bus(g); + + /* Initialise the GDISP structure */ + g->g.Width = GDISP_SCREEN_WIDTH; + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Orientation = GDISP_ROTATE_0; + g->g.Powermode = powerOn; + g->g.Backlight = GDISP_INITIAL_BACKLIGHT; + g->g.Contrast = GDISP_INITIAL_CONTRAST; + return TRUE; +} + +#if GDISP_HARDWARE_FLUSH + LLDSPEC void gdisp_lld_flush(GDisplay *g) { + unsigned i; + + // Don't flush if we don't need it. + if (!(g->flags & GDISP_FLG_NEEDFLUSH)) + return; + + write_cmd(g, SSD1306_SETSTARTLINE | 0); + + for(i=0; i < GDISP_SCREEN_HEIGHT/8 * SSD1306_PAGE_WIDTH; i+=SSD1306_PAGE_WIDTH) + write_data(g, RAM(g)+i, SSD1306_PAGE_WIDTH); + } +#endif + +#if GDISP_HARDWARE_DRAWPIXEL + LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + coord_t x, y; + + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90: + x = g->p.y; + y = GDISP_SCREEN_HEIGHT-1 - g->p.x; + break; + case GDISP_ROTATE_180: + x = GDISP_SCREEN_WIDTH-1 - g->p.x; + y = GDISP_SCREEN_HEIGHT-1 - g->p.y; + break; + case GDISP_ROTATE_270: + x = GDISP_SCREEN_HEIGHT-1 - g->p.y; + x = g->p.x; + break; + } + if (g->p.color != Black) + RAM(g)[xyaddr(x, y)] |= xybit(y); + else + RAM(g)[xyaddr(x, y)] &= ~xybit(y); + g->flags |= GDISP_FLG_NEEDFLUSH; + } +#endif + +#if GDISP_HARDWARE_PIXELREAD + LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) { + coord_t x, y; + + switch(g->g.Orientation) { + case GDISP_ROTATE_0: + x = g->p.x; + y = g->p.y; + break; + case GDISP_ROTATE_90: + x = g->p.y; + y = GDISP_SCREEN_HEIGHT-1 - g->p.x; + break; + case GDISP_ROTATE_180: + x = GDISP_SCREEN_WIDTH-1 - g->p.x; + y = GDISP_SCREEN_HEIGHT-1 - g->p.y; + break; + case GDISP_ROTATE_270: + x = GDISP_SCREEN_HEIGHT-1 - g->p.y; + y = g->p.x; + break; + } + return (RAM(g)[xyaddr(x, y)] & xybit(y)) ? White : Black; + } +#endif + +#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + LLDSPEC void gdisp_lld_control(GDisplay *g) { + switch(g->p.x) { + case GDISP_CONTROL_POWER: + if (g->g.Powermode == (powermode_t)g->p.ptr) + return; + switch((powermode_t)g->p.ptr) { + case powerOff: + case powerSleep: + case powerDeepSleep: + acquire_bus(g); + write_cmd(g, SSD1306_DISPLAYOFF); + release_bus(g); + break; + case powerOn: + acquire_bus(g); + write_cmd(g, SSD1306_DISPLAYON); + release_bus(g); + break; + default: + return; + } + g->g.Powermode = (powermode_t)g->p.ptr; + return; + + case GDISP_CONTROL_ORIENTATION: + if (g->g.Orientation == (orientation_t)g->p.ptr) + return; + switch((orientation_t)g->p.ptr) { + /* Rotation is handled by the drawing routines */ + case GDISP_ROTATE_0: + case GDISP_ROTATE_180: + g->g.Height = GDISP_SCREEN_HEIGHT; + g->g.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + case GDISP_ROTATE_270: + g->g.Height = GDISP_SCREEN_WIDTH; + g->g.Width = GDISP_SCREEN_HEIGHT; + break; + default: + return; + } + g->g.Orientation = (orientation_t)g->p.ptr; + return; + + case GDISP_CONTROL_CONTRAST: + if ((unsigned)g->p.ptr > 100) + g->p.ptr = (void *)100; + acquire_bus(g); + write_cmd2(g, SSD1306_SETCONTRAST, (((unsigned)g->p.ptr)<<8)/101); + release_bus(g); + g->g.Contrast = (unsigned)g->p.ptr; + return; + + // Our own special controller code to inverse the display + // 0 = normal, 1 = inverse + case GDISP_CONTROL_INVERSE: + acquire_bus(g); + write_cmd(g, g->p.ptr ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY); + release_bus(g); + return; + } + } +#endif // GDISP_NEED_CONTROL + +#endif // GFX_USE_GDISP + diff --git a/drivers/gdisp/SSD1963/gdisp_lld.mk b/drivers/gdisp/SSD1963/gdisp_lld.mk index ad406898..f56f11de 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld.mk +++ b/drivers/gdisp/SSD1963/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/SSD1963 -GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1963/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c diff --git a/drivers/gdisp/SSD1963/gdisp_lld.c b/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c similarity index 100% rename from drivers/gdisp/SSD1963/gdisp_lld.c rename to drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c diff --git a/drivers/gdisp/SSD2119/gdisp_lld.mk b/drivers/gdisp/SSD2119/gdisp_lld.mk index 46807f62..921eaa2c 100644 --- a/drivers/gdisp/SSD2119/gdisp_lld.mk +++ b/drivers/gdisp/SSD2119/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/SSD2119 -GFXSRC += $(GFXLIB)/drivers/gdisp/SSD2119/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c diff --git a/drivers/gdisp/SSD2119/gdisp_lld.c b/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c similarity index 100% rename from drivers/gdisp/SSD2119/gdisp_lld.c rename to drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c diff --git a/drivers/gdisp/ST7565/gdisp_lld.mk b/drivers/gdisp/ST7565/gdisp_lld.mk index cf0896e6..9f9c5408 100644 --- a/drivers/gdisp/ST7565/gdisp_lld.mk +++ b/drivers/gdisp/ST7565/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/ST7565 -GFXSRC += $(GFXLIB)/drivers/gdisp/ST7565/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/ST7565/gdisp_lld_ST7565.c diff --git a/drivers/gdisp/ST7565/gdisp_lld.c b/drivers/gdisp/ST7565/gdisp_lld_ST7565.c similarity index 100% rename from drivers/gdisp/ST7565/gdisp_lld.c rename to drivers/gdisp/ST7565/gdisp_lld_ST7565.c diff --git a/drivers/gdisp/TestStub/gdisp_lld.mk b/drivers/gdisp/TestStub/gdisp_lld.mk index 9394ee9d..d8faa3e9 100644 --- a/drivers/gdisp/TestStub/gdisp_lld.mk +++ b/drivers/gdisp/TestStub/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/gdisp/TestStub -GFXSRC += $(GFXLIB)/drivers/gdisp/TestStub/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/gdisp/TestStub/gdisp_lld_TestStub.c diff --git a/drivers/gdisp/TestStub/gdisp_lld.c b/drivers/gdisp/TestStub/gdisp_lld_TestStub.c similarity index 100% rename from drivers/gdisp/TestStub/gdisp_lld.c rename to drivers/gdisp/TestStub/gdisp_lld_TestStub.c diff --git a/drivers/multiple/Win32/gdisp_lld.mk b/drivers/multiple/Win32/gdisp_lld.mk index 081d8dda..f9242380 100644 --- a/drivers/multiple/Win32/gdisp_lld.mk +++ b/drivers/multiple/Win32/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/multiple/Win32 -GFXSRC += $(GFXLIB)/drivers/multiple/Win32/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/multiple/Win32/gdisp_lld_Win32.c diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld_Win32.c similarity index 100% rename from drivers/multiple/Win32/gdisp_lld.c rename to drivers/multiple/Win32/gdisp_lld_Win32.c diff --git a/drivers/multiple/X/gdisp_lld.mk b/drivers/multiple/X/gdisp_lld.mk index e7b9daef..572a5b7d 100644 --- a/drivers/multiple/X/gdisp_lld.mk +++ b/drivers/multiple/X/gdisp_lld.mk @@ -1,2 +1,2 @@ GFXINC += $(GFXLIB)/drivers/multiple/X -GFXSRC += $(GFXLIB)/drivers/multiple/X/gdisp_lld.c +GFXSRC += $(GFXLIB)/drivers/multiple/X/gdisp_lld_X.c diff --git a/drivers/multiple/X/gdisp_lld.c b/drivers/multiple/X/gdisp_lld_X.c similarity index 100% rename from drivers/multiple/X/gdisp_lld.c rename to drivers/multiple/X/gdisp_lld_X.c From 737ac5be9743e37b80133706faf02e959e803459 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 28 Oct 2013 19:06:16 +1000 Subject: [PATCH 136/160] Create uGFX board directories which include example Makefiles. Currently only done for the Olimex-SAM7EX256 board. --- boards/base/Olimex-SAM7EX256-GE12/board.mk | 14 + .../board_Nokia6610GE12.h | 2 +- boards/base/Olimex-SAM7EX256-GE12/readme.txt | 6 + boards/base/Olimex-SAM7EX256-GE8/board.mk | 14 + .../Olimex-SAM7EX256-GE8/board_Nokia6610GE8.h | 23 +- .../Olimex-SAM7EX256-GE8/example/Makefile | 199 +++++++ .../Olimex-SAM7EX256-GE8/example/chconf.h | 542 ++++++++++++++++++ .../Olimex-SAM7EX256-GE8/example/halconf.h | 360 ++++++++++++ .../Olimex-SAM7EX256-GE8/example/linker.ld | 105 ++++ .../Olimex-SAM7EX256-GE8/example/mcuconf.h | 71 +++ .../Olimex-SAM7EX256-GE8/example/readme.txt | 3 + .../Olimex-SAM7EX256-GE8/gadc_lld_board.h | 12 +- .../Olimex-SAM7EX256-GE8/gaudin_lld_board.h | 33 ++ .../ginput_lld_dial_board.h | 30 + .../ginput_lld_toggle_board.h | 8 +- .../gadc/AT91SAM7/gadc_lld_board_template.h | 37 ++ drivers/gadc/AT91SAM7/gadc_lld_config.h | 12 +- ...am7ex256.h => gaudin_lld_board_template.h} | 15 +- drivers/gaudin/gadc/gaudin_lld_config.h | 11 +- ...256.h => ginput_lld_dial_board_template.h} | 9 +- .../ginput/dial/GADC/ginput_lld_dial_config.h | 11 +- ...e.h => ginput_lld_toggle_board_template.h} | 84 +-- .../toggle/Pal/ginput_lld_toggle_config.h | 11 +- 23 files changed, 1501 insertions(+), 111 deletions(-) create mode 100644 boards/base/Olimex-SAM7EX256-GE12/board.mk rename drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h => boards/base/Olimex-SAM7EX256-GE12/board_Nokia6610GE12.h (98%) create mode 100644 boards/base/Olimex-SAM7EX256-GE12/readme.txt create mode 100644 boards/base/Olimex-SAM7EX256-GE8/board.mk rename drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h => boards/base/Olimex-SAM7EX256-GE8/board_Nokia6610GE8.h (88%) create mode 100644 boards/base/Olimex-SAM7EX256-GE8/example/Makefile create mode 100644 boards/base/Olimex-SAM7EX256-GE8/example/chconf.h create mode 100644 boards/base/Olimex-SAM7EX256-GE8/example/halconf.h create mode 100644 boards/base/Olimex-SAM7EX256-GE8/example/linker.ld create mode 100644 boards/base/Olimex-SAM7EX256-GE8/example/mcuconf.h create mode 100644 boards/base/Olimex-SAM7EX256-GE8/example/readme.txt rename drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h => boards/base/Olimex-SAM7EX256-GE8/gadc_lld_board.h (73%) create mode 100644 boards/base/Olimex-SAM7EX256-GE8/gaudin_lld_board.h create mode 100644 boards/base/Olimex-SAM7EX256-GE8/ginput_lld_dial_board.h rename drivers/ginput/toggle/Pal/ginput_lld_toggle_board_olimexsam7ex256.h => boards/base/Olimex-SAM7EX256-GE8/ginput_lld_toggle_board.h (91%) create mode 100644 drivers/gadc/AT91SAM7/gadc_lld_board_template.h rename drivers/gaudin/gadc/{gaudin_lld_board_olimexsam7ex256.h => gaudin_lld_board_template.h} (71%) rename drivers/ginput/dial/GADC/{ginput_lld_dial_board_olimexsam7ex256.h => ginput_lld_dial_board_template.h} (77%) rename drivers/ginput/toggle/Pal/{ginput_lld_toggle_board_example.h => ginput_lld_toggle_board_template.h} (93%) diff --git a/boards/base/Olimex-SAM7EX256-GE12/board.mk b/boards/base/Olimex-SAM7EX256-GE12/board.mk new file mode 100644 index 00000000..5230b6b4 --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE12/board.mk @@ -0,0 +1,14 @@ +GFXINC += $(GFXLIB)/boards/base/Olimex-SAM7EX256-GE12 $(GFXLIB)/boards/base/Olimex-SAM7EX256-GE8 +GFXSRC += +GFXDEFS += -DGFX_USE_OS_CHIBIOS=TRUE + +#This board has a Nokia6610GE12 display +include $(GFXLIB)/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk +#This board supports GADC via the AT91SAM7 driver +include $(GFXLIB)/drivers/gadc/AT91SAM7/gadc_lld.mk +#This board supports GINPUT dials via the GADC driver +include $(GFXLIB)/drivers/ginput/dial/GADC/ginput_lld.mk +#This board supports GINPUT toggles via the Pal driver +include $(GFXLIB)/drivers/ginput/toggle/Pal/ginput_lld.mk +#This board support GAUDIN via the GADC driver +include $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.mk diff --git a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h b/boards/base/Olimex-SAM7EX256-GE12/board_Nokia6610GE12.h similarity index 98% rename from drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h rename to boards/base/Olimex-SAM7EX256-GE12/board_Nokia6610GE12.h index 12dbc9a5..feb1887e 100644 --- a/drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h +++ b/boards/base/Olimex-SAM7EX256-GE12/board_Nokia6610GE12.h @@ -6,7 +6,7 @@ */ /** - * @file drivers/gdisp/Nokia6610GE8/board_Nokia6610GE8_olimexsam7ex256.h + * @file boards/base/Olimex-SAM7EX256-GE12/board_Nokia6610GE12.h * @brief GDISP Graphic Driver subsystem board interface for the Olimex SAM7-EX256 board. */ diff --git a/boards/base/Olimex-SAM7EX256-GE12/readme.txt b/boards/base/Olimex-SAM7EX256-GE12/readme.txt new file mode 100644 index 00000000..b84e5575 --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE12/readme.txt @@ -0,0 +1,6 @@ +This is the same as the Olimex-SAM7EX256-GE8 board except that it uses the GE12 display controller +instead of the GE8 display controller. + +See the Olimex-SAM7EX256-GE8 board file directory for example Makefiles etc. +Don't forget to change the example Makefile to point the GFX board file to the GE12 instead of the GE8. + diff --git a/boards/base/Olimex-SAM7EX256-GE8/board.mk b/boards/base/Olimex-SAM7EX256-GE8/board.mk new file mode 100644 index 00000000..c11a0bbb --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/board.mk @@ -0,0 +1,14 @@ +GFXINC += $(GFXLIB)/boards/base/Olimex-SAM7EX256-GE8 +GFXSRC += +GFXDEFS += -DGFX_USE_OS_CHIBIOS=TRUE + +#This board has a Nokia6610GE8 display +include $(GFXLIB)/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk +#This board supports GADC via the AT91SAM7 driver +include $(GFXLIB)/drivers/gadc/AT91SAM7/gadc_lld.mk +#This board supports GINPUT dials via the GADC driver +include $(GFXLIB)/drivers/ginput/dial/GADC/ginput_lld.mk +#This board supports GINPUT toggles via the Pal driver +include $(GFXLIB)/drivers/ginput/toggle/Pal/ginput_lld.mk +#This board support GAUDIN via the GADC driver +include $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.mk diff --git a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h b/boards/base/Olimex-SAM7EX256-GE8/board_Nokia6610GE8.h similarity index 88% rename from drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h rename to boards/base/Olimex-SAM7EX256-GE8/board_Nokia6610GE8.h index 5b9ff6f6..c88dbe74 100644 --- a/drivers/gdisp/Nokia6610GE12/board_Nokia6610GE12_olimexsam7ex256.h +++ b/boards/base/Olimex-SAM7EX256-GE8/board_Nokia6610GE8.h @@ -6,7 +6,7 @@ */ /** - * @file drivers/gdisp/Nokia6610GE8/board_Nokia6610GE12_olimexsam7ex256.h + * @file boards/base/Olimex-SAM7EX256-GE8/board_Nokia6610GE8.h * @brief GDISP Graphic Driver subsystem board interface for the Olimex SAM7-EX256 board. */ @@ -17,12 +17,14 @@ * Set various display properties. These properties mostly depend on the exact controller chip you get. * The defaults should work for most controllers. */ +//#define GDISP_GE8_BROKEN_CONTROLLER FALSE // Uncomment this out if you have a controller thats not window wrap broken. //#define GDISP_SCREEN_HEIGHT 130 // The visible display height //#define GDISP_SCREEN_WIDTH 130 // The visible display width //#define GDISP_RAM_X_OFFSET 0 // The x offset of the visible area //#define GDISP_RAM_Y_OFFSET 2 // The y offset of the visible area +//#define GDISP_SLEEP_SIZE 32 // The size of the sleep mode partial display //#define GDISP_SLEEP_POS 50 // The position of the sleep mode partial display -//#define GDISP_INITIAL_CONTRAST 50 // The initial contrast percentage +//#define GDISP_INITIAL_CONTRAST 38 // The initial contrast percentage //#define GDISP_INITIAL_BACKLIGHT 100 // The initial backlight percentage // For a multiple display configuration we would put all this in a structure and then @@ -57,6 +59,16 @@ static const PWMConfig pwmcfg = { static bool_t pwmRunning = FALSE; +/** + * @brief Initialise the board for the display. + * @notes Performs the following functions: + * 1. initialise the spi port used by your display + * 2. initialise the reset pin (initial state not-in-reset) + * 3. initialise the chip select pin (initial state not-active) + * 4. initialise the backlight pin (initial state back-light off) + * + * @notapi + */ static inline void init_board(GDisplay *g) { // As we are not using multiple displays we set g->board to NULL as we don't use it. @@ -132,7 +144,6 @@ static inline void setpin_reset(GDisplay *g, bool_t state) { static inline void set_backlight(GDisplay *g, uint8_t percent) { (void) g; - if (percent == 100) { /* Turn the pin on - No PWM */ if (pwmRunning) { @@ -165,18 +176,16 @@ static inline void release_bus(GDisplay *g) { (void) g; } -static inline void write_index(GDisplay *g, uint16_t cmd) { +static inline void write_index(GDisplay *g, uint16_t index) { (void) g; - // wait for the previous transfer to complete while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // send the command - pSPI->SPI_TDR = cmd & 0xFF; + pSPI->SPI_TDR = index & 0xFF; } static inline void write_data(GDisplay *g, uint16_t data) { (void) g; - // wait for the previous transfer to complete while((pSPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // send the data diff --git a/boards/base/Olimex-SAM7EX256-GE8/example/Makefile b/boards/base/Olimex-SAM7EX256-GE8/example/Makefile new file mode 100644 index 00000000..cff4e7ad --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/example/Makefile @@ -0,0 +1,199 @@ +############################################################################## +# Build global options +# NOTE: Can be overridden externally. +# + +# Compiler options here. +ifeq ($(USE_OPT),) +# USE_OPT = -O2 -ggdb -gstabs+ -fomit-frame-pointer -mabi=apcs-gnu + USE_OPT = -O0 -ggdb -gstabs+ -fomit-frame-pointer -mabi=apcs-gnu +endif + +# C specific options here (added to USE_OPT). +ifeq ($(USE_COPT),) + USE_COPT = +endif + +# C++ specific options here (added to USE_OPT). +ifeq ($(USE_CPPOPT),) + USE_CPPOPT = -fno-rtti +endif + +# Enable this if you want the linker to remove unused code and data +ifeq ($(USE_LINK_GC),) + USE_LINK_GC = yes +endif + +# If enabled, this option allows to compile the application in THUMB mode. +ifeq ($(USE_THUMB),) + USE_THUMB = no +endif + +# Enable this if you want to see the full log while compiling. +ifeq ($(USE_VERBOSE_COMPILE),) + USE_VERBOSE_COMPILE = no +endif + +# +# Build global options +############################################################################## + +############################################################################## +# Project, sources and paths +# + +# Define project name here +PROJECT = ch + +# Imported source files and paths for ChibiOS +CHIBIOS = ../ChibiOS +include $(CHIBIOS)/boards/OLIMEX_SAM7_EX256/board.mk +include $(CHIBIOS)/os/hal/platforms/AT91SAM7/platform.mk +include $(CHIBIOS)/os/hal/hal.mk +include $(CHIBIOS)/os/ports/GCC/ARM/AT91SAM7/port.mk +include $(CHIBIOS)/os/kernel/kernel.mk + +# We define a non standard linker script here just to give us some more stack space +# LDSCRIPT= $(PORTLD)/AT91SAM7X256.ld +LDSCRIPT= linker.ld + +# Imported source files and paths for uGFX +GFXLIB = ../uGFX +include $(GFXLIB)/gfx.mk +include $(GFXLIB)/boards/base/Olimex-SAM7EX256-GE8/board.mk + +# Where is our source code - alter these for your project. +MYFILES = $(GFXLIB)/demos/modules/gdisp/basics +MYCSRC = $(MYFILES)/main.c + +# C sources that can be compiled in ARM or THUMB mode depending on the global +# setting. +CSRC = $(PORTSRC) \ + $(KERNSRC) \ + $(TESTSRC) \ + $(HALSRC) \ + $(PLATFORMSRC) \ + $(BOARDSRC) \ + $(GFXSRC) \ + $(MYCSRC) + +# C++ sources that can be compiled in ARM or THUMB mode depending on the global +# setting. +CPPSRC = + +# C sources to be compiled in ARM mode regardless of the global setting. +# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler +# option that results in lower performance and larger code size. +ACSRC = + +# C++ sources to be compiled in ARM mode regardless of the global setting. +# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler +# option that results in lower performance and larger code size. +ACPPSRC = + +# C sources to be compiled in THUMB mode regardless of the global setting. +# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler +# option that results in lower performance and larger code size. +TCSRC = + +# C sources to be compiled in THUMB mode regardless of the global setting. +# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler +# option that results in lower performance and larger code size. +TCPPSRC = + +# List ASM source files here +ASMSRC = $(PORTASM) + +INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \ + $(HALINC) $(PLATFORMINC) $(BOARDINC) \ + $(GFXINC) \ + $(MYFILES) + +# +# Project, sources and paths +############################################################################## + +############################################################################## +# Compiler settings +# + +MCU = arm7tdmi + +#TRGT = arm-elf- +TRGT = arm-none-eabi- +CC = $(TRGT)gcc +CPPC = $(TRGT)g++ +# Enable loading with g++ only if you need C++ runtime support. +# NOTE: You can use C++ even without C++ support if you are careful. C++ +# runtime support makes code size explode. +LD = $(TRGT)gcc -ggdb -gstabs+ +#LD = $(TRGT)g++ +CP = $(TRGT)objcopy +AS = $(TRGT)gcc -x assembler-with-cpp +OD = $(TRGT)objdump +HEX = $(CP) -O ihex +BIN = $(CP) -O binary + +# ARM-specific options here +AOPT = + +# THUMB-specific options here +TOPT = -mthumb -DTHUMB + +# Define C warning options here +CWARN = -Wall -Wextra -Wstrict-prototypes + +# Define C++ warning options here +CPPWARN = -Wall -Wextra + +# +# Compiler settings +############################################################################## + +############################################################################## +# Start of default section +# + +# List all default C defines here, like -D_DEBUG=1 +DDEFS = $(GFXDEFS) + +# List all default ASM defines here, like -D_DEBUG=1 +DADEFS = + +# List all default directories to look for include files here +DINCDIR = + +# List the default directory to look for the libraries here +DLIBDIR = + +# List all default libraries here +DLIBS = + +# +# End of default section +############################################################################## + +############################################################################## +# Start of user section +# + +# List all user C define here, like -D_DEBUG=1 +UDEFS = + +# Define ASM defines here +UADEFS = + +# List all user directories here +UINCDIR = + +# List the user directory to look for the libraries here +ULIBDIR = + +# List all user libraries here +ULIBS = + +# +# End of user defines +############################################################################## + +include $(CHIBIOS)/os/ports/GCC/ARM/rules.mk diff --git a/boards/base/Olimex-SAM7EX256-GE8/example/chconf.h b/boards/base/Olimex-SAM7EX256-GE8/example/chconf.h new file mode 100644 index 00000000..6d012c3e --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/example/chconf.h @@ -0,0 +1,542 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + --- + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes ChibiOS/RT, without being obliged to provide + the source code for any proprietary components. See the file exception.txt + for full details of how and when the exception can be applied. +*/ + +/** + * @file templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef _CHCONF_H_ +#define _CHCONF_H_ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + */ +#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__) +#define CH_FREQUENCY 1000 +#endif + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + */ +#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__) +#define CH_TIME_QUANTUM 20 +#endif + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_USE_MEMCORE. + */ +#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__) +#define CH_MEMCORE_SIZE 0 +#endif + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread automatically. The application has + * then the responsibility to do one of the following: + * - Spawn a custom idle thread at priority @p IDLEPRIO. + * - Change the main() thread priority to @p IDLEPRIO then enter + * an endless loop. In this scenario the @p main() thread acts as + * the idle thread. + * . + * @note Unless an idle thread is spawned the @p main() thread must not + * enter a sleep state. + */ +#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__) +#define CH_NO_IDLE_THREAD FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__) +#define CH_OPTIMIZE_SPEED TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__) +#define CH_USE_REGISTRY TRUE +#endif + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__) +#define CH_USE_WAITEXIT TRUE +#endif + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__) +#define CH_USE_SEMAPHORES TRUE +#endif + +/** + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special requirements. + * @note Requires @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__) +#define CH_USE_SEMAPHORES_PRIORITY FALSE +#endif + +/** + * @brief Atomic semaphore API. + * @details If enabled then the semaphores the @p chSemSignalWait() API + * is included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__) +#define CH_USE_SEMSW TRUE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__) +#define CH_USE_MUTEXES TRUE +#endif + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_MUTEXES. + */ +#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__) +#define CH_USE_CONDVARS TRUE +#endif + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_CONDVARS. + */ +#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__) +#define CH_USE_CONDVARS_TIMEOUT TRUE +#endif + +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__) +#define CH_USE_EVENTS TRUE +#endif + +/** + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_EVENTS. + */ +#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__) +#define CH_USE_EVENTS_TIMEOUT TRUE +#endif + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__) +#define CH_USE_MESSAGES TRUE +#endif + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special requirements. + * @note Requires @p CH_USE_MESSAGES. + */ +#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__) +#define CH_USE_MESSAGES_PRIORITY FALSE +#endif + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__) +#define CH_USE_MAILBOXES TRUE +#endif + +/** + * @brief I/O Queues APIs. + * @details If enabled then the I/O queues APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__) +#define CH_USE_QUEUES TRUE +#endif + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MEMCORE) || defined(__DOXYGEN__) +#define CH_USE_MEMCORE TRUE +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or + * @p CH_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__) +#define CH_USE_HEAP TRUE +#endif + +/** + * @brief C-runtime allocator. + * @details If enabled the the heap allocator APIs just wrap the C-runtime + * @p malloc() and @p free() functions. + * + * @note The default is @p FALSE. + * @note Requires @p CH_USE_HEAP. + * @note The C-runtime may or may not require @p CH_USE_MEMCORE, see the + * appropriate documentation. + */ +#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__) +#define CH_USE_MALLOC_HEAP FALSE +#endif + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__) +#define CH_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_WAITEXIT. + * @note Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS. + */ +#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__) +#define CH_USE_DYNAMIC TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__) +#define CH_DBG_SYSTEM_STATE_CHECK FALSE +#endif + +/** + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_CHECKS FALSE +#endif + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_ASSERTS FALSE +#endif + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the context switch circular trace buffer is + * activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_TRACE FALSE +#endif + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_STACK_CHECK FALSE +#endif + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__) +#define CH_DBG_FILL_THREADS FALSE +#endif + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p Thread structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p TRUE. + * @note This debug option is defaulted to TRUE because it is required by + * some test cases into the test suite. + */ +#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) +#define CH_DBG_THREADS_PROFILING TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p Thread structure. + */ +#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__) +#define THREAD_EXT_FIELDS \ + /* Add threads custom fields here.*/ +#endif + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p chThdInit() API. + * + * @note It is invoked from within @p chThdInit() and implicitly from all + * the threads creation APIs. + */ +#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__) +#define THREAD_EXT_INIT_HOOK(tp) { \ + /* Add threads initialization code here.*/ \ +} +#endif + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + * + * @note It is inserted into lock zone. + * @note It is also invoked when the threads simply return in order to + * terminate. + */ +#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__) +#define THREAD_EXT_EXIT_HOOK(tp) { \ + /* Add threads finalization code here.*/ \ +} +#endif + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + */ +#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__) +#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) { \ + /* System halt code here.*/ \ +} +#endif + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__) +#define IDLE_LOOP_HOOK() { \ + /* Idle loop code here.*/ \ +} +#endif + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__) +#define SYSTEM_TICK_EVENT_HOOK() { \ + /* System tick event code here.*/ \ +} +#endif + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) +#define SYSTEM_HALT_HOOK() { \ + /* System halt code here.*/ \ +} +#endif + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#endif /* _CHCONF_H_ */ + +/** @} */ diff --git a/boards/base/Olimex-SAM7EX256-GE8/example/halconf.h b/boards/base/Olimex-SAM7EX256-GE8/example/halconf.h new file mode 100644 index 00000000..db88d41b --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/example/halconf.h @@ -0,0 +1,360 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + --- + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes ChibiOS/RT, without being obliged to provide + the source code for any proprietary components. See the file exception.txt + for full details of how and when the exception can be applied. +*/ + +/** + * @file templates/halconf.h + * @brief HAL configuration header. + * @details HAL configuration file, this file allows to enable or disable the + * various device drivers from your application. You may also use + * this file in order to override the device drivers default settings. + * + * @addtogroup HAL_CONF + * @{ + */ + +#ifndef _HALCONF_H_ +#define _HALCONF_H_ + +#include "mcuconf.h" + +/** + * @brief Enables the TM subsystem. + */ +#if !defined(HAL_USE_TM) || defined(__DOXYGEN__) +#define HAL_USE_TM FALSE +#endif + +/** + * @brief Enables the PAL subsystem. + */ +#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) +#define HAL_USE_PAL TRUE +#endif + +/** + * @brief Enables the ADC subsystem. + */ +#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) +#define HAL_USE_ADC TRUE +#endif + +/** + * @brief Enables the CAN subsystem. + */ +#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) +#define HAL_USE_CAN FALSE +#endif + +/** + * @brief Enables the EXT subsystem. + */ +#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__) +#define HAL_USE_EXT FALSE +#endif + +/** + * @brief Enables the GPT subsystem. + */ +#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) +#define HAL_USE_GPT FALSE +#endif + +/** + * @brief Enables the I2C subsystem. + */ +#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) +#define HAL_USE_I2C FALSE +#endif + +/** + * @brief Enables the ICU subsystem. + */ +#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) +#define HAL_USE_ICU FALSE +#endif + +/** + * @brief Enables the MAC subsystem. + */ +#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) +#define HAL_USE_MAC FALSE +#endif + +/** + * @brief Enables the MMC_SPI subsystem. + */ +#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) +#define HAL_USE_MMC_SPI FALSE +#endif + +/** + * @brief Enables the PWM subsystem. + */ +#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) +#define HAL_USE_PWM TRUE +#define PWM_USE_PWM1 FALSE +#define PWM_USE_PWM2 TRUE +#define PWM_USE_PWM3 FALSE +#define PWM_USE_PWM4 FALSE +#endif + +/** + * @brief Enables the RTC subsystem. + */ +#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) +#define HAL_USE_RTC FALSE +#endif + +/** + * @brief Enables the SDC subsystem. + */ +#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) +#define HAL_USE_SDC FALSE +#endif + +/** + * @brief Enables the SERIAL subsystem. + */ +#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL FALSE +#endif + +/** + * @brief Enables the SERIAL over USB subsystem. + */ +#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL_USB FALSE +#endif + +/** + * @brief Enables the SPI subsystem. + */ +#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) +#define HAL_USE_SPI TRUE +#endif + +/** + * @brief Enables the UART subsystem. + */ +#if !defined(HAL_USE_UART) || defined(__DOXYGEN__) +#define HAL_USE_UART FALSE +#endif + +/** + * @brief Enables the USB subsystem. + */ +#if !defined(HAL_USE_USB) || defined(__DOXYGEN__) +#define HAL_USE_USB FALSE +#endif + +/*===========================================================================*/ +/* ADC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) +#define ADC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define ADC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* CAN driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + */ +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif + +/*===========================================================================*/ +/* I2C driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the mutual exclusion APIs on the I2C bus. + */ +#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define I2C_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* MAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__) +#define MAC_USE_ZERO_COPY FALSE +#endif + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) +#define MAC_USE_EVENTS TRUE +#endif + +/*===========================================================================*/ +/* MMC_SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Block size for MMC transfers. + */ +#if !defined(MMC_SECTOR_SIZE) || defined(__DOXYGEN__) +#define MMC_SECTOR_SIZE 512 +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + * This option is recommended also if the SPI driver does not + * use a DMA channel and heavily loads the CPU. + */ +#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__) +#define MMC_NICE_WAITING TRUE +#endif + +/** + * @brief Number of positive insertion queries before generating the + * insertion event. + */ +#if !defined(MMC_POLLING_INTERVAL) || defined(__DOXYGEN__) +#define MMC_POLLING_INTERVAL 10 +#endif + +/** + * @brief Interval, in milliseconds, between insertion queries. + */ +#if !defined(MMC_POLLING_DELAY) || defined(__DOXYGEN__) +#define MMC_POLLING_DELAY 10 +#endif + +/** + * @brief Uses the SPI polled API for small data transfers. + * @details Polled transfers usually improve performance because it + * saves two context switches and interrupt servicing. Note + * that this option has no effect on large transfers which + * are always performed using DMAs/IRQs. + */ +#if !defined(MMC_USE_SPI_POLLING) || defined(__DOXYGEN__) +#define MMC_USE_SPI_POLLING TRUE +#endif + +/*===========================================================================*/ +/* SDC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intervals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + +/*===========================================================================*/ +/* SERIAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SERIAL_DEFAULT_BITRATE 38400 +#endif + +/** + * @brief Serial buffers size. + * @details Configuration parameter, you can change the depth of the queue + * buffers depending on the requirements of your application. + * @note The default is 64 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_BUFFERS_SIZE 16 +#endif + +/*===========================================================================*/ +/* SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) +#define SPI_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define SPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +#endif /* _HALCONF_H_ */ + +/** @} */ diff --git a/boards/base/Olimex-SAM7EX256-GE8/example/linker.ld b/boards/base/Olimex-SAM7EX256-GE8/example/linker.ld new file mode 100644 index 00000000..c36a07a3 --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/example/linker.ld @@ -0,0 +1,105 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + * AT91SAM7X256 memory setup. + */ +__und_stack_size__ = 0x0004; +__abt_stack_size__ = 0x0004; +__fiq_stack_size__ = 0x0010; +__irq_stack_size__ = 0x0080; +__svc_stack_size__ = 0x0004; +__sys_stack_size__ = 0x0400; +__stacks_total_size__ = __und_stack_size__ + __abt_stack_size__ + __fiq_stack_size__ + __irq_stack_size__ + __svc_stack_size__ + __sys_stack_size__; + +MEMORY +{ + flash : org = 0x100000, len = 256k + ram : org = 0x200020, len = 64k - 0x20 +} + +__ram_start__ = ORIGIN(ram); +__ram_size__ = LENGTH(ram); +__ram_end__ = __ram_start__ + __ram_size__; + +SECTIONS +{ + . = 0; + + .text : ALIGN(16) SUBALIGN(16) + { + _text = .; + KEEP(*(vectors)) + *(.text) + *(.text.*) + *(.rodata) + *(.rodata.*) + *(.glue_7t) + *(.glue_7) + *(.gcc*) + *(.ctors) + *(.dtors) + } > flash + + .ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} + + __exidx_start = .; + .ARM.exidx : {*(.ARM.exidx* .gnu.linkonce.armexidx.*)} > flash + __exidx_end = .; + + .eh_frame_hdr : {*(.eh_frame_hdr)} + + .eh_frame : ONLY_IF_RO {*(.eh_frame)} + + . = ALIGN(4); + _etext = .; + _textdata = _etext; + + .data : + { + _data = .; + *(.data) + . = ALIGN(4); + *(.data.*) + . = ALIGN(4); + *(.ramtext) + . = ALIGN(4); + _edata = .; + } > ram AT > flash + + .bss : + { + _bss_start = .; + *(.bss) + . = ALIGN(4); + *(.bss.*) + . = ALIGN(4); + *(COMMON) + . = ALIGN(4); + _bss_end = .; + } > ram +} + +PROVIDE(end = .); +_end = .; + +__heap_base__ = _end; +__heap_end__ = __ram_end__ - __stacks_total_size__; +__main_thread_stack_base__ = __ram_end__ - __stacks_total_size__; diff --git a/boards/base/Olimex-SAM7EX256-GE8/example/mcuconf.h b/boards/base/Olimex-SAM7EX256-GE8/example/mcuconf.h new file mode 100644 index 00000000..a9a0fea7 --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/example/mcuconf.h @@ -0,0 +1,71 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + --- + + A special exception to the GPL can be applied should you wish to distribute + a combined work that includes ChibiOS/RT, without being obliged to provide + the source code for any proprietary components. See the file exception.txt + for full details of how and when the exception can be applied. +*/ + +/* + * AT91SAM7 drivers configuration. + * The following settings override the default settings present in + * the various device driver implementation headers. + * Note that the settings for each driver only have effect if the driver + * is enabled in halconf.h. + */ + +/* + * ADC driver system settings. + */ + +/* + * CAN driver system settings. + */ + +/* + * MAC driver system settings. + */ +#define MAC_TRANSMIT_BUFFERS 2 +#define MAC_RECEIVE_BUFFERS 2 +#define MAC_BUFFERS_SIZE 1518 +#define EMAC_INTERRUPT_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 3) + +/* + * PWM driver system settings. + */ + +/* + * SERIAL driver system settings. + */ +#define USE_SAM7_USART0 TRUE +#define USE_SAM7_USART1 TRUE +#define SAM7_USART0_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2) +#define SAM7_USART1_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 2) + +/* + * SPI driver system settings. + */ +#define USE_AT91SAM7_SPI FALSE +#define AT91SAM7_SPI_USE_SPI0 TRUE +#define AT91SAM7_SPI_USE_SPI1 FALSE +#define AT91SAM7_SPI0_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 1) +#define AT91SAM7_SPI1_PRIORITY (AT91C_AIC_PRIOR_HIGHEST - 1) diff --git a/boards/base/Olimex-SAM7EX256-GE8/example/readme.txt b/boards/base/Olimex-SAM7EX256-GE8/example/readme.txt new file mode 100644 index 00000000..a357dc52 --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/example/readme.txt @@ -0,0 +1,3 @@ +Copy these files into your own project directory and alter them to suite. + +In particular look at the MYFILES definition and the MYCSRC definition. \ No newline at end of file diff --git a/drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h b/boards/base/Olimex-SAM7EX256-GE8/gadc_lld_board.h similarity index 73% rename from drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h rename to boards/base/Olimex-SAM7EX256-GE8/gadc_lld_board.h index 8f047015..fef861e5 100644 --- a/drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h +++ b/boards/base/Olimex-SAM7EX256-GE8/gadc_lld_board.h @@ -6,15 +6,12 @@ */ /** - * @file drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h + * @file boards/base/Olimex-SAM7EX256-GE8/gadc_lld_board.h * @brief GADC Driver config file. - * - * @addtogroup GADC - * @{ */ -#ifndef _GADC_LLD_BOARD_OLIMEXSAM7EX256_H -#define _GADC_LLD_BOARD_OLIMEXSAM7EX256_H +#ifndef _GADC_LLD_BOARD_H +#define _GADC_LLD_BOARD_H #if GFX_USE_GADC @@ -28,6 +25,5 @@ #endif /* GFX_USE_GADC */ -#endif /* _GADC_LLD_BOARD_OLIMEXSAM7EX256_H */ -/** @} */ +#endif /* _GADC_LLD_BOARD_H */ diff --git a/boards/base/Olimex-SAM7EX256-GE8/gaudin_lld_board.h b/boards/base/Olimex-SAM7EX256-GE8/gaudin_lld_board.h new file mode 100644 index 00000000..632f0659 --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/gaudin_lld_board.h @@ -0,0 +1,33 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file boards/base/Olimex-SAM7EX256-GE8/gaudin_lld_board.h + * @brief GAUDIN Driver board config file for the Olimex SAM7EX256 board + */ + +#ifndef _GAUDIN_LLD_BOARD_H +#define _GAUDIN_LLD_BOARD_H + +/*===========================================================================*/ +/* Audio inputs on this board */ +/*===========================================================================*/ + +#define GAUDIN_NUM_CHANNELS 1 + +/** + * The list of audio channels and their uses + */ +#define GAUDIN_MICROPHONE 0 + +#ifdef GAUDIN_LLD_IMPLEMENTATION + static uint32_t gaudin_lld_physdevs[GAUDIN_NUM_CHANNELS] = { + GADC_PHYSDEV_MICROPHONE, + }; +#endif + +#endif /* _GAUDIN_LLD_BOARD_H */ diff --git a/boards/base/Olimex-SAM7EX256-GE8/ginput_lld_dial_board.h b/boards/base/Olimex-SAM7EX256-GE8/ginput_lld_dial_board.h new file mode 100644 index 00000000..c0d3ab3f --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/ginput_lld_dial_board.h @@ -0,0 +1,30 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file boards/base/Olimex-SAM7EX256-GE8/ginput_lld_dial_board.h + * @brief GINPUT Dial Driver config file. + */ + +#ifndef _GINPUT_LLD_DIAL_BOARD_H +#define _GINPUT_LLD_DIAL_BOARD_H + +#if GFX_USE_GINPUT && GINPUT_NEED_DIAL + +/*===========================================================================*/ +/* Analogue devices on this board */ +/*===========================================================================*/ + +#define GINPUT_DIAL_NUM_PORTS 1 +#define GINPUT_DIAL_DEVICE0 GADC_PHYSDEV_DIAL +#define GINPUT_DIAL_POLL_PERIOD 200 +#define GINPUT_DIAL_CYCLE_POLL FALSE + +#endif /* GFX_USE_GINPUT && GINPUT_NEED_DIAL */ + +#endif /* _GINPUT_LLD_DIAL_BOARD_H */ + diff --git a/drivers/ginput/toggle/Pal/ginput_lld_toggle_board_olimexsam7ex256.h b/boards/base/Olimex-SAM7EX256-GE8/ginput_lld_toggle_board.h similarity index 91% rename from drivers/ginput/toggle/Pal/ginput_lld_toggle_board_olimexsam7ex256.h rename to boards/base/Olimex-SAM7EX256-GE8/ginput_lld_toggle_board.h index 5861b6f5..39e7837a 100644 --- a/drivers/ginput/toggle/Pal/ginput_lld_toggle_board_olimexsam7ex256.h +++ b/boards/base/Olimex-SAM7EX256-GE8/ginput_lld_toggle_board.h @@ -6,12 +6,8 @@ */ /** - * @file drivers/ginput/toggle/Pal/ginput_lld_toggle_board_olimexsam7ex256.h + * @file boards/base/Olimex-SAM7EX256-GE8/ginput_lld_toggle_board.h * @brief GINPUT Toggle low level driver source for the ChibiOS PAL hardware on the Olimex SAM7EX256 board. - * - * @defgroup Toggle Toggle - * @ingroup GINPUT - * @{ */ #ifndef _GDISP_LLD_TOGGLE_BOARD_H @@ -41,4 +37,4 @@ } #endif /* _GDISP_LLD_TOGGLE_BOARD_H */ -/** @} */ + diff --git a/drivers/gadc/AT91SAM7/gadc_lld_board_template.h b/drivers/gadc/AT91SAM7/gadc_lld_board_template.h new file mode 100644 index 00000000..045c0ed7 --- /dev/null +++ b/drivers/gadc/AT91SAM7/gadc_lld_board_template.h @@ -0,0 +1,37 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/gadc/AT91SAM7/gadc_lld_board_template.h + * @brief GADC Driver config file. + * + * @addtogroup GADC + * @{ + */ + +#ifndef _GADC_LLD_BOARD_H +#define _GADC_LLD_BOARD_H + +#if GFX_USE_GADC + +/*===========================================================================*/ +/* Analogue devices on this board */ +/*===========================================================================*/ + +/** + * @brief The physical devices that are accessible via GADC and their physical device numbers. + * @note The numbers below are examples for this template file + */ +#define GADC_PHYSDEV_MICROPHONE 0x00000080 +#define GADC_PHYSDEV_DIAL 0x00000040 +#define GADC_PHYSDEV_TEMPERATURE 0x00000020 + +#endif /* GFX_USE_GADC */ + +#endif /* _GADC_LLD_BOARD_H */ +/** @} */ + diff --git a/drivers/gadc/AT91SAM7/gadc_lld_config.h b/drivers/gadc/AT91SAM7/gadc_lld_config.h index 8c6e1cc0..ba6cbda2 100644 --- a/drivers/gadc/AT91SAM7/gadc_lld_config.h +++ b/drivers/gadc/AT91SAM7/gadc_lld_config.h @@ -52,16 +52,8 @@ */ #define GADC_SAMPLE_FORMAT ARRAY_DATA_10BITUNSIGNED -/* Pull in board specific defines */ -#if defined(GADC_USE_CUSTOM_BOARD) && GADC_USE_CUSTOM_BOARD - /* Include the user supplied board definitions */ - #include "gadc_lld_board.h" -#elif defined(BOARD_OLIMEX_SAM7_EX256) - #include "gadc_lld_board_olimexsam7ex256.h" -#else - /* Include the user supplied board definitions */ - #include "gadc_lld_board.h" -#endif +/* Include the user supplied board definitions */ +#include "gadc_lld_board.h" #endif /* GFX_USE_GADC */ diff --git a/drivers/gaudin/gadc/gaudin_lld_board_olimexsam7ex256.h b/drivers/gaudin/gadc/gaudin_lld_board_template.h similarity index 71% rename from drivers/gaudin/gadc/gaudin_lld_board_olimexsam7ex256.h rename to drivers/gaudin/gadc/gaudin_lld_board_template.h index a98f392c..89cc0c12 100644 --- a/drivers/gaudin/gadc/gaudin_lld_board_olimexsam7ex256.h +++ b/drivers/gaudin/gadc/gaudin_lld_board_template.h @@ -6,15 +6,15 @@ */ /** - * @file drivers/gaudin/gadc/gaudin_lld_board_olimexsam7ex256.h - * @brief GAUDIN Driver board config file for the Olimex SAM7EX256 board + * @file drivers/gaudin/gadc/gaudin_lld_board_template.h + * @brief GAUDIN Driver board config board file * * @addtogroup GAUDIN * @{ */ -#ifndef _GAUDIN_LLD_BOARD_OLIMEXSAM7EX256_H -#define _GAUDIN_LLD_BOARD_OLIMEXSAM7EX256_H +#ifndef _GAUDIN_LLD_BOARD_H +#define _GAUDIN_LLD_BOARD_H /*===========================================================================*/ /* Audio inputs on this board */ @@ -22,18 +22,21 @@ /** * @brief The number of audio channels supported by this driver + * @note This is an example */ #define GAUDIN_NUM_CHANNELS 1 /** * @brief The list of audio channels and their uses + * @note This is an example * @{ */ #define GAUDIN_MICROPHONE 0 /** @} */ /** - * @brief The following defines are for the low level driver use only + * @brief The audio channel to GADC physical device assignment + * @note This is an example * @{ */ #ifdef GAUDIN_LLD_IMPLEMENTATION @@ -43,5 +46,5 @@ #endif /** @} */ -#endif /* _GAUDIN_LLD_BOARD_OLIMEXSAM7EX256_H */ +#endif /* _GAUDIN_LLD_BOARD_H */ /** @} */ diff --git a/drivers/gaudin/gadc/gaudin_lld_config.h b/drivers/gaudin/gadc/gaudin_lld_config.h index f10e0575..a9fd02ae 100644 --- a/drivers/gaudin/gadc/gaudin_lld_config.h +++ b/drivers/gaudin/gadc/gaudin_lld_config.h @@ -50,15 +50,8 @@ typedef adcsample_t audin_sample_t; * For the GAUDIN driver that uses GADC - all the remaining config definitions are specific * to the board. */ -#if defined(GADC_USE_CUSTOM_BOARD) && GADC_USE_CUSTOM_BOARD - /* Include the user supplied board definitions */ - #include "gaudin_lld_board.h" -#elif defined(BOARD_OLIMEX_SAM7_EX256) - #include "gaudin_lld_board_olimexsam7ex256.h" -#else - /* Include the user supplied board definitions */ - #include "gaudin_lld_board.h" -#endif +/* Include the user supplied board definitions */ +#include "gaudin_lld_board.h" #endif /* GFX_USE_GAUDIN */ diff --git a/drivers/ginput/dial/GADC/ginput_lld_dial_board_olimexsam7ex256.h b/drivers/ginput/dial/GADC/ginput_lld_dial_board_template.h similarity index 77% rename from drivers/ginput/dial/GADC/ginput_lld_dial_board_olimexsam7ex256.h rename to drivers/ginput/dial/GADC/ginput_lld_dial_board_template.h index 09ca3dc0..202b5386 100644 --- a/drivers/ginput/dial/GADC/ginput_lld_dial_board_olimexsam7ex256.h +++ b/drivers/ginput/dial/GADC/ginput_lld_dial_board_template.h @@ -6,7 +6,7 @@ */ /** - * @file drivers/ginput/dial/GADC/ginput_lld_dial_board_olimexsam7ex256.h + * @file drivers/ginput/dial/GADC/ginput_lld_dial_board_template.h * @brief GINPUT Dial Driver config file. * * @defgroup Dial Dial @@ -14,8 +14,8 @@ * @{ */ -#ifndef _GINPUT_LLD_DIAL_BOARD_OLIMEXSAM7EX256_H -#define _GINPUT_LLD_DIAL_BOARD_OLIMEXSAM7EX256_H +#ifndef _GINPUT_LLD_DIAL_BOARD_H +#define _GINPUT_LLD_DIAL_BOARD_H #if GFX_USE_GINPUT && GINPUT_NEED_DIAL @@ -23,6 +23,7 @@ /* Analogue devices on this board */ /*===========================================================================*/ +/* Example values */ #define GINPUT_DIAL_NUM_PORTS 1 #define GINPUT_DIAL_DEVICE0 GADC_PHYSDEV_DIAL #define GINPUT_DIAL_POLL_PERIOD 200 @@ -30,6 +31,6 @@ #endif /* GFX_USE_GINPUT && GINPUT_NEED_DIAL */ -#endif /* _GINPUT_LLD_DIAL_BOARD_OLIMEXSAM7EX256_H */ +#endif /* _GINPUT_LLD_DIAL_BOARD_H */ /** @} */ diff --git a/drivers/ginput/dial/GADC/ginput_lld_dial_config.h b/drivers/ginput/dial/GADC/ginput_lld_dial_config.h index 3dc7bfca..3e54b4ca 100644 --- a/drivers/ginput/dial/GADC/ginput_lld_dial_config.h +++ b/drivers/ginput/dial/GADC/ginput_lld_dial_config.h @@ -21,15 +21,8 @@ #define GINPUT_DIAL_MAX_VALUE ((1< Date: Mon, 28 Oct 2013 19:18:24 +1000 Subject: [PATCH 137/160] Add readme's to the board directories --- boards/base/Olimex-SAM7EX256-GE12/board.mk | 6 ------ boards/base/Olimex-SAM7EX256-GE12/readme.txt | 15 ++++++++++++--- boards/base/Olimex-SAM7EX256-GE8/board.mk | 6 ------ boards/base/Olimex-SAM7EX256-GE8/readme.txt | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 15 deletions(-) create mode 100644 boards/base/Olimex-SAM7EX256-GE8/readme.txt diff --git a/boards/base/Olimex-SAM7EX256-GE12/board.mk b/boards/base/Olimex-SAM7EX256-GE12/board.mk index 5230b6b4..662178a6 100644 --- a/boards/base/Olimex-SAM7EX256-GE12/board.mk +++ b/boards/base/Olimex-SAM7EX256-GE12/board.mk @@ -1,14 +1,8 @@ GFXINC += $(GFXLIB)/boards/base/Olimex-SAM7EX256-GE12 $(GFXLIB)/boards/base/Olimex-SAM7EX256-GE8 GFXSRC += GFXDEFS += -DGFX_USE_OS_CHIBIOS=TRUE - -#This board has a Nokia6610GE12 display include $(GFXLIB)/drivers/gdisp/Nokia6610GE12/gdisp_lld.mk -#This board supports GADC via the AT91SAM7 driver include $(GFXLIB)/drivers/gadc/AT91SAM7/gadc_lld.mk -#This board supports GINPUT dials via the GADC driver include $(GFXLIB)/drivers/ginput/dial/GADC/ginput_lld.mk -#This board supports GINPUT toggles via the Pal driver include $(GFXLIB)/drivers/ginput/toggle/Pal/ginput_lld.mk -#This board support GAUDIN via the GADC driver include $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.mk diff --git a/boards/base/Olimex-SAM7EX256-GE12/readme.txt b/boards/base/Olimex-SAM7EX256-GE12/readme.txt index b84e5575..ebf1497a 100644 --- a/boards/base/Olimex-SAM7EX256-GE12/readme.txt +++ b/boards/base/Olimex-SAM7EX256-GE12/readme.txt @@ -1,6 +1,15 @@ -This is the same as the Olimex-SAM7EX256-GE8 board except that it uses the GE12 display controller -instead of the GE8 display controller. +This directory contains the interface for the Olimex SAM7EX256 board +running under ChibiOS. + +On this board uGFX currently supports: + - GDISP via the Nokia6610GE12 display + - GADC via the AT91SAM7 driver + - GINPUT-dials via the GADC driver + - GINPUT-toggles via the Pal driver + - GAUDIN via the GADC driver + +Note there are two variants of this board - one with the GE8 display + and one with the GE12 display. This one is for the GE12 display. See the Olimex-SAM7EX256-GE8 board file directory for example Makefiles etc. Don't forget to change the example Makefile to point the GFX board file to the GE12 instead of the GE8. - diff --git a/boards/base/Olimex-SAM7EX256-GE8/board.mk b/boards/base/Olimex-SAM7EX256-GE8/board.mk index c11a0bbb..6abd9a33 100644 --- a/boards/base/Olimex-SAM7EX256-GE8/board.mk +++ b/boards/base/Olimex-SAM7EX256-GE8/board.mk @@ -1,14 +1,8 @@ GFXINC += $(GFXLIB)/boards/base/Olimex-SAM7EX256-GE8 GFXSRC += GFXDEFS += -DGFX_USE_OS_CHIBIOS=TRUE - -#This board has a Nokia6610GE8 display include $(GFXLIB)/drivers/gdisp/Nokia6610GE8/gdisp_lld.mk -#This board supports GADC via the AT91SAM7 driver include $(GFXLIB)/drivers/gadc/AT91SAM7/gadc_lld.mk -#This board supports GINPUT dials via the GADC driver include $(GFXLIB)/drivers/ginput/dial/GADC/ginput_lld.mk -#This board supports GINPUT toggles via the Pal driver include $(GFXLIB)/drivers/ginput/toggle/Pal/ginput_lld.mk -#This board support GAUDIN via the GADC driver include $(GFXLIB)/drivers/gaudin/gadc/gaudin_lld.mk diff --git a/boards/base/Olimex-SAM7EX256-GE8/readme.txt b/boards/base/Olimex-SAM7EX256-GE8/readme.txt new file mode 100644 index 00000000..01b3f8b4 --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/readme.txt @@ -0,0 +1,14 @@ +This directory contains the interface for the Olimex SAM7EX256 board +running under ChibiOS. + +On this board uGFX currently supports: + - GDISP via the Nokia6610GE8 display + - GADC via the AT91SAM7 driver + - GINPUT-dials via the GADC driver + - GINPUT-toggles via the Pal driver + - GAUDIN via the GADC driver + +Note there are two variants of this board - one with the GE8 display + and one with the GE12 display. This one is for the GE8 display. + +There is an example Makefile and project in the examples directory. From dc2d5be60625dc03f0982d61a55dd3ccf844fff5 Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 28 Oct 2013 19:49:39 +1000 Subject: [PATCH 138/160] uGFX board definition for the Mikromedia STM32 M4 board. Includes the required ChibiOS board files and an example Makefile. --- .../ChibiOS_Board/board.c | 92 ++ .../ChibiOS_Board/board.h | 1299 ++++++++++++++++ .../ChibiOS_Board/board.mk | 7 + .../ChibiOS_Board/board_orig.h | 1303 +++++++++++++++++ .../ChibiOS_Board/cfg/board.chcfg | 1186 +++++++++++++++ .../ChibiOS_Board/flash_memory.c | 125 ++ .../ChibiOS_Board/flash_memory.h | 6 + .../base/Mikromedia-STM32-M4-ILI9341/board.mk | 5 + .../board_ILI9341.h | 132 ++ .../example/Makefile | 231 +++ .../example/chconf.h | 531 +++++++ .../example/halconf.h | 312 ++++ .../example/mcuconf.h | 289 ++++ .../ginput_lld_mouse_board.h | 152 ++ .../ginput_lld_mouse_config.h | 32 + .../Mikromedia-STM32-M4-ILI9341/readme.txt | 16 + 16 files changed, 5718 insertions(+) create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.c create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.h create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.mk create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board_orig.h create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/cfg/board.chcfg create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.c create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.h create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/board.mk create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/board_ILI9341.h create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/example/Makefile create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/example/chconf.h create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/example/halconf.h create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/example/mcuconf.h create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_board.h create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_config.h create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/readme.txt diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.c b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.c new file mode 100644 index 00000000..7dc6f285 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.c @@ -0,0 +1,92 @@ +#include "ch.h" +#include "hal.h" + +#if HAL_USE_PAL || defined(__DOXYGEN__) +/** + * @brief PAL setup. + * @details Digital I/O ports static configuration as defined in @p board.h. + * This variable is used by the HAL when initializing the PAL driver. + */ +const PALConfig pal_default_config = +{ + {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, + VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH}, + {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR, + VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH}, + {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR, + VAL_GPIOC_ODR, VAL_GPIOC_AFRL, VAL_GPIOC_AFRH}, + {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR, + VAL_GPIOD_ODR, VAL_GPIOD_AFRL, VAL_GPIOD_AFRH}, + {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR, + VAL_GPIOE_ODR, VAL_GPIOE_AFRL, VAL_GPIOE_AFRH}, + {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR, + VAL_GPIOF_ODR, VAL_GPIOF_AFRL, VAL_GPIOF_AFRH}, + {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR, + VAL_GPIOG_ODR, VAL_GPIOG_AFRL, VAL_GPIOG_AFRH}, + {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR, + VAL_GPIOH_ODR, VAL_GPIOH_AFRL, VAL_GPIOH_AFRH}, + {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR, + VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH} +}; +#endif + +/** + * @brief Early initialization code. + * @details This initialization must be performed just after stack setup + * and before any other initialization. + */ +void __early_init(void) { + + stm32_clock_init(); +} + +#if HAL_USE_SDC || defined(__DOXYGEN__) +/** + * @brief SDC card detection. + */ +bool_t sdc_lld_is_card_inserted(SDCDriver *sdcp) { + + (void)sdcp; + /* TODO: Fill the implementation.*/ + return TRUE; +} + +/** + * @brief SDC card write protection detection. + */ +bool_t sdc_lld_is_write_protected(SDCDriver *sdcp) { + + (void)sdcp; + /* TODO: Fill the implementation.*/ + return FALSE; +} +#endif /* HAL_USE_SDC */ + +#if HAL_USE_MMC_SPI || defined(__DOXYGEN__) +/** + * @brief MMC_SPI card detection. + */ +bool_t mmc_lld_is_card_inserted(MMCDriver *mmcp) { + + (void)mmcp; + return !palReadPad(GPIOD, GPIOD_SD_CD); +} + +/** + * @brief MMC_SPI card write protection detection. + */ +bool_t mmc_lld_is_write_protected(MMCDriver *mmcp) { + + (void)mmcp; + /* Board has no write protection detection */ + return FALSE; +} +#endif + +/** + * @brief Board-specific initialization code. + * @todo Add your board-specific code, if any. + */ +void boardInit(void) { + +} diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.h b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.h new file mode 100644 index 00000000..490c0307 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.h @@ -0,0 +1,1299 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +/* + * Setup for mikromedia STM32-M4 board. + */ + +/* + * Board identifier. + */ +#define BOARD_MIKROE_MIKROMEDIA_M4 +#define BOARD_NAME "mikromedia STM32-M4" + + +/* + * Board oscillators-related settings. + */ +#if !defined(STM32_LSECLK) +#define STM32_LSECLK 32768 +#endif + +#if !defined(STM32_HSECLK) +#define STM32_HSECLK 16000000 +#endif + +/* + * Board voltages. + * Required for performance limits calculation. + */ +#define STM32_VDD 330 + +/* + * MCU type as defined in the ST header file stm32f4xx.h. + */ +#define STM32F4XX + +/* + * IO pins assignments. + */ +#define GPIOA_VSENSE 0 +#define GPIOA_PIN1 1 +#define GPIOA_PIN2 2 +#define GPIOA_PIN3 3 +#define GPIOA_PIN4 4 +#define GPIOA_PIN5 5 +#define GPIOA_PIN6 6 +#define GPIOA_PIN7 7 +#define GPIOA_PIN8 8 +#define GPIOA_VBUS_FS 9 +#define GPIOA_PIN10 10 +#define GPIOA_OTG_FS_DM 11 +#define GPIOA_OTG_FS_DP 12 +#define GPIOA_TMS 13 +#define GPIOA_TCK 14 +#define GPIOA_TDI 15 + +#define GPIOB_LCD_YD 0 +#define GPIOB_LCD_XL 1 +#define GPIOB_PIN2 2 +#define GPIOB_TDO 3 +#define GPIOB_TRST 4 +#define GPIOB_PIN5 5 +#define GPIOB_SCL1 6 +#define GPIOB_SDA1 7 +#define GPIOB_DRIVEA 8 +#define GPIOB_DRIVEB 9 +#define GPIOB_SCL2 10 +#define GPIOB_SDA2 11 +#define GPIOB_PIN12 12 +#define GPIOB_SCK2 13 +#define GPIOB_MISO2 14 +#define GPIOB_MOSI2 15 + +#define GPIOC_PIN0 0 +#define GPIOC_PIN1 1 +#define GPIOC_PIN2 2 +#define GPIOC_PIN3 3 +#define GPIOC_PIN4 4 +#define GPIOC_PIN5 5 +#define GPIOC_MP3_DREQ 6 +#define GPIOC_MP3_RST 7 +#define GPIOC_MP3_CS 8 +#define GPIOC_MP3_DCS 9 +#define GPIOC_SCK3 10 +#define GPIOC_MISO3 11 +#define GPIOC_MOSI3 12 +#define GPIOC_STAT 13 +#define GPIOC_PIN14 14 +#define GPIOC_PIN15 15 + +#define GPIOD_PIN0 0 +#define GPIOD_PIN1 1 +#define GPIOD_PIN2 2 +#define GPIOD_SD_CS 3 +#define GPIOD_PIN4 4 +#define GPIOD_TX2 5 +#define GPIOD_RX2 6 +#define GPIOD_FLASH_CS 7 +#define GPIOD_PIN8 8 +#define GPIOD_PIN9 9 +#define GPIOD_PIN10 10 +#define GPIOD_PIN11 11 +#define GPIOD_PIN12 12 +#define GPIOD_PIN13 13 +#define GPIOD_PIN14 14 +#define GPIOD_SD_CD 15 + +#define GPIOE_TD0 0 +#define GPIOE_TD1 1 +#define GPIOE_TD2 2 +#define GPIOE_TD3 3 +#define GPIOE_TD4 4 +#define GPIOE_TD5 5 +#define GPIOE_TD6 6 +#define GPIOE_TD7 7 +#define GPIOE_LCD_RST 8 +#define GPIOE_LCD_BLED 9 +#define GPIOE_PMRD 10 +#define GPIOE_PMWR 11 +#define GPIOE_LCD_RS 12 +#define GPIOE_PIN13 13 +#define GPIOE_PIN14 14 +#define GPIOE_LCD_CS 15 + +#define GPIOF_PIN0 0 +#define GPIOF_PIN1 1 +#define GPIOF_PIN2 2 +#define GPIOF_PIN3 3 +#define GPIOF_PIN4 4 +#define GPIOF_PIN5 5 +#define GPIOF_PIN6 6 +#define GPIOF_PIN7 7 +#define GPIOF_PIN8 8 +#define GPIOF_PIN9 9 +#define GPIOF_PIN10 10 +#define GPIOF_PIN11 11 +#define GPIOF_PIN12 12 +#define GPIOF_PIN13 13 +#define GPIOF_PIN14 14 +#define GPIOF_PIN15 15 + +#define GPIOG_PIN0 0 +#define GPIOG_PIN1 1 +#define GPIOG_PIN2 2 +#define GPIOG_PIN3 3 +#define GPIOG_PIN4 4 +#define GPIOG_PIN5 5 +#define GPIOG_PIN6 6 +#define GPIOG_PIN7 7 +#define GPIOG_PIN8 8 +#define GPIOG_PIN9 9 +#define GPIOG_PIN10 10 +#define GPIOG_PIN11 11 +#define GPIOG_PIN12 12 +#define GPIOG_PIN13 13 +#define GPIOG_PIN14 14 +#define GPIOG_PIN15 15 + +#define GPIOH_OSC_IN 0 +#define GPIOH_OSC_OUT 1 +#define GPIOH_PIN2 2 +#define GPIOH_PIN3 3 +#define GPIOH_PIN4 4 +#define GPIOH_PIN5 5 +#define GPIOH_PIN6 6 +#define GPIOH_PIN7 7 +#define GPIOH_PIN8 8 +#define GPIOH_PIN9 9 +#define GPIOH_PIN10 10 +#define GPIOH_PIN11 11 +#define GPIOH_PIN12 12 +#define GPIOH_PIN13 13 +#define GPIOH_PIN14 14 +#define GPIOH_PIN15 15 + +#define GPIOI_PIN0 0 +#define GPIOI_PIN1 1 +#define GPIOI_PIN2 2 +#define GPIOI_PIN3 3 +#define GPIOI_PIN4 4 +#define GPIOI_PIN5 5 +#define GPIOI_PIN6 6 +#define GPIOI_PIN7 7 +#define GPIOI_PIN8 8 +#define GPIOI_PIN9 9 +#define GPIOI_PIN10 10 +#define GPIOI_PIN11 11 +#define GPIOI_PIN12 12 +#define GPIOI_PIN13 13 +#define GPIOI_PIN14 14 +#define GPIOI_PIN15 15 + +/* + * I/O ports initial setup, this configuration is established soon after reset + * in the initialization code. + * Please refer to the STM32 Reference Manual for details. + */ +#define PIN_MODE_INPUT(n) (0U << ((n) * 2)) +#define PIN_MODE_OUTPUT(n) (1U << ((n) * 2)) +#define PIN_MODE_ALTERNATE(n) (2U << ((n) * 2)) +#define PIN_MODE_ANALOG(n) (3U << ((n) * 2)) +#define PIN_ODR_LOW(n) (0U << (n)) +#define PIN_ODR_HIGH(n) (1U << (n)) +#define PIN_OTYPE_PUSHPULL(n) (0U << (n)) +#define PIN_OTYPE_OPENDRAIN(n) (1U << (n)) +#define PIN_OSPEED_2M(n) (0U << ((n) * 2)) +#define PIN_OSPEED_25M(n) (1U << ((n) * 2)) +#define PIN_OSPEED_50M(n) (2U << ((n) * 2)) +#define PIN_OSPEED_100M(n) (3U << ((n) * 2)) +#define PIN_PUPDR_FLOATING(n) (0U << ((n) * 2)) +#define PIN_PUPDR_PULLUP(n) (1U << ((n) * 2)) +#define PIN_PUPDR_PULLDOWN(n) (2U << ((n) * 2)) +#define PIN_AFIO_AF(n, v) ((v##U) << ((n % 8) * 4)) + +/* + * GPIOA setup: + * + * PA0 - VSENSE (analog). + * PA1 - PIN1 (input pullup). + * PA2 - PIN2 (input pullup). + * PA3 - PIN3 (input pullup). + * PA4 - PIN4 (alternate 6). + * PA5 - PIN5 (alternate 5). + * PA6 - PIN6 (alternate 5). + * PA7 - PIN7 (alternate 5). + * PA8 - PIN8 (input pullup). + * PA9 - VBUS_FS (input floating). + * PA10 - PIN10 (input floating). + * PA11 - OTG_FS_DM (alternate 10). + * PA12 - OTG_FS_DP (alternate 10). + * PA13 - TMS (alternate 0). + * PA14 - TCK (alternate 0). + * PA15 - TDI (input pullup). + */ +#define VAL_GPIOA_MODER (PIN_MODE_ANALOG(GPIOA_VSENSE) | \ + PIN_MODE_INPUT(GPIOA_PIN1) | \ + PIN_MODE_INPUT(GPIOA_PIN2) | \ + PIN_MODE_INPUT(GPIOA_PIN3) | \ + PIN_MODE_ALTERNATE(GPIOA_PIN4) | \ + PIN_MODE_ALTERNATE(GPIOA_PIN5) | \ + PIN_MODE_ALTERNATE(GPIOA_PIN6) | \ + PIN_MODE_ALTERNATE(GPIOA_PIN7) | \ + PIN_MODE_INPUT(GPIOA_PIN8) | \ + PIN_MODE_INPUT(GPIOA_VBUS_FS) | \ + PIN_MODE_INPUT(GPIOA_PIN10) | \ + PIN_MODE_ALTERNATE(GPIOA_OTG_FS_DM) | \ + PIN_MODE_ALTERNATE(GPIOA_OTG_FS_DP) | \ + PIN_MODE_ALTERNATE(GPIOA_TMS) | \ + PIN_MODE_ALTERNATE(GPIOA_TCK) | \ + PIN_MODE_INPUT(GPIOA_TDI)) +#define VAL_GPIOA_OTYPER (PIN_OTYPE_PUSHPULL(GPIOA_VSENSE) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOA_VBUS_FS) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOA_OTG_FS_DM) | \ + PIN_OTYPE_PUSHPULL(GPIOA_OTG_FS_DP) | \ + PIN_OTYPE_PUSHPULL(GPIOA_TMS) | \ + PIN_OTYPE_PUSHPULL(GPIOA_TCK) | \ + PIN_OTYPE_PUSHPULL(GPIOA_TDI)) +#define VAL_GPIOA_OSPEEDR (PIN_OSPEED_100M(GPIOA_VSENSE) | \ + PIN_OSPEED_100M(GPIOA_PIN1) | \ + PIN_OSPEED_100M(GPIOA_PIN2) | \ + PIN_OSPEED_100M(GPIOA_PIN3) | \ + PIN_OSPEED_100M(GPIOA_PIN4) | \ + PIN_OSPEED_50M(GPIOA_PIN5) | \ + PIN_OSPEED_50M(GPIOA_PIN6) | \ + PIN_OSPEED_50M(GPIOA_PIN7) | \ + PIN_OSPEED_100M(GPIOA_PIN8) | \ + PIN_OSPEED_100M(GPIOA_VBUS_FS) | \ + PIN_OSPEED_100M(GPIOA_PIN10) | \ + PIN_OSPEED_100M(GPIOA_OTG_FS_DM) | \ + PIN_OSPEED_100M(GPIOA_OTG_FS_DP) | \ + PIN_OSPEED_100M(GPIOA_TMS) | \ + PIN_OSPEED_100M(GPIOA_TCK) | \ + PIN_OSPEED_100M(GPIOA_TDI)) +#define VAL_GPIOA_PUPDR (PIN_PUPDR_FLOATING(GPIOA_VSENSE) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOA_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOA_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOA_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOA_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOA_VBUS_FS) | \ + PIN_PUPDR_FLOATING(GPIOA_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOA_OTG_FS_DM) | \ + PIN_PUPDR_FLOATING(GPIOA_OTG_FS_DP) | \ + PIN_PUPDR_FLOATING(GPIOA_TMS) | \ + PIN_PUPDR_FLOATING(GPIOA_TCK) | \ + PIN_PUPDR_PULLUP(GPIOA_TDI)) +#define VAL_GPIOA_ODR (PIN_ODR_HIGH(GPIOA_VSENSE) | \ + PIN_ODR_HIGH(GPIOA_PIN1) | \ + PIN_ODR_HIGH(GPIOA_PIN2) | \ + PIN_ODR_HIGH(GPIOA_PIN3) | \ + PIN_ODR_HIGH(GPIOA_PIN4) | \ + PIN_ODR_HIGH(GPIOA_PIN5) | \ + PIN_ODR_HIGH(GPIOA_PIN6) | \ + PIN_ODR_HIGH(GPIOA_PIN7) | \ + PIN_ODR_HIGH(GPIOA_PIN8) | \ + PIN_ODR_HIGH(GPIOA_VBUS_FS) | \ + PIN_ODR_HIGH(GPIOA_PIN10) | \ + PIN_ODR_HIGH(GPIOA_OTG_FS_DM) | \ + PIN_ODR_HIGH(GPIOA_OTG_FS_DP) | \ + PIN_ODR_HIGH(GPIOA_TMS) | \ + PIN_ODR_HIGH(GPIOA_TCK) | \ + PIN_ODR_HIGH(GPIOA_TDI)) +#define VAL_GPIOA_AFRL (PIN_AFIO_AF(GPIOA_VSENSE, 0) | \ + PIN_AFIO_AF(GPIOA_PIN1, 0) | \ + PIN_AFIO_AF(GPIOA_PIN2, 0) | \ + PIN_AFIO_AF(GPIOA_PIN3, 0) | \ + PIN_AFIO_AF(GPIOA_PIN4, 6) | \ + PIN_AFIO_AF(GPIOA_PIN5, 5) | \ + PIN_AFIO_AF(GPIOA_PIN6, 5) | \ + PIN_AFIO_AF(GPIOA_PIN7, 5)) +#define VAL_GPIOA_AFRH (PIN_AFIO_AF(GPIOA_PIN8, 0) | \ + PIN_AFIO_AF(GPIOA_VBUS_FS, 0) | \ + PIN_AFIO_AF(GPIOA_PIN10, 0) | \ + PIN_AFIO_AF(GPIOA_OTG_FS_DM, 10) | \ + PIN_AFIO_AF(GPIOA_OTG_FS_DP, 10) | \ + PIN_AFIO_AF(GPIOA_TMS, 0) | \ + PIN_AFIO_AF(GPIOA_TCK, 0) | \ + PIN_AFIO_AF(GPIOA_TDI, 0)) + +/* + * GPIOB setup: + * + * PB0 - LCD_YD (analog). + * PB1 - LCD_XL (analog). + * PB2 - PIN2 (input pullup). + * PB3 - TDO (alternate 0). + * PB4 - TRST (input pullup). + * PB5 - PIN5 (input pullup). + * PB6 - SCL1 (alternate 4). + * PB7 - SDA1 (input pullup). + * PB8 - DRIVEA (output pushpull maximum). + * PB9 - DRIVEB (output opendrain maximum). + * PB10 - SCL2 (input pullup). + * PB11 - SDA2 (input pullup). + * PB12 - PIN12 (input pullup). + * PB13 - SCK2 (input pullup). + * PB14 - MISO2 (input pullup). + * PB15 - MOSI2 (input pullup). + */ +#define VAL_GPIOB_MODER (PIN_MODE_ANALOG(GPIOB_LCD_YD) | \ + PIN_MODE_ANALOG(GPIOB_LCD_XL) | \ + PIN_MODE_INPUT(GPIOB_PIN2) | \ + PIN_MODE_ALTERNATE(GPIOB_TDO) | \ + PIN_MODE_INPUT(GPIOB_TRST) | \ + PIN_MODE_INPUT(GPIOB_PIN5) | \ + PIN_MODE_ALTERNATE(GPIOB_SCL1) | \ + PIN_MODE_INPUT(GPIOB_SDA1) | \ + PIN_MODE_OUTPUT(GPIOB_DRIVEA) | \ + PIN_MODE_OUTPUT(GPIOB_DRIVEB) | \ + PIN_MODE_INPUT(GPIOB_SCL2) | \ + PIN_MODE_INPUT(GPIOB_SDA2) | \ + PIN_MODE_INPUT(GPIOB_PIN12) | \ + PIN_MODE_INPUT(GPIOB_SCK2) | \ + PIN_MODE_INPUT(GPIOB_MISO2) | \ + PIN_MODE_INPUT(GPIOB_MOSI2)) +#define VAL_GPIOB_OTYPER (PIN_OTYPE_PUSHPULL(GPIOB_LCD_YD) | \ + PIN_OTYPE_PUSHPULL(GPIOB_LCD_XL) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_TDO) | \ + PIN_OTYPE_PUSHPULL(GPIOB_TRST) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN5) | \ + PIN_OTYPE_OPENDRAIN(GPIOB_SCL1) | \ + PIN_OTYPE_PUSHPULL(GPIOB_SDA1) | \ + PIN_OTYPE_PUSHPULL(GPIOB_DRIVEA) | \ + PIN_OTYPE_OPENDRAIN(GPIOB_DRIVEB) | \ + PIN_OTYPE_PUSHPULL(GPIOB_SCL2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_SDA2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOB_SCK2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_MISO2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_MOSI2)) +#define VAL_GPIOB_OSPEEDR (PIN_OSPEED_100M(GPIOB_LCD_YD) | \ + PIN_OSPEED_100M(GPIOB_LCD_XL) | \ + PIN_OSPEED_100M(GPIOB_PIN2) | \ + PIN_OSPEED_100M(GPIOB_TDO) | \ + PIN_OSPEED_100M(GPIOB_TRST) | \ + PIN_OSPEED_100M(GPIOB_PIN5) | \ + PIN_OSPEED_100M(GPIOB_SCL1) | \ + PIN_OSPEED_100M(GPIOB_SDA1) | \ + PIN_OSPEED_100M(GPIOB_DRIVEA) | \ + PIN_OSPEED_100M(GPIOB_DRIVEB) | \ + PIN_OSPEED_100M(GPIOB_SCL2) | \ + PIN_OSPEED_100M(GPIOB_SDA2) | \ + PIN_OSPEED_100M(GPIOB_PIN12) | \ + PIN_OSPEED_100M(GPIOB_SCK2) | \ + PIN_OSPEED_100M(GPIOB_MISO2) | \ + PIN_OSPEED_100M(GPIOB_MOSI2)) +#define VAL_GPIOB_PUPDR (PIN_PUPDR_FLOATING(GPIOB_LCD_YD) | \ + PIN_PUPDR_FLOATING(GPIOB_LCD_XL) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOB_TDO) | \ + PIN_PUPDR_PULLUP(GPIOB_TRST) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOB_SCL1) | \ + PIN_PUPDR_PULLUP(GPIOB_SDA1) | \ + PIN_PUPDR_FLOATING(GPIOB_DRIVEA) | \ + PIN_PUPDR_FLOATING(GPIOB_DRIVEB) | \ + PIN_PUPDR_PULLUP(GPIOB_SCL2) | \ + PIN_PUPDR_PULLUP(GPIOB_SDA2) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOB_SCK2) | \ + PIN_PUPDR_PULLUP(GPIOB_MISO2) | \ + PIN_PUPDR_PULLUP(GPIOB_MOSI2)) +#define VAL_GPIOB_ODR (PIN_ODR_HIGH(GPIOB_LCD_YD) | \ + PIN_ODR_HIGH(GPIOB_LCD_XL) | \ + PIN_ODR_HIGH(GPIOB_PIN2) | \ + PIN_ODR_HIGH(GPIOB_TDO) | \ + PIN_ODR_HIGH(GPIOB_TRST) | \ + PIN_ODR_HIGH(GPIOB_PIN5) | \ + PIN_ODR_HIGH(GPIOB_SCL1) | \ + PIN_ODR_HIGH(GPIOB_SDA1) | \ + PIN_ODR_HIGH(GPIOB_DRIVEA) | \ + PIN_ODR_HIGH(GPIOB_DRIVEB) | \ + PIN_ODR_HIGH(GPIOB_SCL2) | \ + PIN_ODR_HIGH(GPIOB_SDA2) | \ + PIN_ODR_HIGH(GPIOB_PIN12) | \ + PIN_ODR_HIGH(GPIOB_SCK2) | \ + PIN_ODR_HIGH(GPIOB_MISO2) | \ + PIN_ODR_HIGH(GPIOB_MOSI2)) +#define VAL_GPIOB_AFRL (PIN_AFIO_AF(GPIOB_LCD_YD, 0) | \ + PIN_AFIO_AF(GPIOB_LCD_XL, 0) | \ + PIN_AFIO_AF(GPIOB_PIN2, 0) | \ + PIN_AFIO_AF(GPIOB_TDO, 0) | \ + PIN_AFIO_AF(GPIOB_TRST, 0) | \ + PIN_AFIO_AF(GPIOB_PIN5, 0) | \ + PIN_AFIO_AF(GPIOB_SCL1, 4) | \ + PIN_AFIO_AF(GPIOB_SDA1, 4)) +#define VAL_GPIOB_AFRH (PIN_AFIO_AF(GPIOB_DRIVEA, 0) | \ + PIN_AFIO_AF(GPIOB_DRIVEB, 0) | \ + PIN_AFIO_AF(GPIOB_SCL2, 0) | \ + PIN_AFIO_AF(GPIOB_SDA2, 0) | \ + PIN_AFIO_AF(GPIOB_PIN12, 0) | \ + PIN_AFIO_AF(GPIOB_SCK2, 0) | \ + PIN_AFIO_AF(GPIOB_MISO2, 0) | \ + PIN_AFIO_AF(GPIOB_MOSI2, 0)) + +/* + * GPIOC setup: + * + * PC0 - PIN0 (output pushpull maximum). + * PC1 - PIN1 (input pullup). + * PC2 - PIN2 (input pullup). + * PC3 - PIN3 (input pullup). + * PC4 - PIN4 (input pullup). + * PC5 - PIN5 (input pullup). + * PC6 - MP3_DREQ (input pullup). + * PC7 - MP3_RST (alternate 6). + * PC8 - MP3_CS (output pushpull maximum). + * PC9 - MP3_DCS (input pullup). + * PC10 - SCK3 (alternate 6). + * PC11 - MISO3 (alternate 6). + * PC12 - MOSI3 (alternate 6). + * PC13 - STAT (input pullup). + * PC14 - PIN14 (input pullup). + * PC15 - PIN15 (input pullup). + */ +#define VAL_GPIOC_MODER (PIN_MODE_OUTPUT(GPIOC_PIN0) | \ + PIN_MODE_INPUT(GPIOC_PIN1) | \ + PIN_MODE_INPUT(GPIOC_PIN2) | \ + PIN_MODE_INPUT(GPIOC_PIN3) | \ + PIN_MODE_INPUT(GPIOC_PIN4) | \ + PIN_MODE_INPUT(GPIOC_PIN5) | \ + PIN_MODE_INPUT(GPIOC_MP3_DREQ) | \ + PIN_MODE_ALTERNATE(GPIOC_MP3_RST) | \ + PIN_MODE_OUTPUT(GPIOC_MP3_CS) | \ + PIN_MODE_INPUT(GPIOC_MP3_DCS) | \ + PIN_MODE_ALTERNATE(GPIOC_SCK3) | \ + PIN_MODE_ALTERNATE(GPIOC_MISO3) | \ + PIN_MODE_ALTERNATE(GPIOC_MOSI3) | \ + PIN_MODE_INPUT(GPIOC_STAT) | \ + PIN_MODE_INPUT(GPIOC_PIN14) | \ + PIN_MODE_INPUT(GPIOC_PIN15)) +#define VAL_GPIOC_OTYPER (PIN_OTYPE_PUSHPULL(GPIOC_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOC_MP3_DREQ) | \ + PIN_OTYPE_PUSHPULL(GPIOC_MP3_RST) | \ + PIN_OTYPE_PUSHPULL(GPIOC_MP3_CS) | \ + PIN_OTYPE_PUSHPULL(GPIOC_MP3_DCS) | \ + PIN_OTYPE_PUSHPULL(GPIOC_SCK3) | \ + PIN_OTYPE_PUSHPULL(GPIOC_MISO3) | \ + PIN_OTYPE_PUSHPULL(GPIOC_MOSI3) | \ + PIN_OTYPE_PUSHPULL(GPIOC_STAT) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN15)) +#define VAL_GPIOC_OSPEEDR (PIN_OSPEED_100M(GPIOC_PIN0) | \ + PIN_OSPEED_100M(GPIOC_PIN1) | \ + PIN_OSPEED_100M(GPIOC_PIN2) | \ + PIN_OSPEED_100M(GPIOC_PIN3) | \ + PIN_OSPEED_100M(GPIOC_PIN4) | \ + PIN_OSPEED_100M(GPIOC_PIN5) | \ + PIN_OSPEED_100M(GPIOC_MP3_DREQ) | \ + PIN_OSPEED_100M(GPIOC_MP3_RST) | \ + PIN_OSPEED_100M(GPIOC_MP3_CS) | \ + PIN_OSPEED_100M(GPIOC_MP3_DCS) | \ + PIN_OSPEED_100M(GPIOC_SCK3) | \ + PIN_OSPEED_100M(GPIOC_MISO3) | \ + PIN_OSPEED_100M(GPIOC_MOSI3) | \ + PIN_OSPEED_100M(GPIOC_STAT) | \ + PIN_OSPEED_100M(GPIOC_PIN14) | \ + PIN_OSPEED_100M(GPIOC_PIN15)) +#define VAL_GPIOC_PUPDR (PIN_PUPDR_FLOATING(GPIOC_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOC_MP3_DREQ) | \ + PIN_PUPDR_FLOATING(GPIOC_MP3_RST) | \ + PIN_PUPDR_PULLUP(GPIOC_MP3_CS) | \ + PIN_PUPDR_PULLUP(GPIOC_MP3_DCS) | \ + PIN_PUPDR_FLOATING(GPIOC_SCK3) | \ + PIN_PUPDR_FLOATING(GPIOC_MISO3) | \ + PIN_PUPDR_FLOATING(GPIOC_MOSI3) | \ + PIN_PUPDR_PULLUP(GPIOC_STAT) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN15)) +#define VAL_GPIOC_ODR (PIN_ODR_HIGH(GPIOC_PIN0) | \ + PIN_ODR_HIGH(GPIOC_PIN1) | \ + PIN_ODR_HIGH(GPIOC_PIN2) | \ + PIN_ODR_HIGH(GPIOC_PIN3) | \ + PIN_ODR_HIGH(GPIOC_PIN4) | \ + PIN_ODR_HIGH(GPIOC_PIN5) | \ + PIN_ODR_HIGH(GPIOC_MP3_DREQ) | \ + PIN_ODR_HIGH(GPIOC_MP3_RST) | \ + PIN_ODR_HIGH(GPIOC_MP3_CS) | \ + PIN_ODR_HIGH(GPIOC_MP3_DCS) | \ + PIN_ODR_HIGH(GPIOC_SCK3) | \ + PIN_ODR_HIGH(GPIOC_MISO3) | \ + PIN_ODR_HIGH(GPIOC_MOSI3) | \ + PIN_ODR_HIGH(GPIOC_STAT) | \ + PIN_ODR_HIGH(GPIOC_PIN14) | \ + PIN_ODR_HIGH(GPIOC_PIN15)) +#define VAL_GPIOC_AFRL (PIN_AFIO_AF(GPIOC_PIN0, 0) | \ + PIN_AFIO_AF(GPIOC_PIN1, 0) | \ + PIN_AFIO_AF(GPIOC_PIN2, 0) | \ + PIN_AFIO_AF(GPIOC_PIN3, 0) | \ + PIN_AFIO_AF(GPIOC_PIN4, 0) | \ + PIN_AFIO_AF(GPIOC_PIN5, 0) | \ + PIN_AFIO_AF(GPIOC_MP3_DREQ, 0) | \ + PIN_AFIO_AF(GPIOC_MP3_RST, 6)) +#define VAL_GPIOC_AFRH (PIN_AFIO_AF(GPIOC_MP3_CS, 0) | \ + PIN_AFIO_AF(GPIOC_MP3_DCS, 0) | \ + PIN_AFIO_AF(GPIOC_SCK3, 6) | \ + PIN_AFIO_AF(GPIOC_MISO3, 6) | \ + PIN_AFIO_AF(GPIOC_MOSI3, 6) | \ + PIN_AFIO_AF(GPIOC_STAT, 0) | \ + PIN_AFIO_AF(GPIOC_PIN14, 0) | \ + PIN_AFIO_AF(GPIOC_PIN15, 0)) + +/* + * GPIOD setup: + * + * PD0 - PIN0 (input pullup). + * PD1 - PIN1 (input pullup). + * PD2 - PIN2 (input pullup). + * PD3 - SD_CS (output pushpull maximum). + * PD4 - PIN4 (output pushpull maximum). + * PD5 - TX2 (alternate 7). + * PD6 - RX2 (alternate 7). + * PD7 - FLASH_CS (output pushpull maximum). + * PD8 - PIN8 (input pullup). + * PD9 - PIN9 (input pullup). + * PD10 - PIN10 (input pullup). + * PD11 - PIN11 (input pullup). + * PD12 - PIN12 (output pushpull maximum). + * PD13 - PIN13 (output pushpull maximum). + * PD14 - PIN14 (output pushpull maximum). + * PD15 - SD_CD (output pushpull maximum). + */ +#define VAL_GPIOD_MODER (PIN_MODE_INPUT(GPIOD_PIN0) | \ + PIN_MODE_INPUT(GPIOD_PIN1) | \ + PIN_MODE_INPUT(GPIOD_PIN2) | \ + PIN_MODE_OUTPUT(GPIOD_SD_CS) | \ + PIN_MODE_OUTPUT(GPIOD_PIN4) | \ + PIN_MODE_ALTERNATE(GPIOD_TX2) | \ + PIN_MODE_ALTERNATE(GPIOD_RX2) | \ + PIN_MODE_OUTPUT(GPIOD_FLASH_CS) | \ + PIN_MODE_INPUT(GPIOD_PIN8) | \ + PIN_MODE_INPUT(GPIOD_PIN9) | \ + PIN_MODE_INPUT(GPIOD_PIN10) | \ + PIN_MODE_INPUT(GPIOD_PIN11) | \ + PIN_MODE_OUTPUT(GPIOD_PIN12) | \ + PIN_MODE_OUTPUT(GPIOD_PIN13) | \ + PIN_MODE_OUTPUT(GPIOD_PIN14) | \ + PIN_MODE_INPUT(GPIOD_SD_CD)) +#define VAL_GPIOD_OTYPER (PIN_OTYPE_PUSHPULL(GPIOD_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOD_SD_CS) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOD_TX2) | \ + PIN_OTYPE_PUSHPULL(GPIOD_RX2) | \ + PIN_OTYPE_PUSHPULL(GPIOD_FLASH_CS) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOD_SD_CD)) +#define VAL_GPIOD_OSPEEDR (PIN_OSPEED_100M(GPIOD_PIN0) | \ + PIN_OSPEED_100M(GPIOD_PIN1) | \ + PIN_OSPEED_100M(GPIOD_PIN2) | \ + PIN_OSPEED_100M(GPIOD_SD_CS) | \ + PIN_OSPEED_100M(GPIOD_PIN4) | \ + PIN_OSPEED_100M(GPIOD_TX2) | \ + PIN_OSPEED_100M(GPIOD_RX2) | \ + PIN_OSPEED_100M(GPIOD_FLASH_CS) | \ + PIN_OSPEED_100M(GPIOD_PIN8) | \ + PIN_OSPEED_100M(GPIOD_PIN9) | \ + PIN_OSPEED_100M(GPIOD_PIN10) | \ + PIN_OSPEED_100M(GPIOD_PIN11) | \ + PIN_OSPEED_100M(GPIOD_PIN12) | \ + PIN_OSPEED_100M(GPIOD_PIN13) | \ + PIN_OSPEED_100M(GPIOD_PIN14) | \ + PIN_OSPEED_100M(GPIOD_SD_CD)) +#define VAL_GPIOD_PUPDR (PIN_PUPDR_PULLUP(GPIOD_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOD_SD_CS) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOD_TX2) | \ + PIN_PUPDR_PULLUP(GPIOD_RX2) | \ + PIN_PUPDR_PULLUP(GPIOD_FLASH_CS) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOD_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOD_SD_CD)) +#define VAL_GPIOD_ODR (PIN_ODR_HIGH(GPIOD_PIN0) | \ + PIN_ODR_HIGH(GPIOD_PIN1) | \ + PIN_ODR_HIGH(GPIOD_PIN2) | \ + PIN_ODR_HIGH(GPIOD_SD_CS) | \ + PIN_ODR_HIGH(GPIOD_PIN4) | \ + PIN_ODR_HIGH(GPIOD_TX2) | \ + PIN_ODR_HIGH(GPIOD_RX2) | \ + PIN_ODR_HIGH(GPIOD_FLASH_CS) | \ + PIN_ODR_HIGH(GPIOD_PIN8) | \ + PIN_ODR_HIGH(GPIOD_PIN9) | \ + PIN_ODR_HIGH(GPIOD_PIN10) | \ + PIN_ODR_HIGH(GPIOD_PIN11) | \ + PIN_ODR_LOW(GPIOD_PIN12) | \ + PIN_ODR_LOW(GPIOD_PIN13) | \ + PIN_ODR_LOW(GPIOD_PIN14) | \ + PIN_ODR_LOW(GPIOD_SD_CD)) +#define VAL_GPIOD_AFRL (PIN_AFIO_AF(GPIOD_PIN0, 0) | \ + PIN_AFIO_AF(GPIOD_PIN1, 0) | \ + PIN_AFIO_AF(GPIOD_PIN2, 0) | \ + PIN_AFIO_AF(GPIOD_SD_CS, 0) | \ + PIN_AFIO_AF(GPIOD_PIN4, 0) | \ + PIN_AFIO_AF(GPIOD_TX2, 7) | \ + PIN_AFIO_AF(GPIOD_RX2, 7) | \ + PIN_AFIO_AF(GPIOD_FLASH_CS, 0)) +#define VAL_GPIOD_AFRH (PIN_AFIO_AF(GPIOD_PIN8, 0) | \ + PIN_AFIO_AF(GPIOD_PIN9, 0) | \ + PIN_AFIO_AF(GPIOD_PIN10, 0) | \ + PIN_AFIO_AF(GPIOD_PIN11, 0) | \ + PIN_AFIO_AF(GPIOD_PIN12, 0) | \ + PIN_AFIO_AF(GPIOD_PIN13, 0) | \ + PIN_AFIO_AF(GPIOD_PIN14, 0) | \ + PIN_AFIO_AF(GPIOD_SD_CD, 0)) + +/* + * GPIOE setup: + * + * PE0 - TD0 (output pushpull maximum). + * PE1 - TD1 (output pushpull maximum). + * PE2 - TD2 (output pushpull maximum). + * PE3 - TD3 (output pushpull maximum). + * PE4 - TD4 (output pushpull maximum). + * PE5 - TD5 (output pushpull maximum). + * PE6 - TD6 (output pushpull maximum). + * PE7 - TD7 (output pushpull maximum). + * PE8 - LCD_RST (output pushpull maximum). + * PE9 - LCD_BLED (output pushpull maximum). + * PE10 - PMRD (output pushpull maximum). + * PE11 - PMWR (output pushpull maximum). + * PE12 - LCD_RS (output pushpull maximum). + * PE13 - PIN13 (input floating). + * PE14 - PIN14 (input floating). + * PE15 - LCD_CS (output pushpull maximum). + */ +#define VAL_GPIOE_MODER (PIN_MODE_OUTPUT(GPIOE_TD0) | \ + PIN_MODE_OUTPUT(GPIOE_TD1) | \ + PIN_MODE_OUTPUT(GPIOE_TD2) | \ + PIN_MODE_OUTPUT(GPIOE_TD3) | \ + PIN_MODE_OUTPUT(GPIOE_TD4) | \ + PIN_MODE_OUTPUT(GPIOE_TD5) | \ + PIN_MODE_OUTPUT(GPIOE_TD6) | \ + PIN_MODE_OUTPUT(GPIOE_TD7) | \ + PIN_MODE_OUTPUT(GPIOE_LCD_RST) | \ + PIN_MODE_OUTPUT(GPIOE_LCD_BLED) | \ + PIN_MODE_OUTPUT(GPIOE_PMRD) | \ + PIN_MODE_OUTPUT(GPIOE_PMWR) | \ + PIN_MODE_OUTPUT(GPIOE_LCD_RS) | \ + PIN_MODE_INPUT(GPIOE_PIN13) | \ + PIN_MODE_INPUT(GPIOE_PIN14) | \ + PIN_MODE_OUTPUT(GPIOE_LCD_CS)) +#define VAL_GPIOE_OTYPER (PIN_OTYPE_PUSHPULL(GPIOE_TD0) | \ + PIN_OTYPE_PUSHPULL(GPIOE_TD1) | \ + PIN_OTYPE_PUSHPULL(GPIOE_TD2) | \ + PIN_OTYPE_PUSHPULL(GPIOE_TD3) | \ + PIN_OTYPE_PUSHPULL(GPIOE_TD4) | \ + PIN_OTYPE_PUSHPULL(GPIOE_TD5) | \ + PIN_OTYPE_PUSHPULL(GPIOE_TD6) | \ + PIN_OTYPE_PUSHPULL(GPIOE_TD7) | \ + PIN_OTYPE_PUSHPULL(GPIOE_LCD_RST) | \ + PIN_OTYPE_PUSHPULL(GPIOE_LCD_BLED) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PMRD) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PMWR) | \ + PIN_OTYPE_PUSHPULL(GPIOE_LCD_RS) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOE_LCD_CS)) +#define VAL_GPIOE_OSPEEDR (PIN_OSPEED_100M(GPIOE_TD0) | \ + PIN_OSPEED_100M(GPIOE_TD1) | \ + PIN_OSPEED_100M(GPIOE_TD2) | \ + PIN_OSPEED_100M(GPIOE_TD3) | \ + PIN_OSPEED_100M(GPIOE_TD4) | \ + PIN_OSPEED_100M(GPIOE_TD5) | \ + PIN_OSPEED_100M(GPIOE_TD6) | \ + PIN_OSPEED_100M(GPIOE_TD7) | \ + PIN_OSPEED_100M(GPIOE_LCD_RST) | \ + PIN_OSPEED_100M(GPIOE_LCD_BLED) | \ + PIN_OSPEED_100M(GPIOE_PMRD) | \ + PIN_OSPEED_100M(GPIOE_PMWR) | \ + PIN_OSPEED_100M(GPIOE_LCD_RS) | \ + PIN_OSPEED_100M(GPIOE_PIN13) | \ + PIN_OSPEED_100M(GPIOE_PIN14) | \ + PIN_OSPEED_100M(GPIOE_LCD_CS)) +#define VAL_GPIOE_PUPDR (PIN_PUPDR_FLOATING(GPIOE_TD0) | \ + PIN_PUPDR_FLOATING(GPIOE_TD1) | \ + PIN_PUPDR_FLOATING(GPIOE_TD2) | \ + PIN_PUPDR_FLOATING(GPIOE_TD3) | \ + PIN_PUPDR_FLOATING(GPIOE_TD4) | \ + PIN_PUPDR_FLOATING(GPIOE_TD5) | \ + PIN_PUPDR_FLOATING(GPIOE_TD6) | \ + PIN_PUPDR_FLOATING(GPIOE_TD7) | \ + PIN_PUPDR_FLOATING(GPIOE_LCD_RST) | \ + PIN_PUPDR_FLOATING(GPIOE_LCD_BLED) | \ + PIN_PUPDR_FLOATING(GPIOE_PMRD) | \ + PIN_PUPDR_FLOATING(GPIOE_PMWR) | \ + PIN_PUPDR_FLOATING(GPIOE_LCD_RS) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOE_LCD_CS)) +#define VAL_GPIOE_ODR (PIN_ODR_HIGH(GPIOE_TD0) | \ + PIN_ODR_HIGH(GPIOE_TD1) | \ + PIN_ODR_HIGH(GPIOE_TD2) | \ + PIN_ODR_HIGH(GPIOE_TD3) | \ + PIN_ODR_HIGH(GPIOE_TD4) | \ + PIN_ODR_HIGH(GPIOE_TD5) | \ + PIN_ODR_HIGH(GPIOE_TD6) | \ + PIN_ODR_HIGH(GPIOE_TD7) | \ + PIN_ODR_HIGH(GPIOE_LCD_RST) | \ + PIN_ODR_LOW(GPIOE_LCD_BLED) | \ + PIN_ODR_HIGH(GPIOE_PMRD) | \ + PIN_ODR_HIGH(GPIOE_PMWR) | \ + PIN_ODR_HIGH(GPIOE_LCD_RS) | \ + PIN_ODR_HIGH(GPIOE_PIN13) | \ + PIN_ODR_HIGH(GPIOE_PIN14) | \ + PIN_ODR_LOW(GPIOE_LCD_CS)) +#define VAL_GPIOE_AFRL (PIN_AFIO_AF(GPIOE_TD0, 0) | \ + PIN_AFIO_AF(GPIOE_TD1, 0) | \ + PIN_AFIO_AF(GPIOE_TD2, 0) | \ + PIN_AFIO_AF(GPIOE_TD3, 0) | \ + PIN_AFIO_AF(GPIOE_TD4, 0) | \ + PIN_AFIO_AF(GPIOE_TD5, 0) | \ + PIN_AFIO_AF(GPIOE_TD6, 0) | \ + PIN_AFIO_AF(GPIOE_TD7, 0)) +#define VAL_GPIOE_AFRH (PIN_AFIO_AF(GPIOE_LCD_RST, 0) | \ + PIN_AFIO_AF(GPIOE_LCD_BLED, 0) | \ + PIN_AFIO_AF(GPIOE_PMRD, 0) | \ + PIN_AFIO_AF(GPIOE_PMWR, 0) | \ + PIN_AFIO_AF(GPIOE_LCD_RS, 0) | \ + PIN_AFIO_AF(GPIOE_PIN13, 0) | \ + PIN_AFIO_AF(GPIOE_PIN14, 0) | \ + PIN_AFIO_AF(GPIOE_LCD_CS, 0)) + +/* + * GPIOF setup: + * + * PF0 - PIN0 (input floating). + * PF1 - PIN1 (input floating). + * PF2 - PIN2 (input floating). + * PF3 - PIN3 (input floating). + * PF4 - PIN4 (input floating). + * PF5 - PIN5 (input floating). + * PF6 - PIN6 (input floating). + * PF7 - PIN7 (input floating). + * PF8 - PIN8 (input floating). + * PF9 - PIN9 (input floating). + * PF10 - PIN10 (input floating). + * PF11 - PIN11 (input floating). + * PF12 - PIN12 (input floating). + * PF13 - PIN13 (input floating). + * PF14 - PIN14 (input floating). + * PF15 - PIN15 (input floating). + */ +#define VAL_GPIOF_MODER (PIN_MODE_INPUT(GPIOF_PIN0) | \ + PIN_MODE_INPUT(GPIOF_PIN1) | \ + PIN_MODE_INPUT(GPIOF_PIN2) | \ + PIN_MODE_INPUT(GPIOF_PIN3) | \ + PIN_MODE_INPUT(GPIOF_PIN4) | \ + PIN_MODE_INPUT(GPIOF_PIN5) | \ + PIN_MODE_INPUT(GPIOF_PIN6) | \ + PIN_MODE_INPUT(GPIOF_PIN7) | \ + PIN_MODE_INPUT(GPIOF_PIN8) | \ + PIN_MODE_INPUT(GPIOF_PIN9) | \ + PIN_MODE_INPUT(GPIOF_PIN10) | \ + PIN_MODE_INPUT(GPIOF_PIN11) | \ + PIN_MODE_INPUT(GPIOF_PIN12) | \ + PIN_MODE_INPUT(GPIOF_PIN13) | \ + PIN_MODE_INPUT(GPIOF_PIN14) | \ + PIN_MODE_INPUT(GPIOF_PIN15)) +#define VAL_GPIOF_OTYPER (PIN_OTYPE_PUSHPULL(GPIOF_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN15)) +#define VAL_GPIOF_OSPEEDR (PIN_OSPEED_100M(GPIOF_PIN0) | \ + PIN_OSPEED_100M(GPIOF_PIN1) | \ + PIN_OSPEED_100M(GPIOF_PIN2) | \ + PIN_OSPEED_100M(GPIOF_PIN3) | \ + PIN_OSPEED_100M(GPIOF_PIN4) | \ + PIN_OSPEED_100M(GPIOF_PIN5) | \ + PIN_OSPEED_100M(GPIOF_PIN6) | \ + PIN_OSPEED_100M(GPIOF_PIN7) | \ + PIN_OSPEED_100M(GPIOF_PIN8) | \ + PIN_OSPEED_100M(GPIOF_PIN9) | \ + PIN_OSPEED_100M(GPIOF_PIN10) | \ + PIN_OSPEED_100M(GPIOF_PIN11) | \ + PIN_OSPEED_100M(GPIOF_PIN12) | \ + PIN_OSPEED_100M(GPIOF_PIN13) | \ + PIN_OSPEED_100M(GPIOF_PIN14) | \ + PIN_OSPEED_100M(GPIOF_PIN15)) +#define VAL_GPIOF_PUPDR (PIN_PUPDR_FLOATING(GPIOF_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN15)) +#define VAL_GPIOF_ODR (PIN_ODR_HIGH(GPIOF_PIN0) | \ + PIN_ODR_HIGH(GPIOF_PIN1) | \ + PIN_ODR_HIGH(GPIOF_PIN2) | \ + PIN_ODR_HIGH(GPIOF_PIN3) | \ + PIN_ODR_HIGH(GPIOF_PIN4) | \ + PIN_ODR_HIGH(GPIOF_PIN5) | \ + PIN_ODR_HIGH(GPIOF_PIN6) | \ + PIN_ODR_HIGH(GPIOF_PIN7) | \ + PIN_ODR_HIGH(GPIOF_PIN8) | \ + PIN_ODR_HIGH(GPIOF_PIN9) | \ + PIN_ODR_HIGH(GPIOF_PIN10) | \ + PIN_ODR_HIGH(GPIOF_PIN11) | \ + PIN_ODR_HIGH(GPIOF_PIN12) | \ + PIN_ODR_HIGH(GPIOF_PIN13) | \ + PIN_ODR_HIGH(GPIOF_PIN14) | \ + PIN_ODR_HIGH(GPIOF_PIN15)) +#define VAL_GPIOF_AFRL (PIN_AFIO_AF(GPIOF_PIN0, 0) | \ + PIN_AFIO_AF(GPIOF_PIN1, 0) | \ + PIN_AFIO_AF(GPIOF_PIN2, 0) | \ + PIN_AFIO_AF(GPIOF_PIN3, 0) | \ + PIN_AFIO_AF(GPIOF_PIN4, 0) | \ + PIN_AFIO_AF(GPIOF_PIN5, 0) | \ + PIN_AFIO_AF(GPIOF_PIN6, 0) | \ + PIN_AFIO_AF(GPIOF_PIN7, 0)) +#define VAL_GPIOF_AFRH (PIN_AFIO_AF(GPIOF_PIN8, 0) | \ + PIN_AFIO_AF(GPIOF_PIN9, 0) | \ + PIN_AFIO_AF(GPIOF_PIN10, 0) | \ + PIN_AFIO_AF(GPIOF_PIN11, 0) | \ + PIN_AFIO_AF(GPIOF_PIN12, 0) | \ + PIN_AFIO_AF(GPIOF_PIN13, 0) | \ + PIN_AFIO_AF(GPIOF_PIN14, 0) | \ + PIN_AFIO_AF(GPIOF_PIN15, 0)) + +/* + * GPIOG setup: + * + * PG0 - PIN0 (input floating). + * PG1 - PIN1 (input floating). + * PG2 - PIN2 (input floating). + * PG3 - PIN3 (input floating). + * PG4 - PIN4 (input floating). + * PG5 - PIN5 (input floating). + * PG6 - PIN6 (input floating). + * PG7 - PIN7 (input floating). + * PG8 - PIN8 (input floating). + * PG9 - PIN9 (input floating). + * PG10 - PIN10 (input floating). + * PG11 - PIN11 (input floating). + * PG12 - PIN12 (input floating). + * PG13 - PIN13 (input floating). + * PG14 - PIN14 (input floating). + * PG15 - PIN15 (input floating). + */ +#define VAL_GPIOG_MODER (PIN_MODE_INPUT(GPIOG_PIN0) | \ + PIN_MODE_INPUT(GPIOG_PIN1) | \ + PIN_MODE_INPUT(GPIOG_PIN2) | \ + PIN_MODE_INPUT(GPIOG_PIN3) | \ + PIN_MODE_INPUT(GPIOG_PIN4) | \ + PIN_MODE_INPUT(GPIOG_PIN5) | \ + PIN_MODE_INPUT(GPIOG_PIN6) | \ + PIN_MODE_INPUT(GPIOG_PIN7) | \ + PIN_MODE_INPUT(GPIOG_PIN8) | \ + PIN_MODE_INPUT(GPIOG_PIN9) | \ + PIN_MODE_INPUT(GPIOG_PIN10) | \ + PIN_MODE_INPUT(GPIOG_PIN11) | \ + PIN_MODE_INPUT(GPIOG_PIN12) | \ + PIN_MODE_INPUT(GPIOG_PIN13) | \ + PIN_MODE_INPUT(GPIOG_PIN14) | \ + PIN_MODE_INPUT(GPIOG_PIN15)) +#define VAL_GPIOG_OTYPER (PIN_OTYPE_PUSHPULL(GPIOG_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN15)) +#define VAL_GPIOG_OSPEEDR (PIN_OSPEED_100M(GPIOG_PIN0) | \ + PIN_OSPEED_100M(GPIOG_PIN1) | \ + PIN_OSPEED_100M(GPIOG_PIN2) | \ + PIN_OSPEED_100M(GPIOG_PIN3) | \ + PIN_OSPEED_100M(GPIOG_PIN4) | \ + PIN_OSPEED_100M(GPIOG_PIN5) | \ + PIN_OSPEED_100M(GPIOG_PIN6) | \ + PIN_OSPEED_100M(GPIOG_PIN7) | \ + PIN_OSPEED_100M(GPIOG_PIN8) | \ + PIN_OSPEED_100M(GPIOG_PIN9) | \ + PIN_OSPEED_100M(GPIOG_PIN10) | \ + PIN_OSPEED_100M(GPIOG_PIN11) | \ + PIN_OSPEED_100M(GPIOG_PIN12) | \ + PIN_OSPEED_100M(GPIOG_PIN13) | \ + PIN_OSPEED_100M(GPIOG_PIN14) | \ + PIN_OSPEED_100M(GPIOG_PIN15)) +#define VAL_GPIOG_PUPDR (PIN_PUPDR_FLOATING(GPIOG_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN15)) +#define VAL_GPIOG_ODR (PIN_ODR_HIGH(GPIOG_PIN0) | \ + PIN_ODR_HIGH(GPIOG_PIN1) | \ + PIN_ODR_HIGH(GPIOG_PIN2) | \ + PIN_ODR_HIGH(GPIOG_PIN3) | \ + PIN_ODR_HIGH(GPIOG_PIN4) | \ + PIN_ODR_HIGH(GPIOG_PIN5) | \ + PIN_ODR_HIGH(GPIOG_PIN6) | \ + PIN_ODR_HIGH(GPIOG_PIN7) | \ + PIN_ODR_HIGH(GPIOG_PIN8) | \ + PIN_ODR_HIGH(GPIOG_PIN9) | \ + PIN_ODR_HIGH(GPIOG_PIN10) | \ + PIN_ODR_HIGH(GPIOG_PIN11) | \ + PIN_ODR_HIGH(GPIOG_PIN12) | \ + PIN_ODR_HIGH(GPIOG_PIN13) | \ + PIN_ODR_HIGH(GPIOG_PIN14) | \ + PIN_ODR_HIGH(GPIOG_PIN15)) +#define VAL_GPIOG_AFRL (PIN_AFIO_AF(GPIOG_PIN0, 0) | \ + PIN_AFIO_AF(GPIOG_PIN1, 0) | \ + PIN_AFIO_AF(GPIOG_PIN2, 0) | \ + PIN_AFIO_AF(GPIOG_PIN3, 0) | \ + PIN_AFIO_AF(GPIOG_PIN4, 0) | \ + PIN_AFIO_AF(GPIOG_PIN5, 0) | \ + PIN_AFIO_AF(GPIOG_PIN6, 0) | \ + PIN_AFIO_AF(GPIOG_PIN7, 0)) +#define VAL_GPIOG_AFRH (PIN_AFIO_AF(GPIOG_PIN8, 0) | \ + PIN_AFIO_AF(GPIOG_PIN9, 0) | \ + PIN_AFIO_AF(GPIOG_PIN10, 0) | \ + PIN_AFIO_AF(GPIOG_PIN11, 0) | \ + PIN_AFIO_AF(GPIOG_PIN12, 0) | \ + PIN_AFIO_AF(GPIOG_PIN13, 0) | \ + PIN_AFIO_AF(GPIOG_PIN14, 0) | \ + PIN_AFIO_AF(GPIOG_PIN15, 0)) + +/* + * GPIOH setup: + * + * PH0 - OSC_IN (input floating). + * PH1 - OSC_OUT (input floating). + * PH2 - PIN2 (input floating). + * PH3 - PIN3 (input floating). + * PH4 - PIN4 (input floating). + * PH5 - PIN5 (input floating). + * PH6 - PIN6 (input floating). + * PH7 - PIN7 (input floating). + * PH8 - PIN8 (input floating). + * PH9 - PIN9 (input floating). + * PH10 - PIN10 (input floating). + * PH11 - PIN11 (input floating). + * PH12 - PIN12 (input floating). + * PH13 - PIN13 (input floating). + * PH14 - PIN14 (input floating). + * PH15 - PIN15 (input floating). + */ +#define VAL_GPIOH_MODER (PIN_MODE_INPUT(GPIOH_OSC_IN) | \ + PIN_MODE_INPUT(GPIOH_OSC_OUT) | \ + PIN_MODE_INPUT(GPIOH_PIN2) | \ + PIN_MODE_INPUT(GPIOH_PIN3) | \ + PIN_MODE_INPUT(GPIOH_PIN4) | \ + PIN_MODE_INPUT(GPIOH_PIN5) | \ + PIN_MODE_INPUT(GPIOH_PIN6) | \ + PIN_MODE_INPUT(GPIOH_PIN7) | \ + PIN_MODE_INPUT(GPIOH_PIN8) | \ + PIN_MODE_INPUT(GPIOH_PIN9) | \ + PIN_MODE_INPUT(GPIOH_PIN10) | \ + PIN_MODE_INPUT(GPIOH_PIN11) | \ + PIN_MODE_INPUT(GPIOH_PIN12) | \ + PIN_MODE_INPUT(GPIOH_PIN13) | \ + PIN_MODE_INPUT(GPIOH_PIN14) | \ + PIN_MODE_INPUT(GPIOH_PIN15)) +#define VAL_GPIOH_OTYPER (PIN_OTYPE_PUSHPULL(GPIOH_OSC_IN) | \ + PIN_OTYPE_PUSHPULL(GPIOH_OSC_OUT) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN15)) +#define VAL_GPIOH_OSPEEDR (PIN_OSPEED_100M(GPIOH_OSC_IN) | \ + PIN_OSPEED_100M(GPIOH_OSC_OUT) | \ + PIN_OSPEED_100M(GPIOH_PIN2) | \ + PIN_OSPEED_100M(GPIOH_PIN3) | \ + PIN_OSPEED_100M(GPIOH_PIN4) | \ + PIN_OSPEED_100M(GPIOH_PIN5) | \ + PIN_OSPEED_100M(GPIOH_PIN6) | \ + PIN_OSPEED_100M(GPIOH_PIN7) | \ + PIN_OSPEED_100M(GPIOH_PIN8) | \ + PIN_OSPEED_100M(GPIOH_PIN9) | \ + PIN_OSPEED_100M(GPIOH_PIN10) | \ + PIN_OSPEED_100M(GPIOH_PIN11) | \ + PIN_OSPEED_100M(GPIOH_PIN12) | \ + PIN_OSPEED_100M(GPIOH_PIN13) | \ + PIN_OSPEED_100M(GPIOH_PIN14) | \ + PIN_OSPEED_100M(GPIOH_PIN15)) +#define VAL_GPIOH_PUPDR (PIN_PUPDR_FLOATING(GPIOH_OSC_IN) | \ + PIN_PUPDR_FLOATING(GPIOH_OSC_OUT) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN15)) +#define VAL_GPIOH_ODR (PIN_ODR_HIGH(GPIOH_OSC_IN) | \ + PIN_ODR_HIGH(GPIOH_OSC_OUT) | \ + PIN_ODR_HIGH(GPIOH_PIN2) | \ + PIN_ODR_HIGH(GPIOH_PIN3) | \ + PIN_ODR_HIGH(GPIOH_PIN4) | \ + PIN_ODR_HIGH(GPIOH_PIN5) | \ + PIN_ODR_HIGH(GPIOH_PIN6) | \ + PIN_ODR_HIGH(GPIOH_PIN7) | \ + PIN_ODR_HIGH(GPIOH_PIN8) | \ + PIN_ODR_HIGH(GPIOH_PIN9) | \ + PIN_ODR_HIGH(GPIOH_PIN10) | \ + PIN_ODR_HIGH(GPIOH_PIN11) | \ + PIN_ODR_HIGH(GPIOH_PIN12) | \ + PIN_ODR_HIGH(GPIOH_PIN13) | \ + PIN_ODR_HIGH(GPIOH_PIN14) | \ + PIN_ODR_HIGH(GPIOH_PIN15)) +#define VAL_GPIOH_AFRL (PIN_AFIO_AF(GPIOH_OSC_IN, 0) | \ + PIN_AFIO_AF(GPIOH_OSC_OUT, 0) | \ + PIN_AFIO_AF(GPIOH_PIN2, 0) | \ + PIN_AFIO_AF(GPIOH_PIN3, 0) | \ + PIN_AFIO_AF(GPIOH_PIN4, 0) | \ + PIN_AFIO_AF(GPIOH_PIN5, 0) | \ + PIN_AFIO_AF(GPIOH_PIN6, 0) | \ + PIN_AFIO_AF(GPIOH_PIN7, 0)) +#define VAL_GPIOH_AFRH (PIN_AFIO_AF(GPIOH_PIN8, 0) | \ + PIN_AFIO_AF(GPIOH_PIN9, 0) | \ + PIN_AFIO_AF(GPIOH_PIN10, 0) | \ + PIN_AFIO_AF(GPIOH_PIN11, 0) | \ + PIN_AFIO_AF(GPIOH_PIN12, 0) | \ + PIN_AFIO_AF(GPIOH_PIN13, 0) | \ + PIN_AFIO_AF(GPIOH_PIN14, 0) | \ + PIN_AFIO_AF(GPIOH_PIN15, 0)) + +/* + * GPIOI setup: + * + * PI0 - PIN0 (input floating). + * PI1 - PIN1 (input floating). + * PI2 - PIN2 (input floating). + * PI3 - PIN3 (input floating). + * PI4 - PIN4 (input floating). + * PI5 - PIN5 (input floating). + * PI6 - PIN6 (input floating). + * PI7 - PIN7 (input floating). + * PI8 - PIN8 (input floating). + * PI9 - PIN9 (input floating). + * PI10 - PIN10 (input floating). + * PI11 - PIN11 (input floating). + * PI12 - PIN12 (input floating). + * PI13 - PIN13 (input floating). + * PI14 - PIN14 (input floating). + * PI15 - PIN15 (input floating). + */ +#define VAL_GPIOI_MODER (PIN_MODE_INPUT(GPIOI_PIN0) | \ + PIN_MODE_INPUT(GPIOI_PIN1) | \ + PIN_MODE_INPUT(GPIOI_PIN2) | \ + PIN_MODE_INPUT(GPIOI_PIN3) | \ + PIN_MODE_INPUT(GPIOI_PIN4) | \ + PIN_MODE_INPUT(GPIOI_PIN5) | \ + PIN_MODE_INPUT(GPIOI_PIN6) | \ + PIN_MODE_INPUT(GPIOI_PIN7) | \ + PIN_MODE_INPUT(GPIOI_PIN8) | \ + PIN_MODE_INPUT(GPIOI_PIN9) | \ + PIN_MODE_INPUT(GPIOI_PIN10) | \ + PIN_MODE_INPUT(GPIOI_PIN11) | \ + PIN_MODE_INPUT(GPIOI_PIN12) | \ + PIN_MODE_INPUT(GPIOI_PIN13) | \ + PIN_MODE_INPUT(GPIOI_PIN14) | \ + PIN_MODE_INPUT(GPIOI_PIN15)) +#define VAL_GPIOI_OTYPER (PIN_OTYPE_PUSHPULL(GPIOI_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN15)) +#define VAL_GPIOI_OSPEEDR (PIN_OSPEED_100M(GPIOI_PIN0) | \ + PIN_OSPEED_100M(GPIOI_PIN1) | \ + PIN_OSPEED_100M(GPIOI_PIN2) | \ + PIN_OSPEED_100M(GPIOI_PIN3) | \ + PIN_OSPEED_100M(GPIOI_PIN4) | \ + PIN_OSPEED_100M(GPIOI_PIN5) | \ + PIN_OSPEED_100M(GPIOI_PIN6) | \ + PIN_OSPEED_100M(GPIOI_PIN7) | \ + PIN_OSPEED_100M(GPIOI_PIN8) | \ + PIN_OSPEED_100M(GPIOI_PIN9) | \ + PIN_OSPEED_100M(GPIOI_PIN10) | \ + PIN_OSPEED_100M(GPIOI_PIN11) | \ + PIN_OSPEED_100M(GPIOI_PIN12) | \ + PIN_OSPEED_100M(GPIOI_PIN13) | \ + PIN_OSPEED_100M(GPIOI_PIN14) | \ + PIN_OSPEED_100M(GPIOI_PIN15)) +#define VAL_GPIOI_PUPDR (PIN_PUPDR_FLOATING(GPIOI_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN15)) +#define VAL_GPIOI_ODR (PIN_ODR_HIGH(GPIOI_PIN0) | \ + PIN_ODR_HIGH(GPIOI_PIN1) | \ + PIN_ODR_HIGH(GPIOI_PIN2) | \ + PIN_ODR_HIGH(GPIOI_PIN3) | \ + PIN_ODR_HIGH(GPIOI_PIN4) | \ + PIN_ODR_HIGH(GPIOI_PIN5) | \ + PIN_ODR_HIGH(GPIOI_PIN6) | \ + PIN_ODR_HIGH(GPIOI_PIN7) | \ + PIN_ODR_HIGH(GPIOI_PIN8) | \ + PIN_ODR_HIGH(GPIOI_PIN9) | \ + PIN_ODR_HIGH(GPIOI_PIN10) | \ + PIN_ODR_HIGH(GPIOI_PIN11) | \ + PIN_ODR_HIGH(GPIOI_PIN12) | \ + PIN_ODR_HIGH(GPIOI_PIN13) | \ + PIN_ODR_HIGH(GPIOI_PIN14) | \ + PIN_ODR_HIGH(GPIOI_PIN15)) +#define VAL_GPIOI_AFRL (PIN_AFIO_AF(GPIOI_PIN0, 0) | \ + PIN_AFIO_AF(GPIOI_PIN1, 0) | \ + PIN_AFIO_AF(GPIOI_PIN2, 0) | \ + PIN_AFIO_AF(GPIOI_PIN3, 0) | \ + PIN_AFIO_AF(GPIOI_PIN4, 0) | \ + PIN_AFIO_AF(GPIOI_PIN5, 0) | \ + PIN_AFIO_AF(GPIOI_PIN6, 0) | \ + PIN_AFIO_AF(GPIOI_PIN7, 0)) +#define VAL_GPIOI_AFRH (PIN_AFIO_AF(GPIOI_PIN8, 0) | \ + PIN_AFIO_AF(GPIOI_PIN9, 0) | \ + PIN_AFIO_AF(GPIOI_PIN10, 0) | \ + PIN_AFIO_AF(GPIOI_PIN11, 0) | \ + PIN_AFIO_AF(GPIOI_PIN12, 0) | \ + PIN_AFIO_AF(GPIOI_PIN13, 0) | \ + PIN_AFIO_AF(GPIOI_PIN14, 0) | \ + PIN_AFIO_AF(GPIOI_PIN15, 0)) + + +#if !defined(_FROM_ASM_) +#ifdef __cplusplus +extern "C" { +#endif + void boardInit(void); +#ifdef __cplusplus +} +#endif +#endif /* _FROM_ASM_ */ + +#endif /* _BOARD_H_ */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.mk b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.mk new file mode 100644 index 00000000..d6a45638 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.mk @@ -0,0 +1,7 @@ +# Required include directories +BOARDINC = $(GFXLIB)/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board + +# List of all the board related files. +BOARDSRC = $(BOARDINC)/board.c \ + $(BOARDINC)/flash_memory.c + diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board_orig.h b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board_orig.h new file mode 100644 index 00000000..e4d2c31f --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board_orig.h @@ -0,0 +1,1303 @@ + +#ifndef _BOARD_H_ +#define _BOARD_H_ + +/* + * Setup for Mikroe mikromedia STM32-M4. + */ + +/* + * Board identifier. + */ +#define BOARD_MIKROMEDIA_STM32_M4 +#define BOARD_NAME "mikromedia STM32-M4" + + +/* + * Board oscillators-related settings. + * NOTE: LSE not fitted. + */ +#if !defined(STM32_LSECLK) +#define STM32_LSECLK 32768 +#endif + +#if !defined(STM32_HSECLK) +#define STM32_HSECLK 16000000 +#endif + + +/* + * Board voltages. + * Required for performance limits calculation. + */ +#define STM32_VDD 330 + +/* + * MCU type as defined in the ST header file stm32f4xx.h. + */ +#define STM32F4XX + +/* + * IO pins assignments. + */ +#define GPIOA_VSENSE 0 +#define GPIOA_PIN1 1 +#define GPIOA_PIN2 2 +#define GPIOA_PIN3 3 +#define GPIOA_PIN4 4 +#define GPIOA_PIN5 5 +#define GPIOA_PIN6 6 +#define GPIOA_PIN7 7 +#define GPIOA_PIN8 8 +#define GPIOA_VBUS_FS 9 +#define GPIOA_PIN10 10 +#define GPIOA_OTG_FS_DM 11 +#define GPIOA_OTG_FS_DP 12 +#define GPIOA_TMS 13 +#define GPIOA_TCK 14 +#define GPIOA_TDI 15 + +#define GPIOB_LCD_YD 0 +#define GPIOB_LCD_XL 1 +#define GPIOB_PIN2 2 +#define GPIOB_TDO 3 +#define GPIOB_TRST 4 +#define GPIOB_PIN5 5 +#define GPIOB_SCL1 6 +#define GPIOB_SDA1 7 +#define GPIOB_DRIVEA 8 +#define GPIOB_DRIVEB 9 +#define GPIOB_SCL2 10 +#define GPIOB_SDA2 11 +#define GPIOB_PIN12 12 +#define GPIOB_SCK2 13 +#define GPIOB_MISO2 14 +#define GPIOB_MOSI2 15 + +#define GPIOC_PIN0 0 +#define GPIOC_PIN1 1 +#define GPIOC_PIN2 2 +#define GPIOC_PIN3 3 +#define GPIOC_PIN4 4 +#define GPIOC_PIN5 5 +#define GPIOC_MP3_DREQ 6 +#define GPIOC_MP3_RST 7 +#define GPIOC_MP3_CS 8 +#define GPIOC_MP3_DCS 9 +#define GPIOC_SCL3 10 +#define GPIOC_MISO3 11 +#define GPIOC_MOSI3 12 +#define GPIOC_STAT 13 +#define GPIOC_OSC32_IN 14 +#define GPIOC_OSC32_OUT 15 + +#define GPIOD_PIN0 0 +#define GPIOD_PIN1 1 +#define GPIOD_PIN2 2 +#define GPIOD_SD_CS 3 +#define GPIOD_PIN4 4 +#define GPIOD_TX2 5 +#define GPIOD_RX2 6 +#define GPIOD_FLASH_CS 7 +#define GPIOD_PIN8 8 +#define GPIOD_PIN9 9 +#define GPIOD_PIN10 10 +#define GPIOD_PIN11 11 +#define GPIOD_PIN12 12 +#define GPIOD_PIN13 13 +#define GPIOD_PIN14 14 +#define GPIOD_SD_CD 15 + +// DONE TO HERE + +#define GPIOE_TD0 0 +#define GPIOE_TD1 1 +#define GPIOE_TD2 2 +#define GPIOE_TD3 3 +#define GPIOE_TD4 4 +#define GPIOE_TD5 5 +#define GPIOE_TD6 6 +#define GPIOE_TD7 7 +#define GPIOE_LCD_RST 8 +#define GPIOE_LCD_BLED 9 +#define GPIOE_PMRD 10 +#define GPIOE_PMWR 11 +#define GPIOE_LCD_RS 12 +#define GPIOE_PIN13 13 +#define GPIOE_PIN14 14 +#define GPIOE_LCD_CS 15 + +#define GPIOF_PIN0 0 +#define GPIOF_PIN1 1 +#define GPIOF_PIN2 2 +#define GPIOF_PIN3 3 +#define GPIOF_PIN4 4 +#define GPIOF_PIN5 5 +#define GPIOF_PIN6 6 +#define GPIOF_PIN7 7 +#define GPIOF_PIN8 8 +#define GPIOF_PIN9 9 +#define GPIOF_PIN10 10 +#define GPIOF_PIN11 11 +#define GPIOF_PIN12 12 +#define GPIOF_PIN13 13 +#define GPIOF_PIN14 14 +#define GPIOF_PIN15 15 + +#define GPIOG_PIN0 0 +#define GPIOG_PIN1 1 +#define GPIOG_PIN2 2 +#define GPIOG_PIN3 3 +#define GPIOG_PIN4 4 +#define GPIOG_PIN5 5 +#define GPIOG_PIN6 6 +#define GPIOG_PIN7 7 +#define GPIOG_PIN8 8 +#define GPIOG_PIN9 9 +#define GPIOG_PIN10 10 +#define GPIOG_PIN11 11 +#define GPIOG_PIN12 12 +#define GPIOG_PIN13 13 +#define GPIOG_PIN14 14 +#define GPIOG_PIN15 15 + +#define GPIOH_OSC_IN 0 +#define GPIOH_OSC_OUT 1 +#define GPIOH_PIN2 2 +#define GPIOH_PIN3 3 +#define GPIOH_PIN4 4 +#define GPIOH_PIN5 5 +#define GPIOH_PIN6 6 +#define GPIOH_PIN7 7 +#define GPIOH_PIN8 8 +#define GPIOH_PIN9 9 +#define GPIOH_PIN10 10 +#define GPIOH_PIN11 11 +#define GPIOH_PIN12 12 +#define GPIOH_PIN13 13 +#define GPIOH_PIN14 14 +#define GPIOH_PIN15 15 + +#define GPIOI_PIN0 0 +#define GPIOI_PIN1 1 +#define GPIOI_PIN2 2 +#define GPIOI_PIN3 3 +#define GPIOI_PIN4 4 +#define GPIOI_PIN5 5 +#define GPIOI_PIN6 6 +#define GPIOI_PIN7 7 +#define GPIOI_PIN8 8 +#define GPIOI_PIN9 9 +#define GPIOI_PIN10 10 +#define GPIOI_PIN11 11 +#define GPIOI_PIN12 12 +#define GPIOI_PIN13 13 +#define GPIOI_PIN14 14 +#define GPIOI_PIN15 15 + +/* + * I/O ports initial setup, this configuration is established soon after reset + * in the initialization code. + * Please refer to the STM32 Reference Manual for details. + */ +#define PIN_MODE_INPUT(n) (0U << ((n) * 2)) +#define PIN_MODE_OUTPUT(n) (1U << ((n) * 2)) +#define PIN_MODE_ALTERNATE(n) (2U << ((n) * 2)) +#define PIN_MODE_ANALOG(n) (3U << ((n) * 2)) +#define PIN_ODR_LOW(n) (0U << (n)) +#define PIN_ODR_HIGH(n) (1U << (n)) +#define PIN_OTYPE_PUSHPULL(n) (0U << (n)) +#define PIN_OTYPE_OPENDRAIN(n) (1U << (n)) +#define PIN_OSPEED_2M(n) (0U << ((n) * 2)) +#define PIN_OSPEED_25M(n) (1U << ((n) * 2)) +#define PIN_OSPEED_50M(n) (2U << ((n) * 2)) +#define PIN_OSPEED_100M(n) (3U << ((n) * 2)) +#define PIN_PUPDR_FLOATING(n) (0U << ((n) * 2)) +#define PIN_PUPDR_PULLUP(n) (1U << ((n) * 2)) +#define PIN_PUPDR_PULLDOWN(n) (2U << ((n) * 2)) +#define PIN_AFIO_AF(n, v) ((v##U) << ((n % 8) * 4)) + +/* + * GPIOA setup: + * + * PA0 - Battery Voltage Sense (Analog) + * PA0 - BUTTON (input floating). +#define GPIOA_VSENSE 0 +#define GPIOA_PIN1 1 +#define GPIOA_PIN2 2 +#define GPIOA_PIN3 3 +#define GPIOA_PIN4 4 +#define GPIOA_PIN5 5 +#define GPIOA_PIN6 6 +#define GPIOA_PIN7 7 +#define GPIOA_PIN8 8 +#define GPIOA_VBUS_FS 9 +#define GPIOA_PIN10 10 +#define GPIOA_OTG_FS_DM 11 +#define GPIOA_OTG_FS_DP 12 +#define GPIOA_TMS 13 +#define GPIOA_TCK 14 +#define GPIOA_TDI 15 + */ +#define VAL_GPIOA_MODER (PIN_MODE_ANALOG(GPIOA_VSENSE) | \ + PIN_MODE_INPUT(GPIOA_PIN1) | \ + PIN_MODE_INPUT(GPIOA_PIN2) | \ + PIN_MODE_INPUT(GPIOA_PIN3) | \ + PIN_MODE_INPUT(GPIOA_PIN4) | \ + PIN_MODE_INPUT(GPIOA_PIN5) | \ + PIN_MODE_INPUT(GPIOA_PIN6) | \ + PIN_MODE_INPUT(GPIOA_PIN7) | \ + PIN_MODE_INPUT(GPIOA_PIN8) | \ + PIN_MODE_INPUT(GPIOA_VBUS_FS) | \ + PIN_MODE_INPUT(GPIOA_PIN10) | \ + PIN_MODE_ALTERNATE(GPIOA_OTG_FS_DM) | \ + PIN_MODE_ALTERNATE(GPIOA_OTG_FS_DP) | \ + PIN_MODE_ALTERNATE(GPIOA_TMS) | \ + PIN_MODE_ALTERNATE(GPIOA_TCK) | \ + PIN_MODE_ALTERNATE(GPIOA_TDI)) +#define VAL_GPIOA_OTYPER (PIN_OTYPE_PUSHPULL(GPIOA_VSENSE) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOA_VBUS_FS) | \ + PIN_OTYPE_PUSHPULL(GPIOA_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOA_OTG_FS_DM) | \ + PIN_OTYPE_PUSHPULL(GPIOA_OTG_FS_DP) | \ + PIN_OTYPE_PUSHPULL(GPIOA_TMS) | \ + PIN_OTYPE_PUSHPULL(GPIOA_TCK) | \ + PIN_OTYPE_PUSHPULL(GPIOA_TDI)) +#define VAL_GPIOA_OSPEEDR (PIN_OSPEED_100M(GPIOA_VSENSE) | \ + PIN_OSPEED_100M(GPIOA_PIN1) | \ + PIN_OSPEED_100M(GPIOA_PIN2) | \ + PIN_OSPEED_100M(GPIOA_PIN3) | \ + PIN_OSPEED_100M(GPIOA_PIN4) | \ + PIN_OSPEED_100M(GPIOA_PIN5) | \ + PIN_OSPEED_100M(GPIOA_PIN6) | \ + PIN_OSPEED_100M(GPIOA_PIN7) | \ + PIN_OSPEED_100M(GPIOA_PIN8) | \ + PIN_OSPEED_100M(GPIOA_VBUS_FS) | \ + PIN_OSPEED_100M(GPIOA_PIN10) | \ + PIN_OSPEED_100M(GPIOA_OTG_FS_DM) | \ + PIN_OSPEED_100M(GPIOA_OTG_FS_DP) | \ + PIN_OSPEED_100M(GPIOA_TMS) | \ + PIN_OSPEED_100M(GPIOA_TCK) | \ + PIN_OSPEED_100M(GPIOA_TDI)) +#define VAL_GPIOA_PUPDR (PIN_PUPDR_FLOATING(GPIOA_VSENSE) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN3) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOA_VBUS_FS) | \ + PIN_PUPDR_PULLUP(GPIOA_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOA_OTG_FS_DM) | \ + PIN_PUPDR_FLOATING(GPIOA_OTG_FS_DP) | \ + PIN_PUPDR_FLOATING(GPIOA_TMS) | \ + PIN_PUPDR_FLOATING(GPIOA_TCK) | \ + PIN_PUPDR_FLOATING(GPIOA_TDI)) +#define VAL_GPIOA_ODR (PIN_ODR_HIGH(GPIOA_VSENSE) | \ + PIN_ODR_HIGH(GPIOA_PIN1) | \ + PIN_ODR_HIGH(GPIOA_PIN2) | \ + PIN_ODR_HIGH(GPIOA_PIN3) | \ + PIN_ODR_HIGH(GPIOA_PIN4) | \ + PIN_ODR_HIGH(GPIOA_PIN5) | \ + PIN_ODR_HIGH(GPIOA_PIN6) | \ + PIN_ODR_HIGH(GPIOA_PIN7) | \ + PIN_ODR_HIGH(GPIOA_PIN8) | \ + PIN_ODR_HIGH(GPIOA_VBUS_FS) | \ + PIN_ODR_HIGH(GPIOA_PIN10) | \ + PIN_ODR_HIGH(GPIOA_OTG_FS_DM) | \ + PIN_ODR_HIGH(GPIOA_OTG_FS_DP) | \ + PIN_ODR_HIGH(GPIOA_TMS) | \ + PIN_ODR_HIGH(GPIOA_TCK) | \ + PIN_ODR_HIGH(GPIOA_TDI)) +#define VAL_GPIOA_AFRL (PIN_AFIO_AF(GPIOA_VSENSE, 0) | \ + PIN_AFIO_AF(GPIOA_PIN1, 0) | \ + PIN_AFIO_AF(GPIOA_PIN2, 0) | \ + PIN_AFIO_AF(GPIOA_PIN3, 0) | \ + PIN_AFIO_AF(GPIOA_PIN4, 0) | \ + PIN_AFIO_AF(GPIOA_PIN5, 0) | \ + PIN_AFIO_AF(GPIOA_PIN6, 0) | \ + PIN_AFIO_AF(GPIOA_PIN7, 0)) +#define VAL_GPIOA_AFRH (PIN_AFIO_AF(GPIOA_PIN8, 0) | \ + PIN_AFIO_AF(GPIOA_VBUS_FS, 0) | \ + PIN_AFIO_AF(GPIOA_PIN10, 0) | \ + PIN_AFIO_AF(GPIOA_OTG_FS_DM, 10) | \ + PIN_AFIO_AF(GPIOA_OTG_FS_DP, 10) | \ + PIN_AFIO_AF(GPIOA_TMS, 0) | \ + PIN_AFIO_AF(GPIOA_TCK, 0) | \ + PIN_AFIO_AF(GPIOA_TDI, 0)) +// DONE TO HERE +/* + * GPIOB setup: + * + * PB0 - PIN0 (input pullup). + * PB1 - PIN1 (input pullup). + * PB2 - PIN2 (input pullup). + * PB3 - SWO (alternate 0). + * PB4 - PIN4 (input pullup). + * PB5 - PIN5 (input pullup). + * PB6 - SCL (alternate 4). + * PB7 - PIN7 (input pullup). + * PB8 - PIN8 (input pullup). + * PB9 - SDA (alternate 4). + * PB10 - CLK_IN (input pullup). + * PB11 - PIN11 (input pullup). + * PB12 - PIN12 (input pullup). + * PB13 - PIN13 (input pullup). + * PB14 - PIN14 (input pullup). + * PB15 - PIN15 (input pullup). + +#define GPIOB_LCD_YD 0 +#define GPIOB_LCD_XL 1 + +#define GPIOB_TDO 3 +#define GPIOB_TRST 4 +#define GPIOB_PIN5 5 +#define GPIOB_SCL1 6 +#define GPIOB_SDA1 7 +#define GPIOB_DRIVEA 8 +#define GPIOB_DRIVEB 9 +#define GPIOB_SCL2 10 +#define GPIOB_SDA2 11 +#define GPIOB_PIN12 12 +#define GPIOB_SCK2 13 +#define GPIOB_MISO2 14 +#define GPIOB_MOSI2 15 + */ +#define VAL_GPIOB_MODER (PIN_MODE_INPUT(GPIOB_LCD_YD) | \ + PIN_MODE_INPUT(GPIOB_LCD_XL) | \ + PIN_MODE_INPUT(GPIOB_PIN2) | \ + PIN_MODE_ALTERNATE(GPIOB_TDO) | \ + PIN_MODE_ALTERNATE(GPIOB_TRST) | \ + PIN_MODE_INPUT(GPIOB_PIN5) | \ + PIN_MODE_ALTERNATE(GPIOB_SCL1) | \ + PIN_MODE_ALTERNATE(GPIOB_SDA1) | \ + PIN_MODE_INPUT(GPIOB_DRIVEA) | \ + PIN_MODE_INPUT(GPIOB_DRIVEB) | \ + PIN_MODE_ALTERNATE(GPIOB_SCL2) | \ + PIN_MODE_ALTERNATE(GPIOB_SDA2) | \ + PIN_MODE_INPUT(GPIOB_PIN12) | \ + PIN_MODE_ALTERNATE(GPIOB_SCK2) | \ + PIN_MODE_ALTERNATE(GPIOB_MISO2) | \ + PIN_MODE_ALTERNATE(GPIOB_MOSI2)) +#define VAL_GPIOB_OTYPER (PIN_OTYPE_PUSHPULL(GPIOB_LCD_YD) | \ + PIN_OTYPE_PUSHPULL(GPIOB_LCD_XL) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_TDO) | \ + PIN_OTYPE_PUSHPULL(GPIOB_TRST) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN5) | \ + PIN_OTYPE_OPENDRAIN(GPIOB_SCL1) | \ + PIN_OTYPE_OPENDRAIN(GPIOB_SDA1) | \ + PIN_OTYPE_PUSHPULL(GPIOB_DRIVEA) | \ + PIN_OTYPE_PUSHPULL(GPIOB_DRIVEB) | \ + PIN_OTYPE_OPENDRAIN(GPIOB_SCL2) | \ + PIN_OTYPE_OPENDRAIN(GPIOB_SDA2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOB_SCK2 ) | \ + PIN_OTYPE_PUSHPULL(GPIOB_MISO2) | \ + PIN_OTYPE_PUSHPULL(GPIOB_MOSI2)) +#define VAL_GPIOB_OSPEEDR (PIN_OSPEED_100M(GPIOB_PIN0) | \ + PIN_OSPEED_100M(GPIOB_PIN1) | \ + PIN_OSPEED_100M(GPIOB_PIN2) | \ + PIN_OSPEED_100M(GPIOB_SWO) | \ + PIN_OSPEED_100M(GPIOB_PIN4) | \ + PIN_OSPEED_100M(GPIOB_PIN5) | \ + PIN_OSPEED_100M(GPIOB_SCL) | \ + PIN_OSPEED_100M(GPIOB_PIN7) | \ + PIN_OSPEED_100M(GPIOB_PIN8) | \ + PIN_OSPEED_100M(GPIOB_SDA) | \ + PIN_OSPEED_100M(GPIOB_CLK_IN) | \ + PIN_OSPEED_100M(GPIOB_PIN11) | \ + PIN_OSPEED_100M(GPIOB_PIN12) | \ + PIN_OSPEED_100M(GPIOB_PIN13) | \ + PIN_OSPEED_100M(GPIOB_PIN14) | \ + PIN_OSPEED_100M(GPIOB_PIN15)) +#define VAL_GPIOB_PUPDR (PIN_PUPDR_PULLUP(GPIOB_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOB_SWO) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOB_SCL) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOB_SDA) | \ + PIN_PUPDR_PULLUP(GPIOB_CLK_IN) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN11) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN12) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN13) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOB_PIN15)) +#define VAL_GPIOB_ODR (PIN_ODR_HIGH(GPIOB_PIN0) | \ + PIN_ODR_HIGH(GPIOB_PIN1) | \ + PIN_ODR_HIGH(GPIOB_PIN2) | \ + PIN_ODR_HIGH(GPIOB_SWO) | \ + PIN_ODR_HIGH(GPIOB_PIN4) | \ + PIN_ODR_HIGH(GPIOB_PIN5) | \ + PIN_ODR_HIGH(GPIOB_SCL) | \ + PIN_ODR_HIGH(GPIOB_PIN7) | \ + PIN_ODR_HIGH(GPIOB_PIN8) | \ + PIN_ODR_HIGH(GPIOB_SDA) | \ + PIN_ODR_HIGH(GPIOB_CLK_IN) | \ + PIN_ODR_HIGH(GPIOB_PIN11) | \ + PIN_ODR_HIGH(GPIOB_PIN12) | \ + PIN_ODR_HIGH(GPIOB_PIN13) | \ + PIN_ODR_HIGH(GPIOB_PIN14) | \ + PIN_ODR_HIGH(GPIOB_PIN15)) +#define VAL_GPIOB_AFRL (PIN_AFIO_AF(GPIOB_PIN0, 0) | \ + PIN_AFIO_AF(GPIOB_PIN1, 0) | \ + PIN_AFIO_AF(GPIOB_PIN2, 0) | \ + PIN_AFIO_AF(GPIOB_SWO, 0) | \ + PIN_AFIO_AF(GPIOB_PIN4, 0) | \ + PIN_AFIO_AF(GPIOB_PIN5, 0) | \ + PIN_AFIO_AF(GPIOB_SCL, 4) | \ + PIN_AFIO_AF(GPIOB_PIN7, 0)) +#define VAL_GPIOB_AFRH (PIN_AFIO_AF(GPIOB_PIN8, 0) | \ + PIN_AFIO_AF(GPIOB_SDA, 4) | \ + PIN_AFIO_AF(GPIOB_CLK_IN, 0) | \ + PIN_AFIO_AF(GPIOB_PIN11, 0) | \ + PIN_AFIO_AF(GPIOB_PIN12, 0) | \ + PIN_AFIO_AF(GPIOB_PIN13, 0) | \ + PIN_AFIO_AF(GPIOB_PIN14, 0) | \ + PIN_AFIO_AF(GPIOB_PIN15, 0)) + +/* + * GPIOC setup: + * + * PC0 - OTG_FS_POWER_ON (output pushpull maximum). + * PC1 - PIN1 (input pullup). + * PC2 - PIN2 (input pullup). + * PC3 - PDM_OUT (input pullup). + * PC4 - PIN4 (input pullup). + * PC5 - PIN5 (input pullup). + * PC6 - PIN6 (input pullup). + * PC7 - MCLK (alternate 6). + * PC8 - PIN8 (input pullup). + * PC9 - PIN9 (input pullup). + * PC10 - SCLK (alternate 6). + * PC11 - PIN11 (input pullup). + * PC12 - SDIN (alternate 6). + * PC13 - PIN13 (input pullup). + * PC14 - PIN14 (input pullup). + * PC15 - PIN15 (input pullup). + */ +#define VAL_GPIOC_MODER (PIN_MODE_OUTPUT(GPIOC_OTG_FS_POWER_ON) |\ + PIN_MODE_INPUT(GPIOC_PIN1) | \ + PIN_MODE_INPUT(GPIOC_PIN2) | \ + PIN_MODE_INPUT(GPIOC_PDM_OUT) | \ + PIN_MODE_INPUT(GPIOC_PIN4) | \ + PIN_MODE_INPUT(GPIOC_PIN5) | \ + PIN_MODE_INPUT(GPIOC_PIN6) | \ + PIN_MODE_ALTERNATE(GPIOC_MCLK) | \ + PIN_MODE_INPUT(GPIOC_PIN8) | \ + PIN_MODE_INPUT(GPIOC_PIN9) | \ + PIN_MODE_ALTERNATE(GPIOC_SCLK) | \ + PIN_MODE_INPUT(GPIOC_PIN11) | \ + PIN_MODE_ALTERNATE(GPIOC_SDIN) | \ + PIN_MODE_INPUT(GPIOC_PIN13) | \ + PIN_MODE_INPUT(GPIOC_PIN14) | \ + PIN_MODE_INPUT(GPIOC_PIN15)) +#define VAL_GPIOC_OTYPER (PIN_OTYPE_PUSHPULL(GPIOC_OTG_FS_POWER_ON) |\ + PIN_OTYPE_PUSHPULL(GPIOC_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PDM_OUT) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOC_MCLK) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOC_SCLK) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOC_SDIN) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOC_PIN15)) +#define VAL_GPIOC_OSPEEDR (PIN_OSPEED_100M(GPIOC_OTG_FS_POWER_ON) |\ + PIN_OSPEED_100M(GPIOC_PIN1) | \ + PIN_OSPEED_100M(GPIOC_PIN2) | \ + PIN_OSPEED_100M(GPIOC_PDM_OUT) | \ + PIN_OSPEED_100M(GPIOC_PIN4) | \ + PIN_OSPEED_100M(GPIOC_PIN5) | \ + PIN_OSPEED_100M(GPIOC_PIN6) | \ + PIN_OSPEED_100M(GPIOC_MCLK) | \ + PIN_OSPEED_100M(GPIOC_PIN8) | \ + PIN_OSPEED_100M(GPIOC_PIN9) | \ + PIN_OSPEED_100M(GPIOC_SCLK) | \ + PIN_OSPEED_100M(GPIOC_PIN11) | \ + PIN_OSPEED_100M(GPIOC_SDIN) | \ + PIN_OSPEED_100M(GPIOC_PIN13) | \ + PIN_OSPEED_100M(GPIOC_PIN14) | \ + PIN_OSPEED_100M(GPIOC_PIN15)) +#define VAL_GPIOC_PUPDR (PIN_PUPDR_FLOATING(GPIOC_OTG_FS_POWER_ON) |\ + PIN_PUPDR_PULLUP(GPIOC_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOC_PDM_OUT) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN4) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN5) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOC_MCLK) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOC_SCLK) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOC_SDIN) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN13) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN14) | \ + PIN_PUPDR_PULLUP(GPIOC_PIN15)) +#define VAL_GPIOC_ODR (PIN_ODR_HIGH(GPIOC_OTG_FS_POWER_ON) | \ + PIN_ODR_HIGH(GPIOC_PIN1) | \ + PIN_ODR_HIGH(GPIOC_PIN2) | \ + PIN_ODR_HIGH(GPIOC_PDM_OUT) | \ + PIN_ODR_HIGH(GPIOC_PIN4) | \ + PIN_ODR_HIGH(GPIOC_PIN5) | \ + PIN_ODR_HIGH(GPIOC_PIN6) | \ + PIN_ODR_HIGH(GPIOC_MCLK) | \ + PIN_ODR_HIGH(GPIOC_PIN8) | \ + PIN_ODR_HIGH(GPIOC_PIN9) | \ + PIN_ODR_HIGH(GPIOC_SCLK) | \ + PIN_ODR_HIGH(GPIOC_PIN11) | \ + PIN_ODR_HIGH(GPIOC_SDIN) | \ + PIN_ODR_HIGH(GPIOC_PIN13) | \ + PIN_ODR_HIGH(GPIOC_PIN14) | \ + PIN_ODR_HIGH(GPIOC_PIN15)) +#define VAL_GPIOC_AFRL (PIN_AFIO_AF(GPIOC_OTG_FS_POWER_ON, 0) |\ + PIN_AFIO_AF(GPIOC_PIN1, 0) | \ + PIN_AFIO_AF(GPIOC_PIN2, 0) | \ + PIN_AFIO_AF(GPIOC_PDM_OUT, 0) | \ + PIN_AFIO_AF(GPIOC_PIN4, 0) | \ + PIN_AFIO_AF(GPIOC_PIN5, 0) | \ + PIN_AFIO_AF(GPIOC_PIN6, 0) | \ + PIN_AFIO_AF(GPIOC_MCLK, 6)) +#define VAL_GPIOC_AFRH (PIN_AFIO_AF(GPIOC_PIN8, 0) | \ + PIN_AFIO_AF(GPIOC_PIN9, 0) | \ + PIN_AFIO_AF(GPIOC_SCLK, 6) | \ + PIN_AFIO_AF(GPIOC_PIN11, 0) | \ + PIN_AFIO_AF(GPIOC_SDIN, 6) | \ + PIN_AFIO_AF(GPIOC_PIN13, 0) | \ + PIN_AFIO_AF(GPIOC_PIN14, 0) | \ + PIN_AFIO_AF(GPIOC_PIN15, 0)) + +/* + * GPIOD setup: + * + * PD0 - PIN0 (input pullup). + * PD1 - PIN1 (input pullup). + * PD2 - PIN2 (input pullup). + * PD3 - PIN3 (input pullup). + * PD4 - RESET (output pushpull maximum). + * PD5 - OVER_CURRENT (input floating). + * PD6 - PIN6 (input pullup). + * PD7 - PIN7 (input pullup). + * PD8 - PIN8 (input pullup). + * PD9 - PIN9 (input pullup). + * PD10 - PIN10 (input pullup). + * PD11 - PIN11 (input pullup). + * PD12 - LED4 (output pushpull maximum). + * PD13 - LED3 (output pushpull maximum). + * PD14 - LED5 (output pushpull maximum). + * PD15 - LED6 (output pushpull maximum). + */ +#define VAL_GPIOD_MODER (PIN_MODE_INPUT(GPIOD_PIN0) | \ + PIN_MODE_INPUT(GPIOD_PIN1) | \ + PIN_MODE_INPUT(GPIOD_PIN2) | \ + PIN_MODE_INPUT(GPIOD_PIN3) | \ + PIN_MODE_OUTPUT(GPIOD_RESET) | \ + PIN_MODE_INPUT(GPIOD_OVER_CURRENT) | \ + PIN_MODE_INPUT(GPIOD_PIN6) | \ + PIN_MODE_INPUT(GPIOD_PIN7) | \ + PIN_MODE_INPUT(GPIOD_PIN8) | \ + PIN_MODE_INPUT(GPIOD_PIN9) | \ + PIN_MODE_INPUT(GPIOD_PIN10) | \ + PIN_MODE_INPUT(GPIOD_PIN11) | \ + PIN_MODE_OUTPUT(GPIOD_LED4) | \ + PIN_MODE_OUTPUT(GPIOD_LED3) | \ + PIN_MODE_OUTPUT(GPIOD_LED5) | \ + PIN_MODE_OUTPUT(GPIOD_LED6)) +#define VAL_GPIOD_OTYPER (PIN_OTYPE_PUSHPULL(GPIOD_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOD_RESET) | \ + PIN_OTYPE_PUSHPULL(GPIOD_OVER_CURRENT) |\ + PIN_OTYPE_PUSHPULL(GPIOD_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOD_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOD_LED4) | \ + PIN_OTYPE_PUSHPULL(GPIOD_LED3) | \ + PIN_OTYPE_PUSHPULL(GPIOD_LED5) | \ + PIN_OTYPE_PUSHPULL(GPIOD_LED6)) +#define VAL_GPIOD_OSPEEDR (PIN_OSPEED_100M(GPIOD_PIN0) | \ + PIN_OSPEED_100M(GPIOD_PIN1) | \ + PIN_OSPEED_100M(GPIOD_PIN2) | \ + PIN_OSPEED_100M(GPIOD_PIN3) | \ + PIN_OSPEED_100M(GPIOD_RESET) | \ + PIN_OSPEED_100M(GPIOD_OVER_CURRENT) | \ + PIN_OSPEED_100M(GPIOD_PIN6) | \ + PIN_OSPEED_100M(GPIOD_PIN7) | \ + PIN_OSPEED_100M(GPIOD_PIN8) | \ + PIN_OSPEED_100M(GPIOD_PIN9) | \ + PIN_OSPEED_100M(GPIOD_PIN10) | \ + PIN_OSPEED_100M(GPIOD_PIN11) | \ + PIN_OSPEED_100M(GPIOD_LED4) | \ + PIN_OSPEED_100M(GPIOD_LED3) | \ + PIN_OSPEED_100M(GPIOD_LED5) | \ + PIN_OSPEED_100M(GPIOD_LED6)) +#define VAL_GPIOD_PUPDR (PIN_PUPDR_PULLUP(GPIOD_PIN0) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN1) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN2) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOD_RESET) | \ + PIN_PUPDR_FLOATING(GPIOD_OVER_CURRENT) |\ + PIN_PUPDR_PULLUP(GPIOD_PIN6) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN7) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN8) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN9) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN10) | \ + PIN_PUPDR_PULLUP(GPIOD_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOD_LED4) | \ + PIN_PUPDR_FLOATING(GPIOD_LED3) | \ + PIN_PUPDR_FLOATING(GPIOD_LED5) | \ + PIN_PUPDR_FLOATING(GPIOD_LED6)) +#define VAL_GPIOD_ODR (PIN_ODR_HIGH(GPIOD_PIN0) | \ + PIN_ODR_HIGH(GPIOD_PIN1) | \ + PIN_ODR_HIGH(GPIOD_PIN2) | \ + PIN_ODR_HIGH(GPIOD_PIN3) | \ + PIN_ODR_HIGH(GPIOD_RESET) | \ + PIN_ODR_HIGH(GPIOD_OVER_CURRENT) | \ + PIN_ODR_HIGH(GPIOD_PIN6) | \ + PIN_ODR_HIGH(GPIOD_PIN7) | \ + PIN_ODR_HIGH(GPIOD_PIN8) | \ + PIN_ODR_HIGH(GPIOD_PIN9) | \ + PIN_ODR_HIGH(GPIOD_PIN10) | \ + PIN_ODR_HIGH(GPIOD_PIN11) | \ + PIN_ODR_LOW(GPIOD_LED4) | \ + PIN_ODR_LOW(GPIOD_LED3) | \ + PIN_ODR_LOW(GPIOD_LED5) | \ + PIN_ODR_LOW(GPIOD_LED6)) +#define VAL_GPIOD_AFRL (PIN_AFIO_AF(GPIOD_PIN0, 0) | \ + PIN_AFIO_AF(GPIOD_PIN1, 0) | \ + PIN_AFIO_AF(GPIOD_PIN2, 0) | \ + PIN_AFIO_AF(GPIOD_PIN3, 0) | \ + PIN_AFIO_AF(GPIOD_RESET, 0) | \ + PIN_AFIO_AF(GPIOD_OVER_CURRENT, 0) | \ + PIN_AFIO_AF(GPIOD_PIN6, 0) | \ + PIN_AFIO_AF(GPIOD_PIN7, 0)) +#define VAL_GPIOD_AFRH (PIN_AFIO_AF(GPIOD_PIN8, 0) | \ + PIN_AFIO_AF(GPIOD_PIN9, 0) | \ + PIN_AFIO_AF(GPIOD_PIN10, 0) | \ + PIN_AFIO_AF(GPIOD_PIN11, 0) | \ + PIN_AFIO_AF(GPIOD_LED4, 0) | \ + PIN_AFIO_AF(GPIOD_LED3, 0) | \ + PIN_AFIO_AF(GPIOD_LED5, 0) | \ + PIN_AFIO_AF(GPIOD_LED6, 0)) + +/* + * GPIOE setup: + * + * PE0 - INT1 (input floating). + * PE1 - INT2 (input floating). + * PE2 - PIN2 (input floating). + * PE3 - CS_SPI (output pushpull maximum). + * PE4 - PIN4 (input floating). + * PE5 - PIN5 (input floating). + * PE6 - PIN6 (input floating). + * PE7 - PIN7 (input floating). + * PE8 - PIN8 (input floating). + * PE9 - PIN9 (input floating). + * PE10 - PIN10 (input floating). + * PE11 - PIN11 (input floating). + * PE12 - PIN12 (input floating). + * PE13 - PIN13 (input floating). + * PE14 - PIN14 (input floating). + * PE15 - PIN15 (input floating). + */ +#define VAL_GPIOE_MODER (PIN_MODE_INPUT(GPIOE_INT1) | \ + PIN_MODE_INPUT(GPIOE_INT2) | \ + PIN_MODE_INPUT(GPIOE_PIN2) | \ + PIN_MODE_OUTPUT(GPIOE_CS_SPI) | \ + PIN_MODE_INPUT(GPIOE_PIN4) | \ + PIN_MODE_INPUT(GPIOE_PIN5) | \ + PIN_MODE_INPUT(GPIOE_PIN6) | \ + PIN_MODE_INPUT(GPIOE_PIN7) | \ + PIN_MODE_INPUT(GPIOE_PIN8) | \ + PIN_MODE_INPUT(GPIOE_PIN9) | \ + PIN_MODE_INPUT(GPIOE_PIN10) | \ + PIN_MODE_INPUT(GPIOE_PIN11) | \ + PIN_MODE_INPUT(GPIOE_PIN12) | \ + PIN_MODE_INPUT(GPIOE_PIN13) | \ + PIN_MODE_INPUT(GPIOE_PIN14) | \ + PIN_MODE_INPUT(GPIOE_PIN15)) +#define VAL_GPIOE_OTYPER (PIN_OTYPE_PUSHPULL(GPIOE_INT1) | \ + PIN_OTYPE_PUSHPULL(GPIOE_INT2) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOE_CS_SPI) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOE_PIN15)) +#define VAL_GPIOE_OSPEEDR (PIN_OSPEED_100M(GPIOE_INT1) | \ + PIN_OSPEED_100M(GPIOE_INT2) | \ + PIN_OSPEED_100M(GPIOE_PIN2) | \ + PIN_OSPEED_100M(GPIOE_CS_SPI) | \ + PIN_OSPEED_100M(GPIOE_PIN4) | \ + PIN_OSPEED_100M(GPIOE_PIN5) | \ + PIN_OSPEED_100M(GPIOE_PIN6) | \ + PIN_OSPEED_100M(GPIOE_PIN7) | \ + PIN_OSPEED_100M(GPIOE_PIN8) | \ + PIN_OSPEED_100M(GPIOE_PIN9) | \ + PIN_OSPEED_100M(GPIOE_PIN10) | \ + PIN_OSPEED_100M(GPIOE_PIN11) | \ + PIN_OSPEED_100M(GPIOE_PIN12) | \ + PIN_OSPEED_100M(GPIOE_PIN13) | \ + PIN_OSPEED_100M(GPIOE_PIN14) | \ + PIN_OSPEED_100M(GPIOE_PIN15)) +#define VAL_GPIOE_PUPDR (PIN_PUPDR_FLOATING(GPIOE_INT1) | \ + PIN_PUPDR_FLOATING(GPIOE_INT2) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOE_CS_SPI) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOE_PIN15)) +#define VAL_GPIOE_ODR (PIN_ODR_HIGH(GPIOE_INT1) | \ + PIN_ODR_HIGH(GPIOE_INT2) | \ + PIN_ODR_HIGH(GPIOE_PIN2) | \ + PIN_ODR_HIGH(GPIOE_CS_SPI) | \ + PIN_ODR_HIGH(GPIOE_PIN4) | \ + PIN_ODR_HIGH(GPIOE_PIN5) | \ + PIN_ODR_HIGH(GPIOE_PIN6) | \ + PIN_ODR_HIGH(GPIOE_PIN7) | \ + PIN_ODR_HIGH(GPIOE_PIN8) | \ + PIN_ODR_HIGH(GPIOE_PIN9) | \ + PIN_ODR_HIGH(GPIOE_PIN10) | \ + PIN_ODR_HIGH(GPIOE_PIN11) | \ + PIN_ODR_HIGH(GPIOE_PIN12) | \ + PIN_ODR_HIGH(GPIOE_PIN13) | \ + PIN_ODR_HIGH(GPIOE_PIN14) | \ + PIN_ODR_HIGH(GPIOE_PIN15)) +#define VAL_GPIOE_AFRL (PIN_AFIO_AF(GPIOE_INT1, 0) | \ + PIN_AFIO_AF(GPIOE_INT2, 0) | \ + PIN_AFIO_AF(GPIOE_PIN2, 0) | \ + PIN_AFIO_AF(GPIOE_CS_SPI, 0) | \ + PIN_AFIO_AF(GPIOE_PIN4, 0) | \ + PIN_AFIO_AF(GPIOE_PIN5, 0) | \ + PIN_AFIO_AF(GPIOE_PIN6, 0) | \ + PIN_AFIO_AF(GPIOE_PIN7, 0)) +#define VAL_GPIOE_AFRH (PIN_AFIO_AF(GPIOE_PIN8, 0) | \ + PIN_AFIO_AF(GPIOE_PIN9, 0) | \ + PIN_AFIO_AF(GPIOE_PIN10, 0) | \ + PIN_AFIO_AF(GPIOE_PIN11, 0) | \ + PIN_AFIO_AF(GPIOE_PIN12, 0) | \ + PIN_AFIO_AF(GPIOE_PIN13, 0) | \ + PIN_AFIO_AF(GPIOE_PIN14, 0) | \ + PIN_AFIO_AF(GPIOE_PIN15, 0)) + +/* + * GPIOF setup: + * + * PF0 - PIN0 (input floating). + * PF1 - PIN1 (input floating). + * PF2 - PIN2 (input floating). + * PF3 - PIN3 (input floating). + * PF4 - PIN4 (input floating). + * PF5 - PIN5 (input floating). + * PF6 - PIN6 (input floating). + * PF7 - PIN7 (input floating). + * PF8 - PIN8 (input floating). + * PF9 - PIN9 (input floating). + * PF10 - PIN10 (input floating). + * PF11 - PIN11 (input floating). + * PF12 - PIN12 (input floating). + * PF13 - PIN13 (input floating). + * PF14 - PIN14 (input floating). + * PF15 - PIN15 (input floating). + */ +#define VAL_GPIOF_MODER (PIN_MODE_INPUT(GPIOF_PIN0) | \ + PIN_MODE_INPUT(GPIOF_PIN1) | \ + PIN_MODE_INPUT(GPIOF_PIN2) | \ + PIN_MODE_INPUT(GPIOF_PIN3) | \ + PIN_MODE_INPUT(GPIOF_PIN4) | \ + PIN_MODE_INPUT(GPIOF_PIN5) | \ + PIN_MODE_INPUT(GPIOF_PIN6) | \ + PIN_MODE_INPUT(GPIOF_PIN7) | \ + PIN_MODE_INPUT(GPIOF_PIN8) | \ + PIN_MODE_INPUT(GPIOF_PIN9) | \ + PIN_MODE_INPUT(GPIOF_PIN10) | \ + PIN_MODE_INPUT(GPIOF_PIN11) | \ + PIN_MODE_INPUT(GPIOF_PIN12) | \ + PIN_MODE_INPUT(GPIOF_PIN13) | \ + PIN_MODE_INPUT(GPIOF_PIN14) | \ + PIN_MODE_INPUT(GPIOF_PIN15)) +#define VAL_GPIOF_OTYPER (PIN_OTYPE_PUSHPULL(GPIOF_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOF_PIN15)) +#define VAL_GPIOF_OSPEEDR (PIN_OSPEED_100M(GPIOF_PIN0) | \ + PIN_OSPEED_100M(GPIOF_PIN1) | \ + PIN_OSPEED_100M(GPIOF_PIN2) | \ + PIN_OSPEED_100M(GPIOF_PIN3) | \ + PIN_OSPEED_100M(GPIOF_PIN4) | \ + PIN_OSPEED_100M(GPIOF_PIN5) | \ + PIN_OSPEED_100M(GPIOF_PIN6) | \ + PIN_OSPEED_100M(GPIOF_PIN7) | \ + PIN_OSPEED_100M(GPIOF_PIN8) | \ + PIN_OSPEED_100M(GPIOF_PIN9) | \ + PIN_OSPEED_100M(GPIOF_PIN10) | \ + PIN_OSPEED_100M(GPIOF_PIN11) | \ + PIN_OSPEED_100M(GPIOF_PIN12) | \ + PIN_OSPEED_100M(GPIOF_PIN13) | \ + PIN_OSPEED_100M(GPIOF_PIN14) | \ + PIN_OSPEED_100M(GPIOF_PIN15)) +#define VAL_GPIOF_PUPDR (PIN_PUPDR_FLOATING(GPIOF_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOF_PIN15)) +#define VAL_GPIOF_ODR (PIN_ODR_HIGH(GPIOF_PIN0) | \ + PIN_ODR_HIGH(GPIOF_PIN1) | \ + PIN_ODR_HIGH(GPIOF_PIN2) | \ + PIN_ODR_HIGH(GPIOF_PIN3) | \ + PIN_ODR_HIGH(GPIOF_PIN4) | \ + PIN_ODR_HIGH(GPIOF_PIN5) | \ + PIN_ODR_HIGH(GPIOF_PIN6) | \ + PIN_ODR_HIGH(GPIOF_PIN7) | \ + PIN_ODR_HIGH(GPIOF_PIN8) | \ + PIN_ODR_HIGH(GPIOF_PIN9) | \ + PIN_ODR_HIGH(GPIOF_PIN10) | \ + PIN_ODR_HIGH(GPIOF_PIN11) | \ + PIN_ODR_HIGH(GPIOF_PIN12) | \ + PIN_ODR_HIGH(GPIOF_PIN13) | \ + PIN_ODR_HIGH(GPIOF_PIN14) | \ + PIN_ODR_HIGH(GPIOF_PIN15)) +#define VAL_GPIOF_AFRL (PIN_AFIO_AF(GPIOF_PIN0, 0) | \ + PIN_AFIO_AF(GPIOF_PIN1, 0) | \ + PIN_AFIO_AF(GPIOF_PIN2, 0) | \ + PIN_AFIO_AF(GPIOF_PIN3, 0) | \ + PIN_AFIO_AF(GPIOF_PIN4, 0) | \ + PIN_AFIO_AF(GPIOF_PIN5, 0) | \ + PIN_AFIO_AF(GPIOF_PIN6, 0) | \ + PIN_AFIO_AF(GPIOF_PIN7, 0)) +#define VAL_GPIOF_AFRH (PIN_AFIO_AF(GPIOF_PIN8, 0) | \ + PIN_AFIO_AF(GPIOF_PIN9, 0) | \ + PIN_AFIO_AF(GPIOF_PIN10, 0) | \ + PIN_AFIO_AF(GPIOF_PIN11, 0) | \ + PIN_AFIO_AF(GPIOF_PIN12, 0) | \ + PIN_AFIO_AF(GPIOF_PIN13, 0) | \ + PIN_AFIO_AF(GPIOF_PIN14, 0) | \ + PIN_AFIO_AF(GPIOF_PIN15, 0)) + +/* + * GPIOG setup: + * + * PG0 - PIN0 (input floating). + * PG1 - PIN1 (input floating). + * PG2 - PIN2 (input floating). + * PG3 - PIN3 (input floating). + * PG4 - PIN4 (input floating). + * PG5 - PIN5 (input floating). + * PG6 - PIN6 (input floating). + * PG7 - PIN7 (input floating). + * PG8 - PIN8 (input floating). + * PG9 - PIN9 (input floating). + * PG10 - PIN10 (input floating). + * PG11 - PIN11 (input floating). + * PG12 - PIN12 (input floating). + * PG13 - PIN13 (input floating). + * PG14 - PIN14 (input floating). + * PG15 - PIN15 (input floating). + */ +#define VAL_GPIOG_MODER (PIN_MODE_INPUT(GPIOG_PIN0) | \ + PIN_MODE_INPUT(GPIOG_PIN1) | \ + PIN_MODE_INPUT(GPIOG_PIN2) | \ + PIN_MODE_INPUT(GPIOG_PIN3) | \ + PIN_MODE_INPUT(GPIOG_PIN4) | \ + PIN_MODE_INPUT(GPIOG_PIN5) | \ + PIN_MODE_INPUT(GPIOG_PIN6) | \ + PIN_MODE_INPUT(GPIOG_PIN7) | \ + PIN_MODE_INPUT(GPIOG_PIN8) | \ + PIN_MODE_INPUT(GPIOG_PIN9) | \ + PIN_MODE_INPUT(GPIOG_PIN10) | \ + PIN_MODE_INPUT(GPIOG_PIN11) | \ + PIN_MODE_INPUT(GPIOG_PIN12) | \ + PIN_MODE_INPUT(GPIOG_PIN13) | \ + PIN_MODE_INPUT(GPIOG_PIN14) | \ + PIN_MODE_INPUT(GPIOG_PIN15)) +#define VAL_GPIOG_OTYPER (PIN_OTYPE_PUSHPULL(GPIOG_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOG_PIN15)) +#define VAL_GPIOG_OSPEEDR (PIN_OSPEED_100M(GPIOG_PIN0) | \ + PIN_OSPEED_100M(GPIOG_PIN1) | \ + PIN_OSPEED_100M(GPIOG_PIN2) | \ + PIN_OSPEED_100M(GPIOG_PIN3) | \ + PIN_OSPEED_100M(GPIOG_PIN4) | \ + PIN_OSPEED_100M(GPIOG_PIN5) | \ + PIN_OSPEED_100M(GPIOG_PIN6) | \ + PIN_OSPEED_100M(GPIOG_PIN7) | \ + PIN_OSPEED_100M(GPIOG_PIN8) | \ + PIN_OSPEED_100M(GPIOG_PIN9) | \ + PIN_OSPEED_100M(GPIOG_PIN10) | \ + PIN_OSPEED_100M(GPIOG_PIN11) | \ + PIN_OSPEED_100M(GPIOG_PIN12) | \ + PIN_OSPEED_100M(GPIOG_PIN13) | \ + PIN_OSPEED_100M(GPIOG_PIN14) | \ + PIN_OSPEED_100M(GPIOG_PIN15)) +#define VAL_GPIOG_PUPDR (PIN_PUPDR_FLOATING(GPIOG_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOG_PIN15)) +#define VAL_GPIOG_ODR (PIN_ODR_HIGH(GPIOG_PIN0) | \ + PIN_ODR_HIGH(GPIOG_PIN1) | \ + PIN_ODR_HIGH(GPIOG_PIN2) | \ + PIN_ODR_HIGH(GPIOG_PIN3) | \ + PIN_ODR_HIGH(GPIOG_PIN4) | \ + PIN_ODR_HIGH(GPIOG_PIN5) | \ + PIN_ODR_HIGH(GPIOG_PIN6) | \ + PIN_ODR_HIGH(GPIOG_PIN7) | \ + PIN_ODR_HIGH(GPIOG_PIN8) | \ + PIN_ODR_HIGH(GPIOG_PIN9) | \ + PIN_ODR_HIGH(GPIOG_PIN10) | \ + PIN_ODR_HIGH(GPIOG_PIN11) | \ + PIN_ODR_HIGH(GPIOG_PIN12) | \ + PIN_ODR_HIGH(GPIOG_PIN13) | \ + PIN_ODR_HIGH(GPIOG_PIN14) | \ + PIN_ODR_HIGH(GPIOG_PIN15)) +#define VAL_GPIOG_AFRL (PIN_AFIO_AF(GPIOG_PIN0, 0) | \ + PIN_AFIO_AF(GPIOG_PIN1, 0) | \ + PIN_AFIO_AF(GPIOG_PIN2, 0) | \ + PIN_AFIO_AF(GPIOG_PIN3, 0) | \ + PIN_AFIO_AF(GPIOG_PIN4, 0) | \ + PIN_AFIO_AF(GPIOG_PIN5, 0) | \ + PIN_AFIO_AF(GPIOG_PIN6, 0) | \ + PIN_AFIO_AF(GPIOG_PIN7, 0)) +#define VAL_GPIOG_AFRH (PIN_AFIO_AF(GPIOG_PIN8, 0) | \ + PIN_AFIO_AF(GPIOG_PIN9, 0) | \ + PIN_AFIO_AF(GPIOG_PIN10, 0) | \ + PIN_AFIO_AF(GPIOG_PIN11, 0) | \ + PIN_AFIO_AF(GPIOG_PIN12, 0) | \ + PIN_AFIO_AF(GPIOG_PIN13, 0) | \ + PIN_AFIO_AF(GPIOG_PIN14, 0) | \ + PIN_AFIO_AF(GPIOG_PIN15, 0)) + +/* + * GPIOH setup: + * + * PH0 - OSC_IN (input floating). + * PH1 - OSC_OUT (input floating). + * PH2 - PIN2 (input floating). + * PH3 - PIN3 (input floating). + * PH4 - PIN4 (input floating). + * PH5 - PIN5 (input floating). + * PH6 - PIN6 (input floating). + * PH7 - PIN7 (input floating). + * PH8 - PIN8 (input floating). + * PH9 - PIN9 (input floating). + * PH10 - PIN10 (input floating). + * PH11 - PIN11 (input floating). + * PH12 - PIN12 (input floating). + * PH13 - PIN13 (input floating). + * PH14 - PIN14 (input floating). + * PH15 - PIN15 (input floating). + */ +#define VAL_GPIOH_MODER (PIN_MODE_INPUT(GPIOH_OSC_IN) | \ + PIN_MODE_INPUT(GPIOH_OSC_OUT) | \ + PIN_MODE_INPUT(GPIOH_PIN2) | \ + PIN_MODE_INPUT(GPIOH_PIN3) | \ + PIN_MODE_INPUT(GPIOH_PIN4) | \ + PIN_MODE_INPUT(GPIOH_PIN5) | \ + PIN_MODE_INPUT(GPIOH_PIN6) | \ + PIN_MODE_INPUT(GPIOH_PIN7) | \ + PIN_MODE_INPUT(GPIOH_PIN8) | \ + PIN_MODE_INPUT(GPIOH_PIN9) | \ + PIN_MODE_INPUT(GPIOH_PIN10) | \ + PIN_MODE_INPUT(GPIOH_PIN11) | \ + PIN_MODE_INPUT(GPIOH_PIN12) | \ + PIN_MODE_INPUT(GPIOH_PIN13) | \ + PIN_MODE_INPUT(GPIOH_PIN14) | \ + PIN_MODE_INPUT(GPIOH_PIN15)) +#define VAL_GPIOH_OTYPER (PIN_OTYPE_PUSHPULL(GPIOH_OSC_IN) | \ + PIN_OTYPE_PUSHPULL(GPIOH_OSC_OUT) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOH_PIN15)) +#define VAL_GPIOH_OSPEEDR (PIN_OSPEED_100M(GPIOH_OSC_IN) | \ + PIN_OSPEED_100M(GPIOH_OSC_OUT) | \ + PIN_OSPEED_100M(GPIOH_PIN2) | \ + PIN_OSPEED_100M(GPIOH_PIN3) | \ + PIN_OSPEED_100M(GPIOH_PIN4) | \ + PIN_OSPEED_100M(GPIOH_PIN5) | \ + PIN_OSPEED_100M(GPIOH_PIN6) | \ + PIN_OSPEED_100M(GPIOH_PIN7) | \ + PIN_OSPEED_100M(GPIOH_PIN8) | \ + PIN_OSPEED_100M(GPIOH_PIN9) | \ + PIN_OSPEED_100M(GPIOH_PIN10) | \ + PIN_OSPEED_100M(GPIOH_PIN11) | \ + PIN_OSPEED_100M(GPIOH_PIN12) | \ + PIN_OSPEED_100M(GPIOH_PIN13) | \ + PIN_OSPEED_100M(GPIOH_PIN14) | \ + PIN_OSPEED_100M(GPIOH_PIN15)) +#define VAL_GPIOH_PUPDR (PIN_PUPDR_FLOATING(GPIOH_OSC_IN) | \ + PIN_PUPDR_FLOATING(GPIOH_OSC_OUT) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOH_PIN15)) +#define VAL_GPIOH_ODR (PIN_ODR_HIGH(GPIOH_OSC_IN) | \ + PIN_ODR_HIGH(GPIOH_OSC_OUT) | \ + PIN_ODR_HIGH(GPIOH_PIN2) | \ + PIN_ODR_HIGH(GPIOH_PIN3) | \ + PIN_ODR_HIGH(GPIOH_PIN4) | \ + PIN_ODR_HIGH(GPIOH_PIN5) | \ + PIN_ODR_HIGH(GPIOH_PIN6) | \ + PIN_ODR_HIGH(GPIOH_PIN7) | \ + PIN_ODR_HIGH(GPIOH_PIN8) | \ + PIN_ODR_HIGH(GPIOH_PIN9) | \ + PIN_ODR_HIGH(GPIOH_PIN10) | \ + PIN_ODR_HIGH(GPIOH_PIN11) | \ + PIN_ODR_HIGH(GPIOH_PIN12) | \ + PIN_ODR_HIGH(GPIOH_PIN13) | \ + PIN_ODR_HIGH(GPIOH_PIN14) | \ + PIN_ODR_HIGH(GPIOH_PIN15)) +#define VAL_GPIOH_AFRL (PIN_AFIO_AF(GPIOH_OSC_IN, 0) | \ + PIN_AFIO_AF(GPIOH_OSC_OUT, 0) | \ + PIN_AFIO_AF(GPIOH_PIN2, 0) | \ + PIN_AFIO_AF(GPIOH_PIN3, 0) | \ + PIN_AFIO_AF(GPIOH_PIN4, 0) | \ + PIN_AFIO_AF(GPIOH_PIN5, 0) | \ + PIN_AFIO_AF(GPIOH_PIN6, 0) | \ + PIN_AFIO_AF(GPIOH_PIN7, 0)) +#define VAL_GPIOH_AFRH (PIN_AFIO_AF(GPIOH_PIN8, 0) | \ + PIN_AFIO_AF(GPIOH_PIN9, 0) | \ + PIN_AFIO_AF(GPIOH_PIN10, 0) | \ + PIN_AFIO_AF(GPIOH_PIN11, 0) | \ + PIN_AFIO_AF(GPIOH_PIN12, 0) | \ + PIN_AFIO_AF(GPIOH_PIN13, 0) | \ + PIN_AFIO_AF(GPIOH_PIN14, 0) | \ + PIN_AFIO_AF(GPIOH_PIN15, 0)) + +/* + * GPIOI setup: + * + * PI0 - PIN0 (input floating). + * PI1 - PIN1 (input floating). + * PI2 - PIN2 (input floating). + * PI3 - PIN3 (input floating). + * PI4 - PIN4 (input floating). + * PI5 - PIN5 (input floating). + * PI6 - PIN6 (input floating). + * PI7 - PIN7 (input floating). + * PI8 - PIN8 (input floating). + * PI9 - PIN9 (input floating). + * PI10 - PIN10 (input floating). + * PI11 - PIN11 (input floating). + * PI12 - PIN12 (input floating). + * PI13 - PIN13 (input floating). + * PI14 - PIN14 (input floating). + * PI15 - PIN15 (input floating). + */ +#define VAL_GPIOI_MODER (PIN_MODE_INPUT(GPIOI_PIN0) | \ + PIN_MODE_INPUT(GPIOI_PIN1) | \ + PIN_MODE_INPUT(GPIOI_PIN2) | \ + PIN_MODE_INPUT(GPIOI_PIN3) | \ + PIN_MODE_INPUT(GPIOI_PIN4) | \ + PIN_MODE_INPUT(GPIOI_PIN5) | \ + PIN_MODE_INPUT(GPIOI_PIN6) | \ + PIN_MODE_INPUT(GPIOI_PIN7) | \ + PIN_MODE_INPUT(GPIOI_PIN8) | \ + PIN_MODE_INPUT(GPIOI_PIN9) | \ + PIN_MODE_INPUT(GPIOI_PIN10) | \ + PIN_MODE_INPUT(GPIOI_PIN11) | \ + PIN_MODE_INPUT(GPIOI_PIN12) | \ + PIN_MODE_INPUT(GPIOI_PIN13) | \ + PIN_MODE_INPUT(GPIOI_PIN14) | \ + PIN_MODE_INPUT(GPIOI_PIN15)) +#define VAL_GPIOI_OTYPER (PIN_OTYPE_PUSHPULL(GPIOI_PIN0) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN1) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN2) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN3) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN4) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN5) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN6) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN7) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN8) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN9) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN10) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN11) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN12) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN13) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN14) | \ + PIN_OTYPE_PUSHPULL(GPIOI_PIN15)) +#define VAL_GPIOI_OSPEEDR (PIN_OSPEED_100M(GPIOI_PIN0) | \ + PIN_OSPEED_100M(GPIOI_PIN1) | \ + PIN_OSPEED_100M(GPIOI_PIN2) | \ + PIN_OSPEED_100M(GPIOI_PIN3) | \ + PIN_OSPEED_100M(GPIOI_PIN4) | \ + PIN_OSPEED_100M(GPIOI_PIN5) | \ + PIN_OSPEED_100M(GPIOI_PIN6) | \ + PIN_OSPEED_100M(GPIOI_PIN7) | \ + PIN_OSPEED_100M(GPIOI_PIN8) | \ + PIN_OSPEED_100M(GPIOI_PIN9) | \ + PIN_OSPEED_100M(GPIOI_PIN10) | \ + PIN_OSPEED_100M(GPIOI_PIN11) | \ + PIN_OSPEED_100M(GPIOI_PIN12) | \ + PIN_OSPEED_100M(GPIOI_PIN13) | \ + PIN_OSPEED_100M(GPIOI_PIN14) | \ + PIN_OSPEED_100M(GPIOI_PIN15)) +#define VAL_GPIOI_PUPDR (PIN_PUPDR_FLOATING(GPIOI_PIN0) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN1) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN2) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN3) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN4) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN5) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN6) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN7) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN8) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN9) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN10) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN11) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN12) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN13) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN14) | \ + PIN_PUPDR_FLOATING(GPIOI_PIN15)) +#define VAL_GPIOI_ODR (PIN_ODR_HIGH(GPIOI_PIN0) | \ + PIN_ODR_HIGH(GPIOI_PIN1) | \ + PIN_ODR_HIGH(GPIOI_PIN2) | \ + PIN_ODR_HIGH(GPIOI_PIN3) | \ + PIN_ODR_HIGH(GPIOI_PIN4) | \ + PIN_ODR_HIGH(GPIOI_PIN5) | \ + PIN_ODR_HIGH(GPIOI_PIN6) | \ + PIN_ODR_HIGH(GPIOI_PIN7) | \ + PIN_ODR_HIGH(GPIOI_PIN8) | \ + PIN_ODR_HIGH(GPIOI_PIN9) | \ + PIN_ODR_HIGH(GPIOI_PIN10) | \ + PIN_ODR_HIGH(GPIOI_PIN11) | \ + PIN_ODR_HIGH(GPIOI_PIN12) | \ + PIN_ODR_HIGH(GPIOI_PIN13) | \ + PIN_ODR_HIGH(GPIOI_PIN14) | \ + PIN_ODR_HIGH(GPIOI_PIN15)) +#define VAL_GPIOI_AFRL (PIN_AFIO_AF(GPIOI_PIN0, 0) | \ + PIN_AFIO_AF(GPIOI_PIN1, 0) | \ + PIN_AFIO_AF(GPIOI_PIN2, 0) | \ + PIN_AFIO_AF(GPIOI_PIN3, 0) | \ + PIN_AFIO_AF(GPIOI_PIN4, 0) | \ + PIN_AFIO_AF(GPIOI_PIN5, 0) | \ + PIN_AFIO_AF(GPIOI_PIN6, 0) | \ + PIN_AFIO_AF(GPIOI_PIN7, 0)) +#define VAL_GPIOI_AFRH (PIN_AFIO_AF(GPIOI_PIN8, 0) | \ + PIN_AFIO_AF(GPIOI_PIN9, 0) | \ + PIN_AFIO_AF(GPIOI_PIN10, 0) | \ + PIN_AFIO_AF(GPIOI_PIN11, 0) | \ + PIN_AFIO_AF(GPIOI_PIN12, 0) | \ + PIN_AFIO_AF(GPIOI_PIN13, 0) | \ + PIN_AFIO_AF(GPIOI_PIN14, 0) | \ + PIN_AFIO_AF(GPIOI_PIN15, 0)) + + +#if !defined(_FROM_ASM_) +#ifdef __cplusplus +extern "C" { +#endif + void boardInit(void); +#ifdef __cplusplus +} +#endif +#endif /* _FROM_ASM_ */ + +#endif /* _BOARD_H_ */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/cfg/board.chcfg b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/cfg/board.chcfg new file mode 100644 index 00000000..a5593446 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/cfg/board.chcfg @@ -0,0 +1,1186 @@ + + + + + resources/gencfg/processors/boards/stm32f4xx/templates + .. + + mikromedia STM32-M4 + MIKROE_MIKROMEDIA_M4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.c b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.c new file mode 100644 index 00000000..1965ba35 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.c @@ -0,0 +1,125 @@ +#include "hal.h" +#include "flash_memory.h" + +static const unsigned short _SERIAL_FLASH_CMD_RDID = 0x9F; // 25P80 +static const unsigned short _SERIAL_FLASH_CMD_READ = 0x03; +static const unsigned short _SERIAL_FLASH_CMD_WRITE = 0x02; +static const unsigned short _SERIAL_FLASH_CMD_WREN = 0x06; +static const unsigned short _SERIAL_FLASH_CMD_RDSR = 0x05; +static const unsigned short _SERIAL_FLASH_CMD_ERASE = 0xC7; // 25P80 +static const unsigned short _SERIAL_FLASH_CMD_EWSR = 0x06; // 25P80 +static const unsigned short _SERIAL_FLASH_CMD_WRSR = 0x01; +static const unsigned short _SERIAL_FLASH_CMD_SER = 0xD8; //25P80 + +static const SPIConfig flash_spicfg = { + NULL, + GPIOD, + GPIOD_FLASH_CS, + 0 +}; + +bool flash_is_write_busy(void) { + static uint8_t is_write_busy_cmd[1]; + is_write_busy_cmd[0] = _SERIAL_FLASH_CMD_RDSR; + + uint8_t result[1]; + + spiAcquireBus(&SPID3); + spiStart(&SPID3, &flash_spicfg); + spiSelect(&SPID3); + spiSend(&SPID3, sizeof(is_write_busy_cmd), is_write_busy_cmd); + spiReceive(&SPID3, sizeof(result), result); + spiUnselect(&SPID3); + spiReleaseBus(&SPID3); + + return result[0]&0x01; +} + +void flash_write_enable(void) { + spiAcquireBus(&SPID3); + spiStart(&SPID3, &flash_spicfg); + spiSelect(&SPID3); + spiSend(&SPID3, 1, &_SERIAL_FLASH_CMD_WREN); + spiUnselect(&SPID3); + spiReleaseBus(&SPID3); +} + +void flash_sector_erase(uint32_t sector) { + flash_write_enable(); + static uint8_t sector_erase_cmd[4]; + sector_erase_cmd[0] = _SERIAL_FLASH_CMD_SER; + sector_erase_cmd[1] = (sector >> 16) & 0xFF; + sector_erase_cmd[2] = (sector >> 8) & 0xFF; + sector_erase_cmd[3] = sector & 0xFF; + + + spiAcquireBus(&SPID3); + spiStart(&SPID3, &flash_spicfg); + spiSelect(&SPID3); + spiSend(&SPID3, sizeof(sector_erase_cmd), sector_erase_cmd); + spiUnselect(&SPID3); + spiReleaseBus(&SPID3); + + /* wait for complete */ + while(flash_is_write_busy()); +} + +void flash_read(uint32_t address, size_t bytes, uint8_t *out) { + static uint8_t sector_read_cmd[4]; + sector_read_cmd[0] = _SERIAL_FLASH_CMD_READ; + sector_read_cmd[1] = (address >> 16) & 0xFF; + sector_read_cmd[2] = (address >> 8) & 0xFF; + sector_read_cmd[3] = address & 0xFF; + uint8_t dummy[1]; + + spiAcquireBus(&SPID3); + spiStart(&SPID3, &flash_spicfg); + spiSelect(&SPID3); + spiSend(&SPID3, sizeof(sector_read_cmd), sector_read_cmd); + spiReceive(&SPID3, bytes, out); + spiUnselect(&SPID3); + spiReleaseBus(&SPID3); +} + +void flash_write(uint32_t address, size_t bytes, uint8_t *data) { + static uint8_t flash_write_cmd[4]; + + flash_write_enable(); + + flash_write_cmd[0] = _SERIAL_FLASH_CMD_WRITE; + flash_write_cmd[1] = (address >> 16) & 0xFF; + flash_write_cmd[2] = (address >> 8) & 0xFF; + flash_write_cmd[3] = address & 0xFF; + uint8_t dummy[1]; + + spiAcquireBus(&SPID3); + spiStart(&SPID3, &flash_spicfg); + spiSelect(&SPID3); + spiSend(&SPID3, sizeof(flash_write_cmd), flash_write_cmd); + spiSend(&SPID3, bytes, data); + spiUnselect(&SPID3); + spiReleaseBus(&SPID3); + + /* wait for complete */ + while(flash_is_write_busy()); +} + +bool flash_tp_calibrated(void) { + uint8_t out[1]; + flash_read(0x0F0000, 1, out); + + return (out[0] == 0x01); +} + +void flash_tp_calibration_save(uint16_t instance, const uint8_t *calbuf, size_t sz) { + flash_sector_erase(0x0F0000); + uint8_t calibrated = 0x01; + flash_write(0x0F0000, 1, &calibrated); + flash_write(0x0F0001, sz, calbuf); +} +const char *flash_tp_calibration_load(uint16_t instance) { + static char foo[24]; + flash_read(0x0F0001, 24, foo); + + return foo; +} \ No newline at end of file diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.h b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.h new file mode 100644 index 00000000..5be7523f --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.h @@ -0,0 +1,6 @@ +void flash_sector_erase(uint32_t sector); +void flash_read(uint32_t address, size_t bytes, uint8_t *out); +void flash_write(uint32_t address, size_t bytes, uint8_t *data); +bool flash_tp_calibrated(void); +void flash_tp_calibration_save(uint16_t instance, const uint8_t *calbuf, size_t sz); +const char *flash_tp_calibration_load(uint16_t instance); \ No newline at end of file diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/board.mk b/boards/base/Mikromedia-STM32-M4-ILI9341/board.mk new file mode 100644 index 00000000..e466621c --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/board.mk @@ -0,0 +1,5 @@ +GFXINC += $(GFXLIB)/boards/base/Mikromedia-STM32-M4-ILI9341 +GFXSRC += +GFXDEFS += -DGFX_USE_OS_CHIBIOS=TRUE +include $(GFXLIB)/drivers/gdisp/ILI9341/gdisp_lld.mk +include $(GFXLIB)/drivers/ginput/touch/MCU/ginput_lld.mk diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/board_ILI9341.h b/boards/base/Mikromedia-STM32-M4-ILI9341/board_ILI9341.h new file mode 100644 index 00000000..ec7292eb --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/board_ILI9341.h @@ -0,0 +1,132 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file boards/base/Mikromedia-STM32-M4-ILI9341/board_ILI9341.h + * @brief GDISP Graphics Driver subsystem low level driver source for the ILI9341 display. + */ + +#ifndef _GDISP_LLD_BOARD_H +#define _GDISP_LLD_BOARD_H + +// For a multiple display configuration we would put all this in a structure and then +// set g->board to that structure. +#define SET_CS palSetPad(GPIOE, GPIOE_LCD_CS); +#define CLR_CS palClearPad(GPIOE, GPIOE_LCD_CS); +#define SET_RS palSetPad(GPIOE, GPIOE_LCD_RS); +#define CLR_RS palClearPad(GPIOE, GPIOE_LCD_RS); +#define SET_WR palSetPad(GPIOE, GPIOE_PMWR); +#define CLR_WR palClearPad(GPIOE, GPIOE_PMWR); +#define SET_RD palSetPad(GPIOE, GPIOE_PMRD); +#define CLR_RD palClearPad(GPIOE, GPIOE_PMRD); + +static inline void init_board(GDisplay *g) { + + // As we are not using multiple displays we set g->board to NULL as we don't use it. + g->board = 0; + + switch(g->controllerdisplay) { + case 0: // Set up for Display 0 + /* Configure the pins to a well know state */ + SET_RS; + SET_RD; + SET_WR; + CLR_CS; + + /* Hardware reset */ + palSetPad(GPIOE, GPIOE_LCD_RST); + chThdSleepMilliseconds(100); + palClearPad(GPIOE, GPIOE_LCD_RST); + chThdSleepMilliseconds(100); + palSetPad(GPIOE, GPIOE_LCD_RST); + chThdSleepMilliseconds(100); + break; + } +} + +static inline void post_init_board(GDisplay *g) { + (void) g; +} + +static inline void setpin_reset(GDisplay *g, bool_t state) { + (void) g; + if(state) { + // reset lcd + palClearPad(GPIOE, GPIOE_LCD_RST); + } else { + palSetPad(GPIOE, GPIOE_LCD_RST); + } +} + +static inline void set_backlight(GDisplay *g, uint8_t percent) { + (void) g; + // TODO: can probably pwm this + if(percent) { + // turn back light on + palSetPad(GPIOE, GPIOE_LCD_BLED); + } else { + // turn off + palClearPad(GPIOE, GPIOE_LCD_BLED); + } +} + +static inline void acquire_bus(GDisplay *g) { + (void) g; +} + +static inline void release_bus(GDisplay *g) { + (void) g; +} + +/** + * @brief Short delay + * + * @param[in] dly Length of delay + * + * @notapi + */ +static inline void ili9341_delay(uint16_t dly) { + static uint16_t i; + for(i = 0; i < dly; i++) + asm("nop"); +} + +static inline void write_index(GDisplay *g, uint16_t index) { + (void) g; + palWriteGroup(GPIOE, 0x00FF, 0, index); + CLR_RS; CLR_WR; ili9341_delay(1); SET_WR; ili9341_delay(1); SET_RS; +} + +static inline void write_data(GDisplay *g, uint16_t data) { + (void) g; + palWriteGroup(GPIOE, 0x00FF, 0, data); + CLR_WR; ili9341_delay(1); SET_WR; ili9341_delay(1); +} + +static inline void setreadmode(GDisplay *g) { + (void) g; + // change pin mode to digital input + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); +} + +static inline void setwritemode(GDisplay *g) { + (void) g; + // change pin mode back to digital output + palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); +} + +static inline uint16_t read_data(GDisplay *g) { + uint16_t value; + (void) g; + CLR_RD; + value = palReadPort(GPIOE); + value = palReadPort(GPIOE); + SET_RD; + return value; +} + +#endif /* _GDISP_LLD_BOARD_H */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/example/Makefile b/boards/base/Mikromedia-STM32-M4-ILI9341/example/Makefile new file mode 100644 index 00000000..28292535 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/example/Makefile @@ -0,0 +1,231 @@ +############################################################################## +# Build global options +# NOTE: Can be overridden externally. +# + +# Compiler options here. +ifeq ($(USE_OPT),) + USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16 +endif + +# C specific options here (added to USE_OPT). +ifeq ($(USE_COPT),) + USE_COPT = +endif + +# C++ specific options here (added to USE_OPT). +ifeq ($(USE_CPPOPT),) + USE_CPPOPT = -fno-rtti +endif + +# Enable this if you want the linker to remove unused code and data +ifeq ($(USE_LINK_GC),) + USE_LINK_GC = yes +endif + +# If enabled, this option allows to compile the application in THUMB mode. +ifeq ($(USE_THUMB),) + USE_THUMB = yes +endif + +# Enable this if you want to see the full log while compiling. +ifeq ($(USE_VERBOSE_COMPILE),) + USE_VERBOSE_COMPILE = no +endif + +# +# Build global options +############################################################################## + +############################################################################## +# Architecture or project specific options +# + +# Enables the use of FPU on Cortex-M4. +# Enable this if you really want to use the STM FWLib. +ifeq ($(USE_FPU),) + USE_FPU = no +endif + +# Enable this if you really want to use the STM FWLib. +ifeq ($(USE_FWLIB),) + USE_FWLIB = no +endif + +# +# Architecture or project specific options +############################################################################## + +############################################################################## +# Project, sources and paths +# + +SW = .. + +# Define project name here +PROJECT = ch + +# Imported source files and paths +CHIBIOS = ../ChibiOS +#include $(CHIBIOS)/boards/MIKROMEDIA_STM32_M4/board.mk # Not a standard ChibiOS supported board +include $(CHIBIOS)/os/hal/platforms/STM32F4xx/platform.mk +include $(CHIBIOS)/os/hal/hal.mk +include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F4xx/port.mk +include $(CHIBIOS)/os/kernel/kernel.mk +LDSCRIPT= $(PORTLD)/STM32F407xG.ld + +# Imported source files and paths for uGFX +GFXLIB = ../uGFX +include $(GFXLIB)/gfx.mk +include $(GFXLIB)/boards/base/Mikromedia-STM32-M4-ILI9341/board.mk +include $(GFXLIB)/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/board.mk # The replacement ChibiOS board files + +# Where is our source code - alter these for your project. +MYFILES = $(GFXLIB)/demos/modules/gdisp/basics +MYCSRC = $(MYFILES)/main.c + +# C sources that can be compiled in ARM or THUMB mode depending on the global +# setting. +CSRC = $(PORTSRC) \ + $(KERNSRC) \ + $(TESTSRC) \ + $(HALSRC) \ + $(PLATFORMSRC) \ + $(BOARDSRC) \ + $(GFXSRC) \ + $(MYCSRC) + +# C++ sources that can be compiled in ARM or THUMB mode depending on the global +# setting. +CPPSRC = + +# C sources to be compiled in ARM mode regardless of the global setting. +# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler +# option that results in lower performance and larger code size. +ACSRC = + +# C++ sources to be compiled in ARM mode regardless of the global setting. +# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler +# option that results in lower performance and larger code size. +ACPPSRC = + +# C sources to be compiled in THUMB mode regardless of the global setting. +# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler +# option that results in lower performance and larger code size. +TCSRC = + +# C sources to be compiled in THUMB mode regardless of the global setting. +# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler +# option that results in lower performance and larger code size. +TCPPSRC = + +# List ASM source files here +ASMSRC = $(PORTASM) + +INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \ + $(HALINC) $(PLATFORMINC) $(BOARDINC) \ + $(GFXINC) \ + $(MYFILES) + +# +# Project, sources and paths +############################################################################## + +############################################################################## +# Compiler settings +# + +MCU = cortex-m4 + +#TRGT = arm-elf- +TRGT = arm-none-eabi- +CC = $(TRGT)gcc +CPPC = $(TRGT)g++ +# Enable loading with g++ only if you need C++ runtime support. +# NOTE: You can use C++ even without C++ support if you are careful. C++ +# runtime support makes code size explode. +LD = $(TRGT)gcc +#LD = $(TRGT)g++ +CP = $(TRGT)objcopy +AS = $(TRGT)gcc -x assembler-with-cpp +OD = $(TRGT)objdump +HEX = $(CP) -O ihex +BIN = $(CP) -O binary + +# ARM-specific options here +AOPT = + +# THUMB-specific options here +TOPT = -mthumb -DTHUMB + +# Define C warning options here +CWARN = -Wall -Wextra -Wstrict-prototypes + +# Define C++ warning options here +CPPWARN = -Wall -Wextra + +# +# Compiler settings +############################################################################## + +############################################################################## +# Start of default section +# + +# List all default C defines here, like -D_DEBUG=1 +DDEFS = $(GFXDEFS) + +# List all default ASM defines here, like -D_DEBUG=1 +DADEFS = + +# List all default directories to look for include files here +DINCDIR = + +# List the default directory to look for the libraries here +DLIBDIR = + +# List all default libraries here +DLIBS = + +# +# End of default section +############################################################################## + +############################################################################## +# Start of user section +# + +# List all user C define here, like -D_DEBUG=1 +UDEFS = + +# Define ASM defines here +UADEFS = + +# List all user directories here +UINCDIR = + +# List the user directory to look for the libraries here +ULIBDIR = + +# List all user libraries here +ULIBS = + +# +# End of user defines +############################################################################## + +ifeq ($(USE_FPU),yes) + USE_OPT += -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -fsingle-precision-constant + DDEFS += -DCORTEX_USE_FPU=TRUE +else + DDEFS += -DCORTEX_USE_FPU=FALSE +endif + +ifeq ($(USE_FWLIB),yes) + include $(CHIBIOS)/ext/stm32lib/stm32lib.mk + CSRC += $(STM32SRC) + INCDIR += $(STM32INC) + USE_OPT += -DUSE_STDPERIPH_DRIVER +endif + +include $(CHIBIOS)/os/ports/GCC/ARMCMx/rules.mk diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/example/chconf.h b/boards/base/Mikromedia-STM32-M4-ILI9341/example/chconf.h new file mode 100644 index 00000000..f4682cb9 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/example/chconf.h @@ -0,0 +1,531 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef _CHCONF_H_ +#define _CHCONF_H_ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + */ +#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__) +#define CH_FREQUENCY 1000 +#endif + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + */ +#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__) +#define CH_TIME_QUANTUM 20 +#endif + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_USE_MEMCORE. + */ +#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__) +#define CH_MEMCORE_SIZE 0 +#endif + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread automatically. The application has + * then the responsibility to do one of the following: + * - Spawn a custom idle thread at priority @p IDLEPRIO. + * - Change the main() thread priority to @p IDLEPRIO then enter + * an endless loop. In this scenario the @p main() thread acts as + * the idle thread. + * . + * @note Unless an idle thread is spawned the @p main() thread must not + * enter a sleep state. + */ +#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__) +#define CH_NO_IDLE_THREAD FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__) +#define CH_OPTIMIZE_SPEED TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__) +#define CH_USE_REGISTRY TRUE +#endif + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__) +#define CH_USE_WAITEXIT TRUE +#endif + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__) +#define CH_USE_SEMAPHORES TRUE +#endif + +/** + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special requirements. + * @note Requires @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__) +#define CH_USE_SEMAPHORES_PRIORITY FALSE +#endif + +/** + * @brief Atomic semaphore API. + * @details If enabled then the semaphores the @p chSemSignalWait() API + * is included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__) +#define CH_USE_SEMSW TRUE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__) +#define CH_USE_MUTEXES TRUE +#endif + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_MUTEXES. + */ +#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__) +#define CH_USE_CONDVARS TRUE +#endif + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_CONDVARS. + */ +#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__) +#define CH_USE_CONDVARS_TIMEOUT TRUE +#endif + +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__) +#define CH_USE_EVENTS TRUE +#endif + +/** + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_EVENTS. + */ +#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__) +#define CH_USE_EVENTS_TIMEOUT TRUE +#endif + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__) +#define CH_USE_MESSAGES TRUE +#endif + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special requirements. + * @note Requires @p CH_USE_MESSAGES. + */ +#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__) +#define CH_USE_MESSAGES_PRIORITY FALSE +#endif + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__) +#define CH_USE_MAILBOXES TRUE +#endif + +/** + * @brief I/O Queues APIs. + * @details If enabled then the I/O queues APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__) +#define CH_USE_QUEUES TRUE +#endif + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MEMCORE) || defined(__DOXYGEN__) +#define CH_USE_MEMCORE TRUE +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or + * @p CH_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__) +#define CH_USE_HEAP TRUE +#endif + +/** + * @brief C-runtime allocator. + * @details If enabled the the heap allocator APIs just wrap the C-runtime + * @p malloc() and @p free() functions. + * + * @note The default is @p FALSE. + * @note Requires @p CH_USE_HEAP. + * @note The C-runtime may or may not require @p CH_USE_MEMCORE, see the + * appropriate documentation. + */ +#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__) +#define CH_USE_MALLOC_HEAP FALSE +#endif + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__) +#define CH_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_WAITEXIT. + * @note Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS. + */ +#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__) +#define CH_USE_DYNAMIC TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__) +#define CH_DBG_SYSTEM_STATE_CHECK FALSE +#endif + +/** + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_CHECKS FALSE +#endif + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_ASSERTS FALSE +#endif + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the context switch circular trace buffer is + * activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_TRACE FALSE +#endif + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_STACK_CHECK FALSE +#endif + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__) +#define CH_DBG_FILL_THREADS FALSE +#endif + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p Thread structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p TRUE. + * @note This debug option is defaulted to TRUE because it is required by + * some test cases into the test suite. + */ +#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) +#define CH_DBG_THREADS_PROFILING TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p Thread structure. + */ +#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__) +#define THREAD_EXT_FIELDS \ + /* Add threads custom fields here.*/ +#endif + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p chThdInit() API. + * + * @note It is invoked from within @p chThdInit() and implicitly from all + * the threads creation APIs. + */ +#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__) +#define THREAD_EXT_INIT_HOOK(tp) { \ + /* Add threads initialization code here.*/ \ +} +#endif + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + * + * @note It is inserted into lock zone. + * @note It is also invoked when the threads simply return in order to + * terminate. + */ +#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__) +#define THREAD_EXT_EXIT_HOOK(tp) { \ + /* Add threads finalization code here.*/ \ +} +#endif + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + */ +#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__) +#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) { \ + /* System halt code here.*/ \ +} +#endif + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__) +#define IDLE_LOOP_HOOK() { \ + /* Idle loop code here.*/ \ +} +#endif + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__) +#define SYSTEM_TICK_EVENT_HOOK() { \ + /* System tick event code here.*/ \ +} +#endif + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) +#define SYSTEM_HALT_HOOK() { \ + /* System halt code here.*/ \ +} +#endif + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#endif /* _CHCONF_H_ */ + +/** @} */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/example/halconf.h b/boards/base/Mikromedia-STM32-M4-ILI9341/example/halconf.h new file mode 100644 index 00000000..6585fb3e --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/example/halconf.h @@ -0,0 +1,312 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file templates/halconf.h + * @brief HAL configuration header. + * @details HAL configuration file, this file allows to enable or disable the + * various device drivers from your application. You may also use + * this file in order to override the device drivers default settings. + * + * @addtogroup HAL_CONF + * @{ + */ + +#ifndef _HALCONF_H_ +#define _HALCONF_H_ + +#include "mcuconf.h" + +/** + * @brief Enables the TM subsystem. + */ +#if !defined(HAL_USE_TM) || defined(__DOXYGEN__) +#define HAL_USE_TM FALSE +#endif + +/** + * @brief Enables the PAL subsystem. + */ +#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) +#define HAL_USE_PAL TRUE +#endif + +/** + * @brief Enables the ADC subsystem. + */ +#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) +#define HAL_USE_ADC TRUE +#endif + +/** + * @brief Enables the CAN subsystem. + */ +#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) +#define HAL_USE_CAN FALSE +#endif + +/** + * @brief Enables the EXT subsystem. + */ +#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__) +#define HAL_USE_EXT FALSE +#endif + +/** + * @brief Enables the GPT subsystem. + */ +#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) +#define HAL_USE_GPT FALSE +#endif + +/** + * @brief Enables the I2C subsystem. + */ +#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) +#define HAL_USE_I2C FALSE +#endif + +/** + * @brief Enables the ICU subsystem. + */ +#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) +#define HAL_USE_ICU FALSE +#endif + +/** + * @brief Enables the MAC subsystem. + */ +#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) +#define HAL_USE_MAC FALSE +#endif + +/** + * @brief Enables the MMC_SPI subsystem. + */ +#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) +#define HAL_USE_MMC_SPI TRUE +#endif + +/** + * @brief Enables the PWM subsystem. + */ +#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) +#define HAL_USE_PWM TRUE +#endif + +/** + * @brief Enables the RTC subsystem. + */ +#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) +#define HAL_USE_RTC FALSE +#endif + +/** + * @brief Enables the SDC subsystem. + */ +#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) +#define HAL_USE_SDC FALSE +#endif + +/** + * @brief Enables the SERIAL subsystem. + */ +#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL TRUE +#endif + +/** + * @brief Enables the SERIAL over USB subsystem. + */ +#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL_USB FALSE +#endif + +/** + * @brief Enables the SPI subsystem. + */ +#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) +#define HAL_USE_SPI TRUE +#endif + +/** + * @brief Enables the UART subsystem. + */ +#if !defined(HAL_USE_UART) || defined(__DOXYGEN__) +#define HAL_USE_UART FALSE +#endif + +/** + * @brief Enables the USB subsystem. + */ +#if !defined(HAL_USE_USB) || defined(__DOXYGEN__) +#define HAL_USE_USB FALSE +#endif + +/*===========================================================================*/ +/* ADC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) +#define ADC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define ADC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* CAN driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + */ +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif + +/*===========================================================================*/ +/* I2C driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the mutual exclusion APIs on the I2C bus. + */ +#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define I2C_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* MAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__) +#define MAC_USE_ZERO_COPY FALSE +#endif + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) +#define MAC_USE_EVENTS TRUE +#endif + +/*===========================================================================*/ +/* MMC_SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + * This option is recommended also if the SPI driver does not + * use a DMA channel and heavily loads the CPU. + */ +#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__) +#define MMC_NICE_WAITING TRUE +#endif + +/*===========================================================================*/ +/* SDC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intervals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + +/*===========================================================================*/ +/* SERIAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SERIAL_DEFAULT_BITRATE 38400 +#endif + +/** + * @brief Serial buffers size. + * @details Configuration parameter, you can change the depth of the queue + * buffers depending on the requirements of your application. + * @note The default is 64 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_BUFFERS_SIZE 16 +#endif + +/*===========================================================================*/ +/* SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) +#define SPI_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define SPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +#endif /* _HALCONF_H_ */ + +/** @} */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/example/mcuconf.h b/boards/base/Mikromedia-STM32-M4-ILI9341/example/mcuconf.h new file mode 100644 index 00000000..64895943 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/example/mcuconf.h @@ -0,0 +1,289 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + * STM32F4xx drivers configuration. + * The following settings override the default settings present in + * the various device driver implementation headers. + * Note that the settings for each driver only have effect if the whole + * driver is enabled in halconf.h. + * + * IRQ priorities: + * 15...0 Lowest...Highest. + * + * DMA priorities: + * 0...3 Lowest...Highest. + */ + +#define STM32F4xx_MCUCONF + +/* + * HAL driver system settings. + */ +#define STM32_NO_INIT FALSE +#define STM32_HSI_ENABLED TRUE +#define STM32_LSI_ENABLED TRUE +#define STM32_HSE_ENABLED FALSE +#define STM32_LSE_ENABLED TRUE +#define STM32_CLOCK48_REQUIRED TRUE +#define STM32_SW STM32_SW_PLL +#define STM32_PLLSRC STM32_PLLSRC_HSI +#define STM32_PLLM_VALUE 16 +#define STM32_PLLN_VALUE 336 +#define STM32_PLLP_VALUE 2 +#define STM32_PLLQ_VALUE 7 +#define STM32_HPRE STM32_HPRE_DIV1 +#define STM32_PPRE1 STM32_PPRE1_DIV4 +#define STM32_PPRE2 STM32_PPRE2_DIV2 +#define STM32_RTCSEL STM32_RTCSEL_LSI +#define STM32_RTCPRE_VALUE 8 +#define STM32_MCO1SEL STM32_MCO1SEL_HSI +#define STM32_MCO1PRE STM32_MCO1PRE_DIV1 +#define STM32_MCO2SEL STM32_MCO2SEL_SYSCLK +#define STM32_MCO2PRE STM32_MCO2PRE_DIV5 +#define STM32_I2SSRC STM32_I2SSRC_CKIN +#define STM32_PLLI2SN_VALUE 192 +#define STM32_PLLI2SR_VALUE 5 +#define STM32_VOS STM32_VOS_HIGH +#define STM32_PVD_ENABLE FALSE +#define STM32_PLS STM32_PLS_LEV0 +#define STM32_BKPRAM_ENABLE FALSE + +/* + * ADC driver system settings. + */ +#define STM32_ADC_ADCPRE ADC_CCR_ADCPRE_DIV4 +#define STM32_ADC_USE_ADC1 TRUE +#define STM32_ADC_USE_ADC2 FALSE +#define STM32_ADC_USE_ADC3 FALSE +#define STM32_ADC_ADC1_DMA_STREAM STM32_DMA_STREAM_ID(2, 4) +#define STM32_ADC_ADC2_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) +#define STM32_ADC_ADC3_DMA_STREAM STM32_DMA_STREAM_ID(2, 1) +#define STM32_ADC_ADC1_DMA_PRIORITY 2 +#define STM32_ADC_ADC2_DMA_PRIORITY 2 +#define STM32_ADC_ADC3_DMA_PRIORITY 2 +#define STM32_ADC_IRQ_PRIORITY 6 +#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY 6 +#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY 6 +#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY 6 + +/* + * CAN driver system settings. + */ +#define STM32_CAN_USE_CAN1 FALSE +#define STM32_CAN_USE_CAN2 FALSE +#define STM32_CAN_CAN1_IRQ_PRIORITY 11 +#define STM32_CAN_CAN2_IRQ_PRIORITY 11 + +/* + * EXT driver system settings. + */ +#define STM32_EXT_EXTI0_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI1_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI2_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI3_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI4_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI5_9_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI10_15_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI16_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI17_IRQ_PRIORITY 15 +#define STM32_EXT_EXTI18_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI19_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI20_IRQ_PRIORITY 6 +#define STM32_EXT_EXTI21_IRQ_PRIORITY 15 +#define STM32_EXT_EXTI22_IRQ_PRIORITY 15 + +/* + * GPT driver system settings. + */ +#define STM32_GPT_USE_TIM1 FALSE +#define STM32_GPT_USE_TIM2 FALSE +#define STM32_GPT_USE_TIM3 FALSE +#define STM32_GPT_USE_TIM4 FALSE +#define STM32_GPT_USE_TIM5 FALSE +#define STM32_GPT_USE_TIM6 FALSE +#define STM32_GPT_USE_TIM7 FALSE +#define STM32_GPT_USE_TIM8 FALSE +#define STM32_GPT_USE_TIM9 FALSE +#define STM32_GPT_USE_TIM11 FALSE +#define STM32_GPT_USE_TIM12 FALSE +#define STM32_GPT_USE_TIM14 FALSE +#define STM32_GPT_TIM1_IRQ_PRIORITY 7 +#define STM32_GPT_TIM2_IRQ_PRIORITY 7 +#define STM32_GPT_TIM3_IRQ_PRIORITY 7 +#define STM32_GPT_TIM4_IRQ_PRIORITY 7 +#define STM32_GPT_TIM5_IRQ_PRIORITY 7 +#define STM32_GPT_TIM6_IRQ_PRIORITY 7 +#define STM32_GPT_TIM7_IRQ_PRIORITY 7 +#define STM32_GPT_TIM8_IRQ_PRIORITY 7 +#define STM32_GPT_TIM9_IRQ_PRIORITY 7 +#define STM32_GPT_TIM11_IRQ_PRIORITY 7 +#define STM32_GPT_TIM12_IRQ_PRIORITY 7 +#define STM32_GPT_TIM14_IRQ_PRIORITY 7 + +/* + * I2C driver system settings. + */ +#define STM32_I2C_USE_I2C1 FALSE +#define STM32_I2C_USE_I2C2 FALSE +#define STM32_I2C_USE_I2C3 FALSE +#define STM32_I2C_I2C1_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#define STM32_I2C_I2C1_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) +#define STM32_I2C_I2C2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#define STM32_I2C_I2C2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_I2C_I2C3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#define STM32_I2C_I2C3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_I2C_I2C1_IRQ_PRIORITY 5 +#define STM32_I2C_I2C2_IRQ_PRIORITY 5 +#define STM32_I2C_I2C3_IRQ_PRIORITY 5 +#define STM32_I2C_I2C1_DMA_PRIORITY 3 +#define STM32_I2C_I2C2_DMA_PRIORITY 3 +#define STM32_I2C_I2C3_DMA_PRIORITY 3 +#define STM32_I2C_I2C1_DMA_ERROR_HOOK() chSysHalt() +#define STM32_I2C_I2C2_DMA_ERROR_HOOK() chSysHalt() +#define STM32_I2C_I2C3_DMA_ERROR_HOOK() chSysHalt() + +/* + * ICU driver system settings. + */ +#define STM32_ICU_USE_TIM1 FALSE +#define STM32_ICU_USE_TIM2 FALSE +#define STM32_ICU_USE_TIM3 FALSE +#define STM32_ICU_USE_TIM4 FALSE +#define STM32_ICU_USE_TIM5 FALSE +#define STM32_ICU_USE_TIM8 FALSE +#define STM32_ICU_USE_TIM9 FALSE +#define STM32_ICU_TIM1_IRQ_PRIORITY 7 +#define STM32_ICU_TIM2_IRQ_PRIORITY 7 +#define STM32_ICU_TIM3_IRQ_PRIORITY 7 +#define STM32_ICU_TIM4_IRQ_PRIORITY 7 +#define STM32_ICU_TIM5_IRQ_PRIORITY 7 +#define STM32_ICU_TIM8_IRQ_PRIORITY 7 +#define STM32_ICU_TIM9_IRQ_PRIORITY 7 + +/* + * MAC driver system settings. + */ +#define STM32_MAC_TRANSMIT_BUFFERS 2 +#define STM32_MAC_RECEIVE_BUFFERS 4 +#define STM32_MAC_BUFFERS_SIZE 1522 +#define STM32_MAC_PHY_TIMEOUT 100 +#define STM32_MAC_ETH1_CHANGE_PHY_STATE TRUE +#define STM32_MAC_ETH1_IRQ_PRIORITY 13 +#define STM32_MAC_IP_CHECKSUM_OFFLOAD 0 + +/* + * PWM driver system settings. + */ +#define STM32_PWM_USE_ADVANCED FALSE +#define STM32_PWM_USE_TIM1 FALSE +#define STM32_PWM_USE_TIM2 FALSE +#define STM32_PWM_USE_TIM3 FALSE +#define STM32_PWM_USE_TIM4 TRUE +#define STM32_PWM_USE_TIM5 FALSE +#define STM32_PWM_USE_TIM8 FALSE +#define STM32_PWM_USE_TIM9 FALSE +#define STM32_PWM_TIM1_IRQ_PRIORITY 7 +#define STM32_PWM_TIM2_IRQ_PRIORITY 7 +#define STM32_PWM_TIM3_IRQ_PRIORITY 7 +#define STM32_PWM_TIM4_IRQ_PRIORITY 7 +#define STM32_PWM_TIM5_IRQ_PRIORITY 7 +#define STM32_PWM_TIM8_IRQ_PRIORITY 7 +#define STM32_PWM_TIM9_IRQ_PRIORITY 7 + +/* + * SERIAL driver system settings. + */ +#define STM32_SERIAL_USE_USART1 FALSE +#define STM32_SERIAL_USE_USART2 TRUE +#define STM32_SERIAL_USE_USART3 FALSE +#define STM32_SERIAL_USE_UART4 FALSE +#define STM32_SERIAL_USE_UART5 FALSE +#define STM32_SERIAL_USE_USART6 FALSE +#define STM32_SERIAL_USART1_PRIORITY 12 +#define STM32_SERIAL_USART2_PRIORITY 12 +#define STM32_SERIAL_USART3_PRIORITY 12 +#define STM32_SERIAL_UART4_PRIORITY 12 +#define STM32_SERIAL_UART5_PRIORITY 12 +#define STM32_SERIAL_USART6_PRIORITY 12 + +/* + * SPI driver system settings. + */ +#define STM32_SPI_USE_SPI1 FALSE +#define STM32_SPI_USE_SPI2 TRUE +#define STM32_SPI_USE_SPI3 TRUE +#define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 0) +#define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) +#define STM32_SPI_SPI2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#define STM32_SPI_SPI2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_SPI_SPI3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#define STM32_SPI_SPI3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_SPI_SPI1_DMA_PRIORITY 1 +#define STM32_SPI_SPI2_DMA_PRIORITY 1 +#define STM32_SPI_SPI3_DMA_PRIORITY 1 +#define STM32_SPI_SPI1_IRQ_PRIORITY 10 +#define STM32_SPI_SPI2_IRQ_PRIORITY 10 +#define STM32_SPI_SPI3_IRQ_PRIORITY 10 +#define STM32_SPI_DMA_ERROR_HOOK(spip) chSysHalt() + +/* + * UART driver system settings. + */ +#define STM32_UART_USE_USART1 FALSE +#define STM32_UART_USE_USART2 FALSE +#define STM32_UART_USE_USART3 FALSE +#define STM32_UART_USE_UART4 FALSE +#define STM32_UART_USE_UART5 FALSE +#define STM32_UART_USE_USART6 FALSE +#define STM32_UART_USART1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) +#define STM32_UART_USART1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) +#define STM32_UART_USART2_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 5) +#define STM32_UART_USART2_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 6) +#define STM32_UART_USART3_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 1) +#define STM32_UART_USART3_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 3) +#define STM32_UART_UART4_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 2) +#define STM32_UART_UART4_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 4) +#define STM32_UART_UART5_RX_DMA_STREAM STM32_DMA_STREAM_ID(1, 0) +#define STM32_UART_UART5_TX_DMA_STREAM STM32_DMA_STREAM_ID(1, 7) +#define STM32_UART_USART6_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 2) +#define STM32_UART_USART6_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 7) +#define STM32_UART_USART1_IRQ_PRIORITY 12 +#define STM32_UART_USART2_IRQ_PRIORITY 12 +#define STM32_UART_USART3_IRQ_PRIORITY 12 +#define STM32_UART_UART4_IRQ_PRIORITY 12 +#define STM32_UART_UART5_IRQ_PRIORITY 12 +#define STM32_UART_USART6_IRQ_PRIORITY 12 +#define STM32_UART_USART1_DMA_PRIORITY 0 +#define STM32_UART_USART2_DMA_PRIORITY 0 +#define STM32_UART_USART3_DMA_PRIORITY 0 +#define STM32_UART_UART4_DMA_PRIORITY 0 +#define STM32_UART_UART5_DMA_PRIORITY 0 +#define STM32_UART_USART6_DMA_PRIORITY 0 +#define STM32_UART_DMA_ERROR_HOOK(uartp) chSysHalt() + +/* + * USB driver system settings. + */ +#define STM32_USB_USE_OTG1 FALSE +#define STM32_USB_USE_OTG2 FALSE +#define STM32_USB_OTG1_IRQ_PRIORITY 14 +#define STM32_USB_OTG2_IRQ_PRIORITY 14 +#define STM32_USB_OTG1_RX_FIFO_SIZE 512 +#define STM32_USB_OTG2_RX_FIFO_SIZE 1024 +#define STM32_USB_OTG_THREAD_PRIO LOWPRIO +#define STM32_USB_OTG_THREAD_STACK_SIZE 128 +#define STM32_USB_OTGFIFO_FILL_BASEPRI 0 diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_board.h b/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_board.h new file mode 100644 index 00000000..373a2474 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_board.h @@ -0,0 +1,152 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_board.h + * @brief GINPUT Touch low level driver source for the MCU. + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +/* read ADC if more than this many ticks since last read */ +#define ADC_UPDATE_INTERVAL 3 + +#define ADC_NUM_CHANNELS 2 +#define ADC_BUF_DEPTH 1 + +static const ADCConversionGroup adcgrpcfg = { + FALSE, + ADC_NUM_CHANNELS, + NULL, + NULL, + /* HW dependent part.*/ + 0, + ADC_CR2_SWSTART, + 0, + 0, + ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), + 0, + ADC_SQR3_SQ2_N(ADC_CHANNEL_IN8) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN9) +}; + +static systime_t last_update; +static volatile uint16_t tpx, tpy, detect; + +static inline void delay(uint16_t dly) { + static uint16_t i; + for(i = 0; i < dly; i++) + asm("nop"); +} + + +void read_mikro_tp(void) { + systime_t now = chTimeNow(); + + adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; + uint16_t _detect, _tpx, _tpy; + + if(now < last_update || ((now - last_update) > ADC_UPDATE_INTERVAL)) { + // detect button press + // sample[0] will go from ~200 to ~4000 when pressed + adcConvert(&ADCD1, &adcgrpcfg, samples, ADC_BUF_DEPTH); + _detect = samples[0]; + + // read x channel + palSetPad(GPIOB, GPIOB_DRIVEA); + palClearPad(GPIOB, GPIOB_DRIVEB); + chThdSleepMilliseconds(1); + adcConvert(&ADCD1, &adcgrpcfg, samples, ADC_BUF_DEPTH); + _tpx = samples[1]; + + // read y channel (invert) + palClearPad(GPIOB, GPIOB_DRIVEA); + palSetPad(GPIOB, GPIOB_DRIVEB); + chThdSleepMilliseconds(1); + adcConvert(&ADCD1, &adcgrpcfg, samples, ADC_BUF_DEPTH); + _tpy = samples[0]; + + // ready for next read + palClearPad(GPIOB, GPIOB_DRIVEA); + palClearPad(GPIOB, GPIOB_DRIVEB); + + chSysLock(); + tpx = _tpx; + tpy = _tpy; + detect = _detect; + last_update = now; + chSysUnlock(); + } +} + +/** + * @brief Initialise the board for the touch. + * + * @notapi + */ +static inline void init_board(void) { + adcStart(&ADCD1, NULL); + last_update = chTimeNow(); + + // leave DRIVEA & DRIVEB ready for next read + palClearPad(GPIOB, GPIOB_DRIVEA); + palClearPad(GPIOB, GPIOB_DRIVEB); + chThdSleepMilliseconds(1); +} + +/** + * @brief Check whether the surface is currently touched + * @return TRUE if the surface is currently touched + * + * @notapi + */ +static inline bool_t getpin_pressed(void) { + read_mikro_tp(); + return (detect > 2000) ? true : false; +} + +/** + * @brief Aquire the bus ready for readings + * + * @notapi + */ +static inline void aquire_bus(void) { + +} + +/** + * @brief Release the bus after readings + * + * @notapi + */ +static inline void release_bus(void) { + +} + +/** + * @brief Read an x value from touch controller + * @return The value read from the controller + * + * @notapi + */ +static inline uint16_t read_x_value(void) { + read_mikro_tp(); + return tpx; +} + +/** + * @brief Read an y value from touch controller + * @return The value read from the controller + * + * @notapi + */ +static inline uint16_t read_y_value(void) { + read_mikro_tp(); + return tpy; +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_config.h b/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_config.h new file mode 100644 index 00000000..0c0ff482 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_config.h @@ -0,0 +1,32 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file boards/base/Mikromedia-STM32-M4-ILI9341/ginput_lld_mouse_config.h + * @brief GINPUT LLD header file for touch driver. + * + * @defgroup Mouse Mouse + * @ingroup GINPUT + * + * @{ + */ + +#ifndef _LLD_GINPUT_MOUSE_CONFIG_H +#define _LLD_GINPUT_MOUSE_CONFIG_H + +#define GINPUT_MOUSE_EVENT_TYPE GEVENT_TOUCH +#define GINPUT_MOUSE_NEED_CALIBRATION TRUE +#define GINPUT_MOUSE_LLD_CALIBRATION_LOADSAVE FALSE +#define GINPUT_MOUSE_MAX_CALIBRATION_ERROR 12 +#define GINPUT_MOUSE_READ_CYCLES 4 +#define GINPUT_MOUSE_POLL_PERIOD 3 +#define GINPUT_MOUSE_MAX_CLICK_JITTER 2 +#define GINPUT_MOUSE_MAX_MOVE_JITTER 2 +#define GINPUT_MOUSE_CLICK_TIME 500 + +#endif /* _LLD_GINPUT_MOUSE_CONFIG_H */ +/** @} */ diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/readme.txt b/boards/base/Mikromedia-STM32-M4-ILI9341/readme.txt new file mode 100644 index 00000000..79b430d2 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/readme.txt @@ -0,0 +1,16 @@ +This directory contains the interface for the MikroMedia STM32 M4 board +running under ChibiOS with the ILI9341 display. + +On this board uGFX currently supports: + - GDISP via the ILI9341 display + - GINPUT-touch via the MCU driver + +Note there are two variants of this board - one with the ILI9341 display + and an older one with a different display. This one is for the ILI9341 display. + +As this is not a standard ChibiOS supported board the necessary board files have also +been provided in the ChibiOS_Board directory. + +There is an example Makefile and project in the examples directory. + +Note: The video driver currently has bugs! \ No newline at end of file From 555257933af6e7e3b106ac3589520b5dad45061b Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 28 Oct 2013 20:04:03 +1000 Subject: [PATCH 139/160] Clean up the driver directory structure by moving all board specific files into the boards sub-structure. --- .../gdisp/ED060SC4_example_schematics.png | Bin 0 -> 305333 bytes .../addons/gdisp}/board_ED060SC4_example.h | 0 .../gdisp}/board_HX8347D_stm32f4discovery.h | 0 .../gdisp}/board_ILI9320_olimex_pic32mx_lcd.h | 0 .../gdisp}/board_ILI9320_olimex_stm32_lcd.h | 0 .../gdisp}/board_ILI9325_hy_stm32_100p.h | 0 .../gdisp}/board_ILI9481_firebullstm32f103.h | 0 .../addons/gdisp}/board_RA8875_marlin.h | 0 .../addons/gdisp}/board_S6D1121_olimex_e407.h | 0 .../gdisp}/board_SSD1289_firebullstm32f103.h | 0 .../gdisp}/board_SSD1289_stm32f4discovery.h | 0 .../addons/gdisp}/board_SSD1306_i2c.h | 0 .../addons/gdisp}/board_SSD1306_spi.h | 0 .../addons/gdisp}/board_SSD1963_fsmc.h | 0 .../addons/gdisp}/board_SSD1963_gpio.h | 0 .../gdisp}/board_SSD2119_embest_dmstf4bb.h | 0 ...input_lld_mouse_board_firebull_stm32f103.h | 168 +++++----- ...ginput_lld_mouse_board_olimex_stm32_e407.h | 168 +++++----- ...put_lld_mouse_board_st_stm32f4_discovery.h | 0 .../FT5x06/ginput_lld_mouse_board_marlin.h | 0 ...input_lld_mouse_board_olimex_pic32mx_lcd.h | 290 ++++++++--------- .../ginput_lld_mouse_board_olimex_stm32_lcd.h | 304 +++++++++--------- .../ginput_lld_mouse_board_embest_dmstf4bb.h | 240 +++++++------- .../HD44780/tdisp_lld_board_olimex_e407.h | 118 +++---- .../tdisp_lld_board_st_stm32f4_discovery.h | 244 +++++++------- .../gdisp/ILI9341/board_ILI9341_mikromedia.h | 130 -------- drivers/ginput/touch/MCU/ginput_lld_mouse.c | 10 +- drivers/tdisp/HD44780/tdisp_lld.c | 10 +- 28 files changed, 768 insertions(+), 914 deletions(-) create mode 100644 boards/addons/gdisp/ED060SC4_example_schematics.png rename {drivers/gdisp/ED060SC4 => boards/addons/gdisp}/board_ED060SC4_example.h (100%) rename {drivers/gdisp/HX8347D => boards/addons/gdisp}/board_HX8347D_stm32f4discovery.h (100%) rename {drivers/gdisp/ILI9320 => boards/addons/gdisp}/board_ILI9320_olimex_pic32mx_lcd.h (100%) rename {drivers/gdisp/ILI9320 => boards/addons/gdisp}/board_ILI9320_olimex_stm32_lcd.h (100%) rename {drivers/gdisp/ILI9325 => boards/addons/gdisp}/board_ILI9325_hy_stm32_100p.h (100%) rename {drivers/gdisp/ILI9481 => boards/addons/gdisp}/board_ILI9481_firebullstm32f103.h (100%) rename {drivers/gdisp/RA8875 => boards/addons/gdisp}/board_RA8875_marlin.h (100%) rename {drivers/gdisp/S6D1121 => boards/addons/gdisp}/board_S6D1121_olimex_e407.h (100%) rename {drivers/gdisp/SSD1289 => boards/addons/gdisp}/board_SSD1289_firebullstm32f103.h (100%) rename {drivers/gdisp/SSD1289 => boards/addons/gdisp}/board_SSD1289_stm32f4discovery.h (100%) rename {drivers/gdisp/SSD1306 => boards/addons/gdisp}/board_SSD1306_i2c.h (100%) rename {drivers/gdisp/SSD1306 => boards/addons/gdisp}/board_SSD1306_spi.h (100%) rename {drivers/gdisp/SSD1963 => boards/addons/gdisp}/board_SSD1963_fsmc.h (100%) rename {drivers/gdisp/SSD1963 => boards/addons/gdisp}/board_SSD1963_gpio.h (100%) rename {drivers/gdisp/SSD2119 => boards/addons/gdisp}/board_SSD2119_embest_dmstf4bb.h (100%) rename {drivers => boards/addons}/ginput/touch/ADS7843/ginput_lld_mouse_board_firebull_stm32f103.h (95%) rename {drivers => boards/addons}/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h (95%) rename {drivers => boards/addons}/ginput/touch/ADS7843/ginput_lld_mouse_board_st_stm32f4_discovery.h (100%) rename {drivers => boards/addons}/ginput/touch/FT5x06/ginput_lld_mouse_board_marlin.h (100%) rename {drivers => boards/addons}/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h (95%) rename {drivers => boards/addons}/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h (96%) rename {drivers => boards/addons}/ginput/touch/STMPE811/ginput_lld_mouse_board_embest_dmstf4bb.h (95%) rename {drivers => boards/addons}/tdisp/HD44780/tdisp_lld_board_olimex_e407.h (95%) rename {drivers => boards/addons}/tdisp/HD44780/tdisp_lld_board_st_stm32f4_discovery.h (96%) delete mode 100644 drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h diff --git a/boards/addons/gdisp/ED060SC4_example_schematics.png b/boards/addons/gdisp/ED060SC4_example_schematics.png new file mode 100644 index 0000000000000000000000000000000000000000..0d9d095fc92830db42f5f2575aa4b937075f0d50 GIT binary patch literal 305333 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ⅆU^u;0^K{b8YktZZ)3)>e^F!D^3e6Aa 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 zËp5)cfCaAzo-i7XA#Lt6H#HvK=7GDPiq@izvAPvulTLQTP=}qb~`W7f}LzZ}N zpIbjMf4C-_l+vVQR3Hh^gqz~iB*A+gKk4_#{y(PPJDkn-{U1-nXw4d}RipM+wYM(B zti4C6z4sy!Yi^%Wp^SqzW_xDeZBgt{x$$j0|d0yvu zov+tr3c2*f&;PIhDdGhza*)yS6Un{z*$YgBRe(u|2iC%4FdIRU4l&>q(+6~fQ;Le^&hNj+UV!#>JJG2N7l&KN+ zwHi`k=jaO)F>6%3&Ec!pub|!&vO5T8r@a12rf0}DC6L9p1Cc)D`J~et-Jqswua5=W z-?tt&TQv>4=%Wae6@Qja-S)*cCmI+>5#q{u!Z-v(=j&PcmBA0e*XzrHan^_gp z57EqUQuSFsIA2Df`2+{oIx{p`E2s1x#+&RoBhY7pjc(BP<|@CFAQO)lk6YV(9X)h| zzbqHQUYpbx&_#+ft;4VK*zm63g+{FY^0}c`c;;AV{CHM(#inZRoJ2`zU0ed+BxefY zJsMur=B-TkIO&EXM=BlfLvtCXFu##Si%Re$;UPsWG}k^s2d+1iUU_Rh-?fj*|JBqd z&m#e#6a2&^9`WV?|1fx1%hD2k-R~XlXSEX)*CP>Tj+SXTGwN&1wcE{yo4z5msk7Fv z1b>+Sk=aa5U_RhTZ_wcGb5nqp{wkR^)AKh&$JF7|8{BU`+p@+t&b2BE`FXLi5SBRC zuR;s@YFqA)*!sN##$N9~KEq$f>%2I!qrA!G1_KcGQ8zYQWd@StHYuSM*GFp+6vorj z!|&QmNi{7$yu@1>FOsQ>tgE#IFu|w#3j&~uPSa1k7ti6pDju^M_0;xP{UBRz?cyov zO6WS#+z@laSufytDovag7WRKH^8Sok_4D&4)lztfMi}^1d{LNod$M#XRA#W6EB7m= zU)RSvYw;fXe(l2GPul*TwSgk|WeOV(?xk}zQp63}%&uKvVqpVSG%+6?sja$bhnNt; z3|qJ4?l5G!kYzE34iBlw)Z4|nz<5sb1pZJQEvZUELi8`f-4mE$O9A5)L~U8KL$fql zY+2A%H_+|+RTcq`O)kt%}z(B-NZw5 zC(5{?a5|jQ*P7VV-T76Hg`Fg(XNXn zebfPAhx_E$=z-xxf3*Iuxpt{&Pi?zj7|C0>;I!3A++LEpIF#Z>blCmL2fVBGNDB}8ZE{K6_z?1TJ>VC3u@EfG*FS>ET$GaP z4MZ3up0LJuLM#S3U*6Ss$w;$Fpqbx>U;oBy#YnVRhV+M4fE0TbP{l6@v;=*PGnl>4 z2I(y`qLR2{8={-MZbt$bMsu=eP;y-kwXFL*>kPS(x4H0h19c z8>X{$71%LjD`Sj$gOBBWc3{v&)E_!*B$j5wP}37e<8VS!1*tO5i;W?%PxqUV36)xk z&z3MmZ=nR$oI~>{VmQ>%PeN6&eXs)n2)&XeDhui&6C;-S!hMC66N5&P~&BHZRv^? zSp3KI$W?gKH_{pe5|| zkrC>CHn{!EF(W8H&Z+9_Zpu+%sJv479Y-5~y|sN$CfG?^q6A}&RM51q-Td2t>w6sY z{adQ2vs*14%!_L$J-Dh|UR{I73;aX{S+gF^{67~TW|DO#5nh4bKsTsN<7wYI1N9Wy~cb(IDDtXp#wshMbCkB9guh5>cj~?{w;i5#G0nYDh z(bZ{m?itVaB0f2Px#jwqNqm!hh<1GCXe(iDs0vj@vQ|7CEB!4I-{a>#S_Vq$!yvCBpC3bTB=c|E1E`SWU=&>P*j_PAZ6 z=q^e#u`uFOS`N>s_L_N@Qp#F%z9cF* zIlX~Ps;%t0(&Wr)Lanl9*?Q7nKKq%DdJK>SRJq1L8Kpl&*}0sVbjQ}ps(|KM^}XO; zxQtVr-$3eEqGS9_EUDP8{q1p)Z+31)(s9=9cHAm2HF*}ym1%GWkKiBE}T zrOX^Pu>O*R@5HJqO#!+2px9i$wYTm^&V6LL(^O~kizqMWU?XF}oi(zSm3F}zK5rh6 zKS&Cl=NuJLenqau5{XW+kDY_Pp|hqaymN4L!%C`aOg6n5$9!|Bx{eP8fDX&HoC<1b zZ6oT-olUG=%-+8|FSE|O?_2s@xlGd1`664x9nzmKR16q>mc8pyV2Y|l$5y6THYw%w7BY5Yytx^Y!|De$o7GCWwWh+A5S9T| z4oT)N927?1o<_*OmH*RD;%V<(-4`g1HI&5Vy|jLsTp8Q7rg9_ZV2f=2mYa|ytEoT) zo$GDemrH%wbQ8v*c6V4#xz8(7Cgf++B?g8%lkvGicJ|J8+H+L;OX(z_O6sl0M@CEF zcdR&B*}drW?M4OX;B9D1N9}=@Tu$b{1coYN1u5Oag+_q&~_}DK{T`248q~qZ2u3XsajAJ(rG& zErp$pTvCxrw%J68kUikWN*8};YM^2vYnIvH;*Z3N+qG|!CQKwU;6<^tZ80|~Zw6%r z*%+gZgzhHo4cq0&FgkW{c+lg^;ZvA{!NNy6o1a?xHoo`Q!XyZ`O0V{lQI5Qj&y&p{ z*&5}==T0apk5^jZWE`kU+1sL-_iZ4uJ8XJKvExUvc;Pf%5)q*?eVtM00`~A#DDhTj zV#Cp$`L{<}I!muKzIG-k`Y;qJwe>`-7@vZIvOhFTd99sM&fG<3H!pYdU*G5;*WuIm z2zr*?ks_SSVMaU{N|t3~*mMzO<{SQPWH{Vd#x=cCmZK3zQPo;2kbkGb)!byq1}84n z9`jaMT|^ge-Ph<##s0Y68EO$+Rf0+<9T6@|{Wu!Xd~Xz>7=D-@UJ3y?*(Ua^UWms& z<5hmDk(*iKl2TDR1Y5JJ{;Ck#5Xo#rM6q`MlH_BXSl3s!FT(2IZ~T6JLWuGW+wowP z{0T}OFnQhNN5}0DzdgH8clzf`YrYc4}6UGxJY<$*P8CA^eb*y8AcBqs$F4j z_xZSXA#V06iIQOgop+WO zIkcPIWa-ih%J0Ul)YXyg;WC)Utx6FiqfQ4!o~h&qW}>+Tx7;}MyF2N+c|~)4>>lG! zASY`jG=fv{XGMNTS%8|~g4#B@L)WzxZW08Tv)*hB$X!pq45Q)r37yS5l+ z5V`wSK&fy*AksHX^TO`UhZ>5#drUaXcg{N%gTM7Y#OQ&dtrsQgEqMYfBp|+4avynf zdMVY0spZpm($#l9h`9JQ#+4-8+CSm8&%HNW9?Eft+56os%9|CSv-y=H7H&8B4Gq{Y z`Rg3FJ>RoDicR!AqU`3D_DMLy??rDu!gj$&MjsBD@)Tmsik@DCaL>nb6nXf$ZH1q0 zJNg0)YX?L=4|9d&ee|@$e)2b`_~>mUbXkN0T{F!sjUIKaIku2{Gg8yY(l6he_`NS$ z8D~UY)Kul7i(nLkY4q;1!B_28Xpc@HqlO_~H>UA#5LA97>0~^35I}Ip@yJ33DcAM; z5ET7Rc)`bMb9fZT#zENyFYel_8b7Rp%5qB||u znjLB`q79vU#tv{r@a{PYh)v#OZ1=H)banb5_D^~OR!+!#J>$uT$4-?cObanUOOL;* zV?XUW-tWbWp_c8#Q>s2T(^m|#?#@2dl~;=?I%C>SpBE_n}jdLmD)v9d}@5XxRDz{ znz^9ar{}LFRtD-$>&3wEq}HRPc<&T5M`V?P%qe86^53kf7Z9J` zauErAdt39x*n!qS;(hF{fD8JOf{Y{Amq+yT@vMIAq|_4i2H3KPaTnj<&fvw=K&aS8 z1DF;(OEaTb_$_BZz*-s0phPn1=afFQbsySYR<(F2vvcKK4?4Tn%tMGD+W{K~-}v|n zVcY!KW2I2&S@r_?ywE5HFU7tc9l}uH=BzPUm*|JJR$|0mHs84?c#F0@_2NtGHQDcY zs@=Y}wesNZ(VmZ<>e=J>_hfdq_TBsW2B)kdo!=#wip`M8?)_qRcJ65aSw!4fiIKHG zpnH+f%M>rn$dDKRIiQYX{_9bY)NA|$ljX&Ncye-va%~I$kJ)&in{$q*LD3S68WWOV z))EMrX>xIlXIGNdqgoML6iWO71?E06LW&epy*|yJ_+wpjXS;SgoN%;H!b6~S&U087 zw#ovOu_$FP^=aCZ6roQ}el87v+HKyxS7c3e^SQ=ClC)*+ET{dW`O>Bz>uMvyN@mX8 zne?&^?~Qd6qXXqiB;6IYUFy z0F0J5sHpDiq%CT~`8Xmz6OTK!->Ym1s{q+aaV>T5>83vTi;m+Wjg(7*EX7|XhT5e{ z<|GO`n?idP$Ee><)MuN`CcbTx9c5OM4@yz$-v8E@;0XI*%)z9@A-grj&9!D${Fr*% zj3+O-LZ{NpnGY(@JwAQP>FTKWaScnZdm>|4&B6!*Mx8%F9(=Q{E~qp^KWV;WBu$3U zh+W`WaCa`^tt4*8Xg={3J%j+v#-leV>Kt#39WSA^^xB+{>k#=sJS^ap&gI4>$x6R= z;<%AkM+)xKRFJ0(%!Q0Pk8sMDzS7mA+@AI8lqf`*fmFzu|J<#u(%H5@$jbD=y=^Xt zF8lydE5-v-MtzgC+s@^hf+40~nxTq_G;8+c%%}b7 ze%Fn)tylXDA(_BrV_4Eg^{2;kNyueD>F$>%*LI2$zW;B%IwM4jf61(`_AGvG!mT&A zc`do*vMH#unptqY;*;|1#m8gm#aAv)y1{huE~{LpN74*t+_UdruF6Q%56OFIxd%Ao z`-c`Qi*0}hxE-hRs{`rXcgndA!751SoANsf&Z(FE)fC~A`SxQxuMmz`(|Mr>*rWtuFky)Kt-8U9N|1sW z(BI#)!$v|km*s!0ffkD|VH+PWIv+0ReiXqMESb)>8=#mD=KEEDuKieAU+Yz&>JAuO zy1sFB!R?!-(hH!7I?6-!xv0#vmuk4^BZr_gk_{fdlCn<$_RyRI$pQ7_w++hd*>jwQ zW@rMKUpt&Wv!{UFta4z=4w@6>X(i;vs=Cv&TEFQa14nYi_8t z6pl$LiE+b2=%(2|$<$?TvZ^zhqrPlC4Cc!lZs?J^FnLGJAWL+S)!gS+y2PsF92w${-EzJpxtkLxI3R(^`e zcKD|17kSsU-@C}(>i!nk!52Xfjrr_t1}Oi7Tr(bdA|MF}ejr!1m?Zpo+o-Y%;pP`K z@h^{`^!q=4X(NdMx81w+pC?)yCp}K63}8}Sbgmi5k?+z&_!)C&;fWKulpK-sbQ}!% z#F>)qyaP=nK+S5Kd@zqJGAC0x0h~w?OZf53BxFV2vi@^k`krgaXyJuPWX-QP^9o5{ zcufz=!A+JwdlO^x<@Y`d?0tTrKP1BOITL77O5D2IL3vb6NRp{nEcCS47>wcYa=spL zP5T@IKqJUOEAa?+0IG>S(6C5z|DYG5)EAQf`Y5;7tL+DEnbV!dczFZ6K%K1E`lDN*i z=dwJs=n4Z=(_6Z;+$+U(^tHA(xn>PH{=;Q&*?Sgo0)2 z+JK+jPrGMV27QUjLWa5pkUGXuV?&(-qOua+I=M=AH}q&qiQeQ|JQSSw)yt-0N=qi9 zaluUb-Cvn;q;ql{_0a(ao?V2f(sww*v|hJc!oWV@>K|bN2b3h?KSq~A9L`8$PyA2% zWHHdoXJXJjq%s4OtBvWLR z67{MpEIIQ-ogx)>zqLP`81eD*Lkm`%B{4D?R+KUNp+X_Ux)g!+3ea;~l#jEFNL8Xq zY}uZNH&edD&mfkPtuwG}Z*`JJ*0ZH?n$@bt|4@#`eM@~85?{LdxSp1803833?7_4_Ly#SoKOqzf%A(vNt_V9sjj=+NjrRljF5;wTm8W8V*p4?_{td-I;%0aZ)W zPq#6NKSAGrlud%)XE(L5i;;EsYb(?yP|!xT#%FuYl48VIw{AWjzIZI2%us*<*i1)` zrkb~_q>MpKlPuGBAMCT6^sj$VzNLTNATZ4}eI-pm0~n!k?^hU((x0l?_LfSp<**3! zbbYzq@Eb2^=5+dbNY6XzNZJqM)VHS}ApP>!{77RncW=*d%i^zpQ#Ry1KPOP?ihr3uuj`;3V4PqUl$c*G0 z?p|E}<#!K_Dep;rlXr9OGBY1FQ|rOksQa(9k>)-rw1l!7ev?dr(`bskirU1 zG6%ty=a&}|tjEfg{*-==9ajqr{_@;ReHqG6YY_0I-pf%EotbVXnqWi;0#}#g`=`T4 z`o9jv^XcDe)~0(A^H=Q~5S4erKEM4Q!Ia6#Mh&pi0@?-@i8*rwgzZlVjixblQQll=71h%D zrg_dP79ZjRwGhYV{>qU1JH7aC2S2`qZX}SSx0(`~Q$NXKoGplH1p{9h02>xCr#Vsh z4MEBOz|25jo=lcX&dw=UcZtZL!p&FSzcW(u#3~;|+pKJKE6QXM>S=C_S&fV;xUk z>Ej*ik3Uo&C(_r@7mm+aA<`pf%Cmq@E|%s8Ur;mASDpFplbe@3W$1B%nS~-_K7nS z=$UiDCpohMSTIz(=OWCvxVQrI$?3mU{omp`|6B44ez~2wokz-Fklqw5Fv64Ie>gt8EVN!heyP zl2y3_D=gU^%YJ>J71Gt{U`0nSlS>3yCRC}(f+Qop42|3>qBuRGSlRh|6u|84lEMmEmAel8D`K! zi*FRHh^#=0O{Q(YYV=gMHg|&}! z_gw3(;UOzj8vK_`eKLg;1$ejNZY~`?6P%AE0}RMTfY^^>kch^6wC`J*Wcj~K@~KMK zS8EUSf~vD;a#oYDw;TN2kCScs5--)@6`LS zU^2-u;`vKZSlQ6ltNC{3*p}Gcp{=4Xe=KHQFY=kP8?T-s;pK@4D%fa!RN4ep7gBXN z$+5~CAX456@nb!6yyfO@|5>0sq(h6YM(VQi(9bWIcRP=^YqvKoO_z#t^!%B11Xx9? zez&4h@gJzlzngFMAE@P+*x#p4f_mwEY-qtI$?63#!0Lly$f`V@EY{giQ5zG^GSats z^NUUp)_H=lf|j*^H{XiC;vUi4Bl#GTD)JSB-XT&Yc&zFdeq_D5!GbR`~o(o>xS{ynh9e-LhVukCsAp%_2cdp|duR z;ze5KUbG};q{QGN2G!BhYDBcFX(>?BL`2%_udmfAXeKKRTwV{&{$g89c)i=)rB`o4 z-_hh}q&*c@&HC2ru{j|fbSEa9ziwL z=HHq<1MsbT)LQ7q4EKME5lhdGvC$pqQ z!?K{%-b3nBzs_67+bHV=0%-J6h{*In<;D&BQR@X8SeyT9ra=gMe%j%#^=!v!6O`b3 za_r__vK?O>aCAzxULbw+t0oT%C;q)KIA#N_`uIi4K#f6!50dcrIO*{?#(sF^uI5Jl!3 zd|xM|SZ{LYvHi%*aY?g;%!)f!Kr)xj>~1Kt65ImqHtWE)R$sat~?R5b<0OxOBC)Hy+i2(<_B>@6l>*A7Y91J} z&5&aDm9I(39;Of>kEGkSV40!IQbcySH1IDScWFqeq8`8S(gOq669a8=xn+EeVGUYy zHN#?Al8lf$@-We5mKW#K_d~3yI2FzK4FM9a|92jZ5&wIr8d(mWazwtSfk)9?s79Qy ziJ6&n_+8*$s==Py7BkW!o=MRXBPhrjHrwUOwDltdY=Bh)2+A%4*TXM?c<*^zj2 zb!M8@;=4)H-J*38MmoxNj=MV7y;yjXNZ7?=Ml~;}!>@;Cp5i6FR)+Zo26Y5hZG7DM zF6;u?xo*V35%int#>r;tM7sme4c6IaRJxCU`=59XvRF3gHh3oOOgv4??HtJ7z6U=u97-3|dOH}qaL5x}B25g&V@W5R081vPm_?clD zR?fcZ4_?~DLb_pVZAGkvIy8l}S{vFOKRWiz>ZpE%g?FY?Io(Y}%fBxWSuGqDo_?xx z8ChK27(G5BMVyX!#gX~Y1Du>b;4~9Gb-bD$WETGAP%abnW|B8Ugxd2{mZ5#W7&V?+ zg5-Mwb?G#mw5)x)^#`+q5WLK?VRJ*0r#Q_}OAvTre2Mgi8)|hF4eieeovIRaQx*X3ePGrx1$?g6AXSXQ-hIqyNRV$&`+)}SI9SbCu6a7RbW{Oz0xn2x z;LoGK$10!61jRQXHe*vg?(QrLaect5an%;8eCtX5+UlfgnnWtoF3r%MDBJ( z*iBCOt;Gr-W1>k_p3aC3JZbaHaUuw5C)Aa@n;FP$uy{GI#q~L^&K4D{bLD-qO9Vqr zWEr;Rerl(zzk~saefFP_?T$M{OeO%5fG^?s5=V1k+GrQ4+y}Z(yAROs9-zBTo!n`D zpZl?^^BjXDDs{r_sQGPkuNgUPY4Ai?>+ld8dzsnB05Ee*bVHRsciii%iMGNvXB0Io z>4H~;N-CAiFxN~#|2}yw!5||(5F+h-oak#$nN^#sB+;qJcDfTAr8BQsd!wV2!9ajO zjl1A!1Y}2Xwq2HG{^Gw`+0>UFWP2#PWW^` z@xm4_6CbhuP}F7hQsr4Z>Ea~%Ws*zxd2yF+^;fkh_hM$H^jj&))0?z!KgnlZc~pR& zjMd&FpwX{(P0u9@6Qi4q;a8?I8t7`S`X(Y0g^g~sQ(vSANOp1iK3Nd+<{gPp2Lua$ zp$gVLNtYvU5lzX`^~>l3QR$l0MggKR{`puj|MDTH&;x5NC7<1?YLTn-C+XM=mssbk zpd#1&M-s0!qs`mq?K0*1_6II~K;8{e);BPxbrj>a zQ=7sx9&s*83yO)o@^N=&L>)=E<#u;DAe4VO(#+lO9fjwTwS~-UXoOdRZhL777)hE` zW<`+LZ(h*RDUz_gdTIC2*c>oYBHjvR%PyXn3L=(X5UTrPP=6l|!&oq36VEY;xk@OoaVWbcI5uXBMB$ERH` zxEir@NkQ9NLZFMxBxvU-BtSE#>W)K<;Ig#k=58B`7cNGouATEiWK#`o7B{UG<CGX}R~0%)7duxJF9?!B7*oHMO1q-YF*e!2UF?o3e((p)4hYTI z*5Vtsr+IB4)&lF94|<*ldHGlzcM;Xxru}3?7204Sczh>n@*Jg%3PiC?@ZOn;&M}O7 z|M`%$KFv`F5}BU#8Dqgy2~At#pq>|5AAcZt*rIjyI-3SN*LHBEWCeXf*uXU6r|0a1`mZ!b=Nl!} zTUH#1Y`>)cO!$Fnn7Y%nqk)<4=h8S$nKVUB>q!f(+PGIlKJ=gK6+M?sro9vIe7WJ!iDmWbLchZ62vS96f`@;V5`-l} z6j4SxOph2-T$cw)`u5L`t9`(sx%AAR|pt z4;NaE;soWV>hK>B7O<2?;zyWK&DOXq_)iI~vk*Y(u+1=A>qBhrV9T_U4sjlM@jY>g z@D8_n(|skeE|O!BwWwQr(|FDZk z_&Qqz-}0?NB*y=IOI=KOBLQeL#y_Cz??BzPdB=LR$usTIH%wZ7;5l58ouScEin`k6_q^ z-J-DH(FHNI;~e(5>rg9NLP!=#Gsmf((*Y*?_6v%y9xKNKc*Xb=w~h~}p|1yl;TFL~ zh%QHPo$ zD0gjldP2*I9CqO4gDH=qVGEGpy4~Emt#Q7bwc30?PJVcE&6IFWuH>`8R%Mupv>*7i0oZhgZjAKVDvgl0>mwyxL!i!LPE}Z^p7;kkv$qIc+5UFWA$< z|8vklw4&(LVovyr)6gg$H(Q5GtUhh*7YdlF+@Mvlltm3*%D_-L=<{(OY9GIlyl7l5 z_HJSc|Jy^p(d?g?5qODDzxwxYm*xVDy2>E=qe!j z$T1h)(S-v7%>Q;k`1IS$9W^aMX$Kq+_O`vP!xI&U0wd~dWKrhtp7$aq@Uo#dr-{uQHUMz zV^jj-ARh<@nq!LgL{*_w!}qf=AT#J(DPwYqVREXJat*t$*Fw3|K-~-2byyHg_q-wC z|6Q@HZ}m!Y8X9K$D@GUiw6`9gf}oGBAEdIEs?ikZIG4eyL6P`PTNP6+WhV&M07FP= zQ1va@HuJL6<`q;!Lr~WE$^QS=T(EdTvW^J2WxxhljCrWQ!DPsKQF~IXf&&X|@sMYa z1j`9s+Fo@mo-mSuhzZ8*fm7%Bl} zj%CN*!|bLXSwWgG(I4uDt56S-OJXNxWWk@dj-9X*8!~u%1A9`;8h9pJAH9!~=!mk% zBty@M_GFWgJdihJX2aaq*wS)`HwM1!?}hw;am!_luRN+gJ-M33d?Wp6=X6Bs}fas=Bv6 zfM19W8&t_Bxj}k)%WaN*HxNfWLDpcMaiV}prY$Ot5pb*SlylaicN5~;ccB52BX)aL z==~4(_Xs+eSGpUYdGa{dH~evl2n*IvZHDNO4P>qs8Vm-oiMXwNu-0MfD^f-nPXv#HYo^X5>Tzext0xs^oLP+y9K_s7&X7 zE36cCy%~M1f=ou@B{5brozYy!LHB3-#*iUA<)BZ~?nSo1cIre_L(<-Vzf>zow5{R+ zUwl-_%0{a_#&Kg)4oDMqjWm-))Y)1JcbAlH>A@m^aU2MPpTo zbm>7nmE@81a+Mkh z;f~LH9csPnu`;8nKqLohzHv&!#?fsvxPOcNAZkNK^<}8H%dP`~i@nQ8+vKSGf3wBwG3PV|-4%1g4K#5t%t#zPIoOX0Kd-bN6Ks;wirV|HiPqhooQu^I(W$oOxOrBjUnF9N*N%~v5USuc+2qR^SHGZC*< z)Hoa*0a$h z480}`@o5V4W+j@QQ|Xvjt*-N?z&c}a={T3hmQhPPB#{ba>q!KIZzm!M=HfA)C&gUc z`3k`uD<6*~1f>Ug5c$kpn$1poAyqdDS=%72bI~>Ps_ny_$;2|Gy$!DCqFnMTYoc>t zPao-IE}~Ou8Z-84(bz^WJCKr9r|eDxK>yVx>Pwfh^_>^vLpRz_ zz8byFq(L9g9s!bs?9yN5|37!x)&DnS1H4rKc*_I(-J4u;m$Dd+iN z?RH`vDTNCdSwYE@l^9zzlYN_iBy1EcNjrJv?IGtLFGhUQE8_MZe0!;J?A0oaQ5YA~ zZh!{uQ5!JZ8z|@{qlc(~(WFkWwF~ZSpp^>tW^P7DN z>vo2FQ0Rcl(><@bdAo}4qFR=!<^_Ur{esPp*C6WsrF_Ls3>d3v-!b4(BRmaa)M|b9 z@t)*mqoCVEd-uW(lxd(2=wp=KFsX?4+O+-T3aT7cjrpyAzc{B?7G}9TG*H}n_dg## z;dAFd5B>z#L-&1_`BcI;331=k48rCZ=il#Rnvuw>Wp2i1uvvE(j<5D)oA#dmlG-8N@A<>5G)8t}&4{3Q`|!$( z%bRN5N#za?FtTg-x#a7eHKOFRd;p0+{G(ekX zQ(hy_1tAZni`QNFRF-nHUkc0;sDmb*Jnbk%RbT0o=+!Pv1rj5DG8$wJ%9f>|jG#8m zWfl`YM$q@xUJU%@>}8GTdCaQJ4JJ2Sfz8d8OPTY9BwT!-Q`&Zn{>I3ECRz;rC+Gn7 zTB;yMoJa$#0ktG=wnaxFeMEI_$wr!NSZ}>XY{SNa+U5$fGI1*QJ{U8k->Jj{=+9~X zeJRq{m9Q7Al>!GU9OM^Np@rg#((zNA1l8N}S@Fl(Gy0!qVVm)wDB%El{8`Os&EGbI z44_RSe)?D+ppe%^#ks!kuQY)F@L-+L?Wwvj8OvL#Z>&1od#vlUpNcBQ{0^}iSX)Ym zzoa+18F^ifEtJ9h<;XaDAQWAKnnM}V&lY>c=D{Lhr2BC~!IxrKMEF@D4m)nk$dW zlR(;KG$`&VLS-{k>TTHRLJ@bFcke>c?x;wr3>w~FCHdf)Pj|?JP^=Hq$qiLgr9xzL zVqDt*#kfV|uUEWaO|UcJO=nQ~Zqc(i1VU`EL3<8%<w_s10td7(%CK@@L$y z{pZ5aJgn#?wts>cEoFW5Jdh{M;YnhTU?r<>fsu3)iPod%(A^(cem8e)Bp)%sibUBc zXFjp$fPqWe5%z}1hUy(jg2-Ssq!-$HA5Ddlg}ni3t->L31K`AC#T&j?5q9bchD&y6 z6L|F1M@ZZa-)uw|J@?Ux2#%135RRjr--NbWqBC>y-XU~hg!Eup2rD>7v_hP-L^ZTk zhssy>QLZJ{(H>v7FbUTa8cZhfMn;9D-cRC%m$kO4jvTWhmn!Xia8Vea+31SHA9&|A z(=9MiQK81tDkQzH)}xU`wx%Eov|C>@*#quoT)0A?c%;%ezYHkm*)~DmfMr3sM2r}f{$oK@EQ)c1orb=;$Vbx>*)PwzzPWnT%;g)07~~zET$U)0 zp-uuvd*JS3nrN>+R&{H3`oFEG0Ytqlfm&C;WpCby@x;B*%KZQuR&SP?S!;Z^V`*7IOo&)E)$c9@uu!*=P4y(|IjUK_lo z6`pzJB9cfhDQUG#Rb;bVeOeTE?PGLi6iui(`t|n6s*-#;F+l@lw=;~5abl>BW!#8a zN~0Z~q@5$p_c>&}iw;Dpx`u=S#hbeAkep9esR9t1y@u^JkY{pw139fu0n2IIb|#PR z!?a7)-s7&E?fN@GD1Z)Opmoh7W~S2|ortnTRixV=QlK~ng1KR4aidLU>vDJ4mg{|Q zIXpQljZ@pBYIGM^l_l`OGsHJT$}b2%lTmFtny8o-9kV^&R)7tQfvw_}(mfsdNAiNM~1%F-s^?-<2&8lWS;x*ngva)mZ!D~EmT$|*jXTbwW!qQ5M~ml4~N zyls%CwO*<e}iVItsYlQ{=m z7kujd9|g{GXuEk!jEh^0sD#aM8>$Xo1vZ{u$n~n$HD>%sjW`v26cq*N`>Z?s=XNogVKN~W~*rK$a?($68Pr`!nJ@rQ@i$Ei1xG?3VIH{ox1%@7*na8 z;C|*Fq+$py00N&5sMD+r>LoIyQiNVYe|-zt!K0a#O~>LQadG>=I=F z4$_F8`@?a$IJ2cXn~mW}$Q1*w115|-UBFubUW7ifBQoZMw^-^dRf^I)>2xG?;g~*X zb4_5d0sv0e;r&-Hhfu#;AGFNI%6f$`kytkEj(y!N>j!LGIlk_PVkVYA@&L7`-EsXw zJhr(WHcAI&5+YnK9>=B!$8ZwGHhxVki$ndAttj&56@|QW!$}79F@u%d+7z7@#~Bc5 zelfIiOUKBlz@ek~u}NXsY@mjptgKA0wKg5;8DUJrzCwy+z%U+8s9=j~xdi*ZAm}$>_vr zn~)oLIq1+eibw-Upl=kThiq&<#Wa4d%iP=vDc1sGHTHEZr}0w)BV8ALc+gK(15!M- z!_RH9)zbnlIBCT%9xX(H+1wR?=lKny$Fs|Jj;i#)hdqu!-;jQqV`x_!m4`^5tNcCL z-4|UjwfcvDQavhf2DH+}sNy+W<8m1GM_vCTA?E*LC8-%ow*{W!{sAM@D6e$u>B1vH z)o{`prM(ve4-bQ_HF?;KPh=Tp3O{XrJ;oqobkbZeEzA^~qR1o)4#2#eZ(EW465=jL z!5n*dOUR4VIQhD2$fXG!4D9P8NvO7VczZ&EPlGL7EVUs-Jm@hCmw=rxZpnl9V6c6X z0)jJ3cEl|q3Ft{AbqujL-#~P!l)#b3URO0`FDf)d_v%{Ke+EMJARF|yM5>7{K>6}x zUN5gXK?6v+@#;mKR?XLD$`ig;STKf`y=l?$NCG3%CRTA1#{sAwRLQ~?hN16x44L_H zA#UyXs)N|*|3}q#$FuqM?&h@_D*SjDxRfhA?Y{}`4 zJNbuafvBx31AngwU78df$IOi5@{$a0RSOZ$J^!89$Uu9tLmLlxu$E? z^qDp$)ndlZJTa*Jf#shPK|sAY#DY{2JjYaIULl+q(tNBDs8P z*OTdc?x*ni`$yFeA{LPOJ=Dv{VLpkJ)wq3V3#em4JIo4hT-1LUFp4r>*OQ(azaMi<_YRX4;<=9+r%U$h zw_AY*Xd-geGkfDv=yZj4?<6CDHe9@lR8iSPNF3d-nJ6Q#4LEA@H}%Cl#4*o6++uNGhaR z)Ul@8Q0aO>ujUL7Xa!e?w_Kire?{H9Bb`Hf30TVKp~mPQI5=1`ePN1T5EuOpT>KbE zW~%Si3exq7v*95#3KK#I3y}OmV^>$M4n6#=yxKAI^y{d2^bZ$YpKRZA9~YdQnRBzZ z;B+sW>(wRiJ`0=p$ZGMF#S7cy*s=f2l5Cp{p;-V2RqIZR!dF0^uu!XH2}^MFbb<#y z3U`bSZi(O07hVfSh(T&U`yC|mdvxvD;(CHqJ$O6Xy5kGcGYLE~Hu$lW3+022bgRpK z#V7cu9OEHRV1(edIw49S_x>mHgUI13#`}(W08nWd3H1yhdK1bemiDD9sNzUxPiGvE zc6U)fCBj>@&~mY|!8{{Dv|_#GSRqt8v>F3+O-s?o)`SO@PAwOkCcpN>ZT;Lpri>-m zKv3Z*TlhsU%3<$s*MDX`khQrA5N75t14~V_dyX9*MJYlEJf{tGFJwOG=9=c1zC#|S zB?@%Z+T-l;Pw;ArlNLo8si4G>zSMqJ(9jNul`dn~{sC;nI#C;8I)3JZ9{vd3@I=)# zD?SLiVoi)B1|jlH3+nMdOuTeRc|)Xkv+r#XD#l&tn9^7DucTMx5aJRCFk6!z3%ngV z!6@x8fhEQqZ;RIPKt{=Ip5WDixT9N*<{L_~RNZ|0-ln3rsuNwA4(BkTX{ z1xBvrUXS?QY=PF1M>Zg|fn!n^Rm1n7xgwFb__`u;q`CCnu+pRqO~Gn%%o(ZWw!7Ua zSDR?&m(yyXPB~YFsW4$^nQdM%y>gXAHG`)H9)+3e>dp^P)pJ{~CvOWtkxN}z*1Thd zFMf-sWl4Fmi;itSO%cv7wR?w63%ZMs&rj2ia;A`N8!GlSr*HYj zPA_uP)xssN7cOtL_<--Yq@p)5CsMp-<3D_9vIoHDO3yFg4C@7Fs9Kw>#InOjfk9nd z)5U7Tw7f@``(TFqkrTm!UiwpU{RRZE9=;15wYK`k(IczX^Vq<^^DJ><=(sSY8XN$4 z^0dt7*~+m=F0IxVfM4`6Yg`P~*);I1>>?XGgZCkude3s-he|57>5m-YYOq!E?JI$c zc9SEFa~vOi;+z2<66`sK(Cp5(@iA941Fe^*;M#V2zB@L6A`a|ZkP%264DA~Xa=|1tANy$8Q%ObOyZ%GpQh>H5k6HAeV2KY*E16@6QKTc_@aE*@0 zLzMXzcHoPQ%EG{h7MZ|Rc32Nk%w-W?z34OOr!HvK$C&Vxfa{JB!04y3PKSQF9e<=c z6teUuF;6mO@P{FyT{R|tBK;-v7A5ljP0@CHhs38b#gntt6CI7e_Yx3B_LGmF?1Ucl zxBydfa|}=QA_^c%2)!#s&L5x96#LgN)bejM|b>n93s$I=A`S{^@=A+gCQy8cYd{ksCeBI?K zBaxvXk0!<>3||R?p6P)$<&lPkT3xL1Px~p+5aKn@?@2Zfui{s68%ghm%XneMY_~%| zJ7K1tiHJe47*DuN;v?oiQ?4ff*3TI*V=2T9#LtgAoScxNUU5Acq~;7X#AwGV%I|qp z-n`a)iZJFtAS9UM??otR7262r=Q0F09m}9dFZGEv(uBR7jao~d96iRn%5TD$%Djem zaOr4wFx8JzS}~HVZ}T|-7l9@-xVO!pd!q3PQIN&#rK4|G1$Ig^e!qXkZQHOfP7pa+ z+1FQUtJr+pKD&tK@VbKAy@F`u{cJvB3_Edjn}<`K7s$7@!-Cj_4UgQbJ)$+6#6$B* z<){G9JszT%IXO{k^A$-qoAQ}El@%1t-B$|i8Dbh>jq*B*_@*tPN~VVO%N?@uZ0Y_; zgoDuX-YIBmLIUBtNoZ8WRdtonR8ld#9&%)l{|#q>K$-jKwx~UoAE=ff1=&*q4GKxS zSwV^(NZaCpYy3_17_k|u;#OkzwFtA>*)$WYo_q5sgQVENzS{f~^_98ClP|=?AcX{K z930_wQ9^sqz6!`iBwWJ(=?|Y?;YTl3?+%h>0T;sw8M{J|DYtFiyhrW`v$lU+YIBBn z(s5v-kdp~O*^XidB~hlcLi-k3y_1C}_<>I z2K_~u&S{i<9pS;m@iM**LrBG>w3wh0S)nYR0iG{Na1;D{bDV=JLPM%%Y!QmfMfYB( zn0)Ij%7^X!6YC*%z_#`Jx~T+x-VL2IbY16xh5$ZxZiZwZ^$wSKmO?E|#m-INbz0B_21#p;w>%yHi&JuZ z>p;Lzdtizu<3``hV_8H7q>v6;vUfgE*A=;)gt1RK2=!;uxzRl~M2mh~h}%mYzpAK) zY+)q9Yt3vGbkbYqf1h`5q1%ig^q5KSR>h$*(R=_YN5Q7a6tTwC2Tzs5y| z`5aIZJUKl1h|f(5ExGMY7Q_>He{2au9mA_@ zlxy}f1v&KdDyj4(4LqP#paJ|njNb>Te^@5Qmw(Z0I;l2==e}E8Y~}0b*`tBoVIy@X zvW&>^o2lGB$XuD!<0F$t4N?3Tka2dWk9!0-+0y+fLpK6-?XT*x z7x(EB1eAb?;EH#d-?*ixK6T7`&PZUKWz(!P((0;iwINsOVtp?y4vvraOCWqZPLlicG(?MM#qYJ z&NC7cSUa9k+l{5O5*R~6tF69ddp)cZN39K)*`wl2PGxhL5D!(*WK0h|DmeSGMwqlUg;rWZ!ZS~H+OZ3nW z0g=R7c5ETvzDQFai8fJBO~t(Y`6^(ea5!ZsT7@eWbb5SRH%0&cdPjDQTU0avG5!_K zk}m-pi7NMy!3TtV=B&^XRN-4|copD~A@Tg2`V#M#y>078;Ig z&JY)rx#Z6T-k@`P><*km6=6Jiy|#Rb`kXM2H~ZtHTHd73kCWD5K~^GQ4zdnn?+YoF zQJ)M|w(zn@#aaCDo*mlhkKodU-l3jv;VR#I0Nx%yh>z9StRsEyp5AMe-Y8V=qA7ff zox8J?!+RgH5xp&JX4k6qfaUX@|4Re@rOeHIfV6#9CQtr6#`mqejSSaO1~d8#r=Ipl za#;LgZBm6=-VHI4budw-pMj9-aECSs5sFkAlCMy`l(VYjNatwM^^h57ulryW8;?{J zzQxuQUyaMM5$qq@aa07{v$r;#-&jF7XA(^D#u90t8fW-o=E%nr_bSXNoGAOijJ2|i zHX`kum(HQ{pIAw;7`I+h+9|mc>-!X7edZfp6%#<-KB)P(T1@`Y3R*1B<3?-Xp=!<=H3tq80eKr_S-&Dr^iy| zi{*id=J-a`u#{0aWf0|wqzDZ*ka;>eF7vmCd^?M;#n9P5EQe+Ag zmu=GxGA?Ml)tAF_L^~grv|SP`s#~GD`O1rnM^81e6NssMbor?vKBrGlDA6Wr1^!;Duk*F_465SwS2(7>3YIm4L+BX~P^Nc=Kj0FdS9`K^LTQkcXxhS?!fmCV(`j;=jw~@$>5zP|W~W#{ zr#_wFh*#@3ZtwtYn-sLy^(8_T+$*yW^D*X0ZmG{cGW9dRKL6B;PpcyP*6gYNWpnW< zUa()vs(#!T2V+6TSBA^uvy0-?vBO~r%BzBWi2y03`7aS>%y$Adyj*t@1LyGqQWCZ_hEX^VCum(V!T*@0gWGA4tbu3&4^A20 zA@sIqM~ZO>v(E)}>vXtmLqq-Nn+Yk_>mbh07q-X&f|8G^kC<;N8qt4Vn@3V)5Z&D3 zzn7uCx}q{`Vo}>IifDOi9S?d>&Vhn zo2DyoKjK%tw$AT$;-Tyi)yVWvGxH-|=C3VtLI}io_8!Y(I}=bZE;*^oh#S<;DajD3 zdrM|Tli?*(1$)EZkUa6Cwu*+m z-rB>`?5_5)DJhG2T9Jl9K&8Tv-o)CU>lFQGe;Cydz=}vXbmhAnaVqC-Q?>-+-&#JSLD##?%83i)?!ETG42g&<&|CA&$0%rp^sfLxV!@bqy$ z?NH5AlHk2IyG|zzDPsG`5y)P*_^xPNx~;yH2c*MNXJd{kDl&FHmH(Q&dpw`F00j~v z5Q6RRqd#zDv^61*{8!ypo%3%!P$KY?B{_d}E0z2}r?#*UpFanBSWiWC*z9HU5{o zSMb;@DS>E;Gn)X^-Dj2{#|9qJ=YU9>#{nK?;tOtCx5UNi1D@R4^NGK@8+LUFgkQt`w-trp8LeYLpQd~nP=hiuBR+#@OusqO0`P&pgzqv0SB|4b&aSDdKwa?_B(Vke*msK& zHxWrPG(FU^1`~^VNxp(83vdIyMXmf3Rjp9uk?SAmAcm1y(vND%Gmr=(u?au~A@JP`Rl-zTas1gmTby!zq)}DGc zAC5bU$Cs;mA_~%tc{&?{C%*MlkOw!1iT|N5fZ%uLZvlX@UuSN`KFG%FrHxi4G zWw-j-9cK&JwK+g4nfRn@6WQg0(v>pvRXU8`hh_eYoRE_el8F|L_6 zT2s0rsphtYuu<9>TFQRWf$4dcOL)8fqHPb@&^?+vzMb;CTOM)9&VA$&eUpuPnnD*% zNa$?-eT(=A?e{|dN$ZJoDw~(Y_7vIW^pX<6x}Z@IA1FZ%`GORNEp2R#XU`9|;c(zd zRgiD@Fe&JK-KA?f+ZNp21~2xQBu#$fH!{|=!*9Tj4e;K+eN}n8-4kd5c>OfdNw>i) z8HF)`%}+cIch$!$!rbJLdw&G3n&!@R;nz*klTwKrZn3TkIT5LtnQo1NMmPzMe1R#K z9iGaLxHdDG8M$$QgvD3Y={n$VM^aqv@zB=G_^6+qFGT!vhq~YOL?u16~~!qzdEf906TVeV15b-->^p{W=Fi5eGz;X zDT;WI7f!o;kgkvSnwav9743CxC*4Hn21cg+6OXDD{{n5~Lu&<$s8y%c1;}PRapRcK zvTi%gpm8UkwJS4(>oisO289-w$g~d&jdttK3KDY&Hkzh}{M7IeM{_T19JClqv!5}V zrRoC9+zdA*vo^_4iS2n#N(SO|sfpk$=W*bR+Y(g1eQlur0nj9WN%ljlwqq(_kLk(c zXb>Rs<=Rvymhs$mKCQu|@t&ODyKz%cDlpL}PJ~d3Jw|%1ri4t3mcKaDdR~8%fB$4A zn}&1($ko*BLK7_1E;-T>%w#hATsV%5r#3XNGohmbTEh+CIg)TaGY)db&^wLLfY7q453c@`9)K4TqmTVvv z_W^<%8z#jQ$8a*((i@+m{Jli?YEvI_7!h=OG7g_IW>}jU3*Y9{u)rhxL&^w9YGIic z)d#4U+T#Tuhn#m(*KGp4DVsF`#i2JC7XOgBBkBw?;9K~LQN_*I+rD;t+}N?zGF@@h zJj#QIMRivVlHg+4spv_0tw3&L2z^9yK9y~Y8Tfq8ex~rBAt(fu(pyL+j&THXeDsU6yQ+pc>V|PMhwP~nD{%){ONG6$x;g?M zP+ZvSyC^wv_&HtqVFCxyAFIn)f^Jm`H6mTeZgovI-;-vsDrKC6j4B5CpRLq;+VxuP z24rtWr$(D^jJL7YZ_!1FPH~octCQBg`Z?S6I?a61>v_SV)< zQ&?N&2ehGM^ZowUMxgz3M0-x&%X>NqP}A`xfgDYG{(-yICRE2sT^ZzMO~>|I?TUv} zE`efPD*IR|%OQo-rMb$Lg=YkKNdzwySF40v-T=^iY| zWj*nsar2AA6H4a?Ghp)}-Bgv;Dx4m6EF@yH%aih_zm*;2afXN2(0+EZvg1~vaj;vD zaCeSSk|}H+bW|U#ne#YB|DoaWicNJ%sA`in3pILBGUFrS>CNh)XS<%w}jQb)GTnow&x6<+< zI>X<|ufE~}(W1ru#~(Rf>A4cu!bptRxN{&Kk+7r=#k4aDhuF9M?>=J{e^h2mxB!(= z>4M`2E!Wt#j%RYJlU(4ttI>hAW6Pq{qmuh%T}Rth*>H$r8=+$+uIyc01(`N*-*;{8 z)m8GYE|loj2Itl&E^lsp3aE-Rw>CiAT;e?&bvr=<#5kPEJd5UOKpw_p%jkNE{{9U$ zINkC_cIHvN&bcL^$HPUTrgPT4Vo>liy*3U46GF3ySv7>I$k|15rA2>*;(Prv-a((( zt@aaF7r~b1m~lV{w7s2hA+@*m+2eKec~)l7ROZ{YcG(5>)S|AhKEw#ZuB~<3_ZX-W zi5K^>e+@#|;I=IdT<|Qs79pGy($z~ zX949yb}+q?O+$UGu5EiA<8R|^pOTX;T(5J(>IFG?OnFZ?QQmy+e?Q-Fhi(JZhdsWu z7y%$8W;wILOZe-Wk_scn%bE4N10V{hanE(?aN-NDmF-Ur9kN+fsE4Lg_?X!_BVgi* zv2je{i)VH;O3(vk2HdTF?QKcAHLi-;L{_UBo-{>>B2uPohh`ZFB%hCUbMqMkm^39o za`bhwD-dWkQU(z>9qiys41@09j!cdmgQ(9gbne8#*b|axsF(11`j?*Kqxi$pb(`jW zm5o@arHr>fkV(ECf<|_kSzG^D_ zGjE5ADmJohcB`etzd75hTvuzZ?-pNJKWp-9VWH+LttEQ$TAuxc80|LG{owl+(g=Yk zc9@FGPo7x8=n=@v*iwvej{q7mg%zcgtTxa9xidd%X~J%0k{xdN8Zv2S+F$0%kaWu;OD- zkLln>(JleeAR0^NR`qL`{?#(ZINtPUgHfLA4zBb7)7$1;nY_rGxxzI*e*;w2t~5G= z8%0~R9#>#Oc*nX!u;)85Nw`Nj*)&_w1e%oztVq!5E)J_1plQjvMbohwJAWeEq9qvl zUdAW7d~bU|+JhZ4+h_}i!a3X=*WDIynw@hS-POE$zBxDQ%(Q^?gw|Gk1cmXmSa^lbtfW`3@| znEpO^8PP?jA*9jU>S3wBu&A)&fs4ZZ1ii!c>NY(lT{9mz>iTed0^68sv+F@fs9y+) zdqHX++Wj3*+~(U>?RfG&c(V?Z$dhjM_{CP2!USm~=>gpB?24vmJaP4A+9Cti|A!!1 zJnbw1oDcMUC=0%I@xx)a>3%cJISwRtrKJKO)Xh*sqfUI~CStf<^AbWgXXlCl&5+oQ zGq0eizKQ)Bi3Ou6G7|Ttc$EQTkyAtpFHE z@yTunJCM6M_nqv6{Bm3^d2?jPs@#oY^8O8f+mY`bdz zymz00?7B1iQ?C@Q;?N%jjQe?*MwIRhHBMj|jBw$7L=xi}kIaBbI#yCnb~Isn?>T*( z8z=Ypjvs4(b5{}%O~Q;N@dlMn@(u#`(Wt_)FOX2|(FCx~NHkM>mz!nYPe1@4wk}cQ)N~=luKDl$8O<5#I z6Iv{w|M@d$tt>E2ZNs>vX79X3m7bcXB8=-UM3zL(AQfwI5OB&yo*a%DI zGPy&772QHWjyYq`b-!NP#A2dTZ(g_8f!h%JI6hwXsqY#fQ+(4cVaF(`@^eB>L2$}z zj}&F*$0u2n;q{zy=GnM_cdreq7^6X24%n&I<0xN>SD766uFAkff6tAsn{yd_ZhcZ? z!)qW~TfFH^Z*nH&Y)NYmebZCSJCp$`K1f}eajt(e`~-1>Em0>iWB<0Kc#$|zE*bDW z=I=uJ*9SA0IX{zz_tr%-g2QJ^YTT~%R&R6&H91wH#af=I@;mia^{FE$T;ryX8D6ra z8gvu~_SyO5$_MSvW)Dv5w7&o7?6VX`8kAj$!&zhV)?PwZ=+ToPa!Zew$C|R{S)>3U z--KwL(Yn}l=B3r`K9ZtLJTKRyF(_ZwqO@Da)aNF?nTnKmV^ufeTXWj@LlRwkfVEUwq%KD!reKfsOS&?22n5#L{V#SBqoN@u9e z2+E6(ZAwj$rhwy_-l|Mh0dXe!+Y=uVu_u@K_4)CQYYj?9rx3QvM~Tghr5RUZ?*OCr z^1e;;5;swU(7o5D^MB)*<`VJqsy?0xM@*k~894ucOXeIp!30BeZQ$;KAwf-=;(`=^ z(0YU5NB9VnD|AJKP?an7aSP>(iVLs}GUR7O^JO#ig`8ix)hSr-z^5-{xaAl~YgFH< zwN3kN&Q9_LcZrTq1{5i#o~$1^bQdqHDA;B9j@fZS!@Q-jrQnhk)SM@jF0!>;e_Y}H zd&A;(LhZ=K0u^5FYjKx9d}=xmbXXTt3#WV1%F8{k&2P+v@-bUB^sHV`rRx1CV7ets z81TiN>Iph}5HiHLqdJ@xe1BI>+3r8n1opv6PZI<~jI}^Ey8~8j00e=&Lg*)lS74XN zan%(EUY_1E93Z&C>U~_-{ENNm_YFA3fS?vg9}|`H5};*suGq+O}+$sV`Nhk@&2 zq|toz3gCq6lwFgl09@+%ErArfvD#hqt&0yyV<=v6ji;YcaH05$yPrZ(@+g->{nxM+ zzlYYZT*TLn)E~C|Z0emXui~Fiqy00LVF=|0tH$^|7-Dbx)VXn~-!!#zNM8!nvm9O0 z`uZl0i@^E#jkfniY+^{<=m4vRKnz%;7pg|@)C=9dNDM`M-tBq=TNV!nh-wxcog@cMbe zE%<+L2MwFI{J%j97Y==a`PtP$v#iF1v>$`GrCTEm{Jh^tp(D5uEY6L4h7# zl<^^Q7H&;dQRE3QL_2h7K2Ql=gQW2HS+tulAcFM@j7XE^ej80EYd@RdAGd8Y2}cyX z2QB@&0Y@uA0H6OBkh*EX9C@%JUdB_` zQ<^ZgSCRhz-QZp(2MB>@oz^kMU(o+TEzn;*a7hZfQT82TYmW_KO7NqU7t9&pDsT%p zP85Lp@Q|8}oM};s6$((ayTPJ290_g^QhLnQhW~t2*pE;-5oKD3sYt%o5q+w!* zoF3o6n*#N}rAVljP!s%|;5o{3>OywdkFEi&m|(&e_P#DJR*K#IA&ACk1-q-n2@+o(nE zm9Z(t^(@s`H)FiA?<>Ucq7mx3`9OEJF~c#e>1=2_1`*(04|poi+_{3^_x^kyN0!BINC-PQ1Xw1p{iN6pLEs3jIwn`^1xsc# z*M-EwP(H2f_eEhS%*$Q%|3(~OnT|dY0HHCQO@Pru9BSj!R?2|pX^8Gwwit1NrYw$a zcw0fo`R}w*?0n$~gdk|nD=yQ7K&LNp=Ttzm3Pcj@LP+SFY}W`?yY_^UAG%^fD9oW6 zB9rfLO`(Hf%@(iZS2T!c35ktq7j!m-o9>cmk&D(D_S(LbX^!{BeiV5SLK56=d~23m z&khD`C5Gu(XQ^x&&UoDf&CN+8Q^aFv9}L@JL?Nl-EP@`XxN57 z>vbsW1`4Onfnu5(BN2v)FmpCJ$nCR8+c!_w&LD2^_GJtQ(z@RV>uWH~DWBLj=QOib zTWruNv^!*bbv^ES&|+sQ&C;X!*j^}H?$Vq$BgB>~J*1SbbT*+)qbA;u0ACx?|0y~< zO)FGp_Kl+>4q_F5^@mwp_CeozZjG;XwWO#w?_}4hzpWXBBE6xqpZv}5*Qe`p;mFS< z4o6Kj{`C1$-p(c*qdJqKSL2JHYdjv+D-v&16W$xz-=_26UA)#)bk%6kG^xdKp-nXAe)&(ev|nb?Tw8Su(;>=ll)~?tX_^m|wh9ji{yY}S z=^ak-|FVY4gV)=xxRiwc>f!~I(K-u+%dW+nEU3f1zUL5M9^H8Qi1JEju5!3n$gB{TNF^8r(ZU_!xGVn?%8o$!mW zV(5w-V81{MXlpf>}jTPO1= z9Z|;fVAgBZ62)p{eT=!_2w7AdNM)?$W&LI!%&;UgBPLj9md&V9=jup!yoUGo(7Ix;m>oKPv$rSU8DuaAw8vuyoB&s_pv- za(bUFvt|e3DL|0?@?#yu@%zWLDY#F}o`H1@q{WNW5Rx;|XUaG=O%;FX)Wx6a5U&QL zr)hG>9z6GRT#_nMvpa{mO1JyX@BcQ{k$?`XN#dK-zJon$Eex+FK0|ZUHpDfS}&NMXcSKCfN??jQ^D#oxu4~$5|ZN(wp|iqV`B); zYBezMyW-g;@jd*;f{hj z&(#3ISBCuWEq)6{qRwf?XLP9P>gm%I%#RGEu1Yz8m(Da0AW3e4V)%$wr3Vle$>P`j z;cxC>_X2p1X&jq3W9NRdH zon=$696g~u|K37xuBu=@nvrL(ilkXRIE5>D#~mytGiF{9Btn!y$QlQ1bly5o6vKKj zG{sktE{lBeK2{#{K{p^J&a5!uD*MCIQKZHoTD7$oszXh^#4_)UvZ|Y%k4JNS@QO=n zsE$TU@+}Js>E~7hw_3F0zU*E&%|98+r!dCAKKPE^MR?Hx=X%$=SH1^>iorwGI zP+;`r#vKKFzq5FJv}4WpYia!NG#|)FUuS`ssyIA6|IOM@Ctw`m_MHEbBGYxf#`#pc zmhQZJOD%;yApSEe&;BIHKm|kQO=!M%$7!x!)_e8@%ZwVT_l392Zy9m^tx=z@59Fog zr+1d8F$LOR{cVK5hl@m0=V#FDSg~v%YtR+*w}**3NNYM6Gf(1t;njppg$5lc<1)0$ zjqv{3rWI_6w;dDrjQ=F)!>&gQJZr2wX2|b|Dit{Uuw7{Vvb}_K<6c+T$8@U^zSa(m z19#=vBvp++|0-zUmY<~XTg^9GIL?4E4#&Jc+xD$Oqz_~@1#*yp)?u22nmE{XdRTiT zD7-;3y*UU{KpdNxAAkYINd2V$fC?%(ux}15QZr}Fza9-O39lX7HRay@DJDIza?fZX zo<6q>o!&bzhdV?Ijv-X6hE`7c0N+{~&}ck4%=V&hV%7>8~#7ojM=Fd6w-$Z8nt?-UCNoCRnzG$LK;E+6V2^EFOWf z5SppRSLd#JU&4o*>1&jy$sDH`&#&{}i157mt^JRMhb$U)eu>fj*VhYz0%e-t`Zatr zDO#b<^&yf(TTiC4lOIQZ?s9Ct!elV({T^>SCd1cl-9DJ@CXD}#@r;AAUP|6YML%j; zv%$@g=BDm{I#l5|!~6>I;hrvje+Se=wtEB>437diLA!uN>cE zm!|stJ1-Nyxs~;dg-UG|Q%~oohBll3_q~myBS6Lj&Ve3hSDc_fe^z1_SAX@wMSdar zp`S`FV!YaI`Ia1zj!i7+gyHu;>CN~T^L`m;hXlPkk2(%){BkOOzySu7AmaYJa&wL6gA?nX3K0%XsNN5d_Z#{#XyNQmQNjcd=oHykBBK+8&ReHmw6 ze4Z*<{&5+nkCv!!H8<5y&Nv}9-u4H`>{q*%w$Fd&zW*HtKar?tINB6?QM_tok-y`m zAN@hvi&S@!@Dos5oKf4BT7dEbyNFdd&$rI!0d;*`)1CaVn()2Gl0NKWTYTWIfrh$v zFvX4_j=5!Vn2xSI%!~M4WQ>Nb$N@si()S9H9u@H?pv{L&cds2m_m`+KjG;R(vd=Uh zmyt>*Zp;vR-;y1$?a-2YV%T^WAw9Pffzn79#G}70#GOU*X(9wdc5IaR5JwT{43h2} z|6a?nbFGrh0PRBx-Ywiz&}ty@erSP)8~z(Q>Pf`ynZ{BeO_CmMYg*u8GkjAI&6nGX z%yfD9etJ8=z$XClh}&HCGx;Aaz|RvUvTy+h@%0tnnUefa#{BLyb@|NBYjFg(gxt3H zVp7i<2@MG7vr)0I5u265N1=eCNZ4|inf6C_(Hu8}&dqM^#Du$in2N{;??=VzCQ3*D zWs?5=i8u5ER?w}$4Qm^VMJTcY3*~;aMLX$<7?A(23)r1KN_OFuHr}A;2-H`C_ZX$h zbuj?!eR;~g1-%#g>v<7dx@Xv$c|o$-@5U|z+6aKM5uCiN?{=V<`i?YuQy}xWjjLDfV!|+QQ`))1^mK+~h(wL4~ zTIX?_V`1#y!n^omD$-cDUd8a8lir%^&~CC+%C?;I>FrMW!xqkUm3>rZkR_~?b|JI) z7a#PS7_@v0krURyM3%csmkw!o8Sj?$Jvmh2h0*S!S#~fgCO5tUzjrFExgdPdz{}yFJL}y z(>Db_`u;x~tEkcZle3|9diXP*76g%+&u;jS8;o*(aaI{Jc@YALLmoJ_HDts!IM)AZcN~A zLT}{Bf$P~Ir!c!+fkNPqri)D?om(v5SN`;u{fM2|aKK+8j`@a*LJf|Zl*#uD{I0&q zS68`K*F8tx%28qjSh|Hi$gL0-z=MjEF1pr{f|)?E@?Us6>JcbrmD$bf)DhT=_>y^S ztKwaQnL(AOtWA~Ubg*LAq3zUG?`esNz6f!oYMX@0jgXx@V7!opZik)zX0|w8Z9^z1@w-cr${b4!iaDPI@zTRwK5**daY4kJjOM~dZi@||5JD7uGFuUS8Y ze7mL^4ca%4z7UOY&U$~c$*R8Jy7cTyw7vsM<}GS*`54IYh7~uDZZdE6xenVT{cE9L zyzE$F0E-8)1&=K#E1)?*<^bLQGS9&R1cU=eV)stk7A+cAa`)P%In;dVw!Zx5yhk4o z?~cd68%hZ0;Xda-qoa@iqObosFj52_#B}tYtU3QIL=&{bB@zknl`w(NE3!-=glz_3 zCSz@YKXv!=x)StZtP1o`WOsnTlW%v!HNNg|pZ!|5r9u=X=xzk{WWCJLxe3}=+q_8d zClB0?zl^BR%_EsoobyVa9qDc!yg0JV1h%Lh(G`Fv`uh+bz+KOq0_^C3bU_Y8YJm0` z^=?JrJB?4j_;V6gXhoJYXGgqjGOqS`>1-O!e_99gi`I)FB<-f|%-gG-#k)($OK}gb zonO&>OWuXEzO_!f9dvtwtaGu!6Sz8F0`C1<6W1oM?DtV04SMVoDUsNs8<7o6XjBjq{%OrHta%L36pjDs;q1W!8%@w%s zd2`?_`d#?EB+5R8Vdvd1@b|>8o>23fZBcM+V_;h{h9PD4S>nt1n0gBI&9sL(ldj0- z#rst(76scd@kzg8h(^kb36@Q;bxW)Dw*B2qUp2&#>JV_@_|cG*f{(1AG1V212U0C6 z4qlXU8?^5eOu0~nVBq4XD`aO+0mFvO|H<3}-}>NW^7npVrzBDSNy{r|zxM&Yx&kcT z2}XMd9HEfVY?60DiYxf2BKO<=AZ`S!D{Nmp=ohGK^2Mqu+qNU?MP@?O3XN?)PR|{m zgtPLTSEWh{RjpsJaTMsMfAM!$_BO zcb6bTN~s_)q=3>XFo<+_Nh>+z(CVPlNK1~Oprnj+4j>{*ch7&k-@V^=|FzCyd04p4 zIdAND?`J=IKk?i+aP~F!hRcV9s{)WM$d;Sk#T&*;51xLI)Ktu8vNT^1Yz1tBM{qTF z7p{%PMP3H)TmUN)cB_{gU5C~}_YGYGkkv}Oi+WcZPUn8>Z?ysM<2^x-6H&!@P%5Mw z!iyG`0TjEAB#YpAfZ|QgWWgz5<1Nz5f8OY?SKAT*0t7GSSre0&KSQ1pM~x^5DnM!l zJsEc(Fp(y%5USdnK$mV}p4&kE{Po$M$ec(VctrawoaP;u8h_k3ZMIe56H%$PmkFDP zt}5ekQ|0JyO^brFB6vo}E#6^0P9LG_M!ardRt<;R)4It9Ep-Lg2;*=C%Bk=;&&UG& z+n8W949yl+X8-Tk!gQeiq~b-zLHmC9k9e@K*?7EJ2rf;^o^)CyYE_&0oIEOD@-kwr zwj*nEHPIY%F1y|}b;OLmKpP|A+iq+bof?J_uz1+5(xWpsfj%>B%!O5M1RhKwz`u(k zsjVJGEIgZ`H3NvB&MTQPMF_xX4nI!84DBlQaW-~#*!OU@PbU$Iwb`5J!4E4O8q^JN zPiU}6jIYRU!M>->dglM;6^8It`LmUk1~_daQ67G`{fTzKk(=6)q{IS|yT6_`sc_P} zMX0^TaXe%P$_k}>jv}IDqmUumT(A{@6+0pG9+hnVSsc@AddXMCvwj~IqHW$Xfy+S1 zw7pX*LfK??ebY9t|B|ac(Z}>0ng2FlvE?YZG-JgTrp6PHjf_(9wd*>Pi=-M^Cy(Tb zEIvS6USE~^vGL+vhJhM}0+Av(nJCSdZ1a0tz*!X*&+xub+kAI4IX1G8k33t7kr6b< z&3`3+zppkIZ_0 zWJ25}M1r^$#KY1?XpEPa*`3829^|~vcl%ULJ0(AbMYMhi0t9l^ob8|-< z+umu+yKbcgkIRVKP5Axs4@P}hlW>`LGB3Mj_8USu>7Y(HfuBt{Ay`A1@Ov5(R`!6h z7P?crDO-{3e4%e{aPvx>u=3IQJbS_K`!I&g$!$K}1=KdjYG~CqK#|y&a<U-(s5>zMw;JgIjX$riF%mZ1#^Utdi{isAP`t6CptPR!ZWmj5* zI!(Gr)V(Mc*NCypC$butfPv-7=Z;kMjt8ed^qQDj69GSAc0)(brduL{mQtFj!tSCtT7rH0C?f{!_Ws%2!N;KU zkuAk+uk`*Pxl$Cz3sklTxu=PuHL84CH-x z+fY!Q4!GdInNr@U<73xcUv!X*-qi%47{7jHg~n1q z{7%stiv$FH{mo@RFN^M=st@64W5?<%^lH{SV@Qg-Y6R_S?v+-kItSk5gVul&xo`9o zyhUB{5*I$L($%JKjs#mwH>EX*dg)aWT29<`Rl+`)wUJ>q7ri*PZ`qB|ogM!)IS|D`Q_S}9 z>7Ji766M0m&t&6q4Mmc<4B~&PVHkrRx{s_L&#&t zMINGPbrq~V%wpy$pfp0{(P*d^x68*qM7Y!W7{$*Ko;YH=Lbj zqx+RJAmW;NUZN7eQh;@(0}#LuS2i$5;WVTAQPu-MxO}sF_bo^I49*|c6RGMp34JYf zk|}XL`HLbxtBG|n)#Q1pD`oW;H+98H8&enATA?MW+@yR_^~}1{>w)bj(FGnMlrR?R zIP8}wp#Flu^~rft_A9?6s9OZ*y7F>Bn@dLLdV;7igD{XN1iLPZJ9jQyYWul&rvp@+{LIb_rY+tsaft@6E}@j1{cmT}=Y429 zp!LY?L!R?tbaj)ssQu-O;I2(jAJ}BJ^97_%1&^XG%x_w`bJT!rlN4_Sme=YZ)-`w3 zffy!GMo0zOE5kJK)~3QMJ{MWfjPMnZnX5O=hF=f7kC|9ybQe2!SG63d;a09Na#Q)! z(UJt+i|%e(B+z>(R5KB{kR}z8QPwPm6FKCm`=DribgG4^OkT5xiG$*sFkQ7YJ3h0r zSz#29H9D6D!;I5a;yf>=T08#b#h?`avSIjIVdF|~?`@1bY;nCr{MwYIdj4|gNWQ(z zcZ2g>V(w(I#KxIplMUpmBIZnNdt+Iyv+nXyDNe*z9~ObfFEUg!bJcL%=$7x@DN6QL z-E$40re+#)Q7G{}tU1vRCy9LoYs&#@Z6&QC+ZyU zgu$?qFpmdhlvO9RQyeY*P1?TSnGioJ9k^Sbn>KJfXqqG>DBbPqdtaO&>G6zve_&Z{ z%(ce$Jl$LG2*S@d%n|v)ZA0ekQJ+$kh5nk?}Wf)ZeY;&tJwj3}IaO&8PnY0A!;%A<;aur{$fXvf&n*TvwQ_`^k({D`E z_uo_DmKZO!_vO0-rib$U`~~DkKo~Tk1!Mv|V(S(*E#KdNE6&_Nm7phc?~!__d} zy;6=~eMpbLx79kDkS<#VnSC_Zj|X@QIY9f zXx&7FikGq&*Sa5f-ImRK<=W3AqG)@b)tdFrkhNE6i>5_zny>JV6O1N1^P(p!;a0Z> zsA4+2C1ZbsMAZJAE|NM(K87lyX2>-6Ep%b3#_Zz?A=-tUCvlUIm(BEt>o+hOsLQqH zucpB(;v1eei(+^-r4ktdo0&bD{MdbZy2ba||Pl?M8;md=` z*qD8+b<+s1;bO%4jm!;UK0-YL|JwNls8#eLgVGHG{)~qBO&_hrIJ8ZI(ZO1 zZ@rMqu~Vjy7NAP}Y$h;(zciu%#ePeuql|Dhj!Q@wjF>ojZ^d}7#{HZM{SHmw2Zpgw z6_1;{B|*h@f`^<-`W?_SAEBeNsj`<7X>+*ggDl`mKRLhQZGTe~+sOU=l&nT<_FKEo zm}^))IWjfzR@rk1gQj_1E69SozJ`;2XA$p8x;0Dnr(NeY;{`V%VYr|7?++Ic-7bpK)+vuWq6s`Z2VROPL~t9nd0$-7$lyHL-&ulV8j{JCwb z&KOs2A(Y=7KQUCf7Ru2A%-Klfh-)#YvouzpEcKa-CzB_&-A9Ew0a{&iN#*psQ%$Tb z47X90`Qy`VsEVCuakl1m8!L~7kAD_T;{LCZth0WPo8HK%ePXAV9uQeyZam5LTLV;+ zsUB%kX%bi4Mv1&`l#l?EC+Y$)$vE!6Y6$pDl^f=ZqV~1poai1uXCcz~q@tBa2PAI- z?-{Ca7oJf8L^_wWyxp!~-B$LK4AkQ6RplVpY|TUxuIus0hmzjt82j1pO)A;G3|=Zq zuYcD2J|DdGu+Rj5;zbZa^@!kVIWIYw zJtmmVF`4n;dD#oUR=tU$`11B9?a9>96`~XWB5PO!P01DBT$mywlJ5QntO>AQEHIT# zHZJzfW<)%93xna&+jtc+NjNu8WrJsrz})6i>vx{2o>cUaPgJIv{`P@2`FJ@J(xw zujTL*@pKi^|H_C9#yVr2VU*Vib_)|iM$BS%FY&Q}Ow~1imxotsn8nDT!~`60b{TWe z9P?nhYVJAQ%(cRVmVO_ZM291qgzMI5QV8FG+khGz|L=G&EhpVpecr!)k%NLJlHK?m?i9nb;+M5A``@_*>cjp7@2H;4&$Goa zK%h=qssiZWVOsT$VzyX&h8j@VwtY!|?10WAM^Yz;P}@ByWNy*HFraN*aj%kmQc-MC z1AHBKQ05WDZ<%-EBtu7!m0&868<__+>QzRwssoQgyC_f*94zYs&gJH_41D7r9(77P zX(%?=Voc&C1!P#PF{_x1Ri3}J@biFoN*HBJf}DQ1jvUp4Z}0U92d$pWQh<#`_uULw zw%EDpcGhsi;CbTvf!^AKG$$U84OAi$Beiz|QeI17^P7k>}AnPjGtT zqj;_4t(vGRHBFvY8A30T8wV9tW#QDDR^>E;H>~|~hsi28-W^|8?*L)Gq zvP0A}FwuT(QOyR}LEDr~VWg3$pag23f#$alBcMCxtCuN_SG^}aylzCI+G>e_!qqyr z53Q%JWAR9oBkyH&df|*a59>krH63D0YwOG)cA*rC3K|2f3Ehec+Fh;pHNgm#UNhyi z`xDdVu+W>LvPs(}#;pPP6FmL956&qF%1dL0Ik!eYU5^i@0U==A6N+FJyoDQ=HLx>x zd3vg0^rYqt$B7?}AI|ptargU;cNiJ6sfKh%^wD*g3!Y83H&lUUwana$geO}uq{#EW zd#%x?>9)wes+{k}U;@Q8{mgB@Dt@2Ku_KiM`DSLXk@j)~)pGtwb*(oKMBS^zqWNbq zmFGj2zJH-w^Kmnj?JUP>Qbf7m{O7UXw607aEx~Wj7AAkyMU1BGu}pP5Ji9_HL?mpU zEjvAgliR8QC9??#dqG4tSnr)uEu;<#dQR0lsvu1INi#1^qKPCIxpdgd@$S;!t$;W& zb~V6F#rk(XOJG^+XAx)iS#jT`o!(no=JS0CGkp))n>!o?dgWPL-l#Q7&m7@hIh_yI zDY2*fhb6|{RK<*;rJHiZ07lS?Yt7fh_xHvQ<_k4fRbmpp;;J_TguN*t+7EveYb0=QtXz!1mb~m>Nmr`&Wyh zF(<`7$4B4)gW$AgR4YE$Jc}e^d^`ypu;~EPm=~sQ)c?}sTju#ECTuH3%052T+mF3RoZXy@$oIM^4fpy78uKmI!^zS! zOjkTu@a*qq=+SR9L1U9sf@Z6XkY8jDH}_8jJNn3;EVbWt0;efn{>@PfnepCbs3v7; zJ==*(Qqq#snWUQuO8^s@4ae&|O&&3rhZ(S3a=*NBV$@OTgE$~)JG#SP)Vp1!QJAOI zdL@6he4-w^*FMcwJT!9lv+a_WF=LzIe@1JM{Bq{++jVFY0icU`8(@4K0BVyt2el}8 zihMjxDW7{)yZ^fMYB1w02VLKbp2Qifo0pV?z)r@pWhSpZoqe8HdwtSo-z5FY-a7!= z|0h-m_|K>TIdfs9JZcln9W}8PzhLhohryD}?=3{8F>l>2)pZ@Lu_i#Rw&Qqkeiw)k zmN$PSa;OK`U!a?0%F;9?!u>AB7k#G2wioZVXtQqd>}}%}ou^;Nwf_g4O8)rYvt+;N zIY$|MH?XyvJwCv)eqoG6okrb3v)vYftR5t7&`M0$g$Q~w)Ebhe7vt6A0H>I?7BX zXLjXlUu-tId1yI2oJJjxb4%WHeGe!v@^42bO{s)*&&BQk;R3i5HvN>YLX1)njxP?Yp>s;N z#b(82fB(PH>$U9NcESJqc|dQvlaJ6PiCG)z^=1W1*2PYDZFOf&d>vB$H+oETf2wZ&+<$2qIEmSf5Vn27U4Bvi$f5VB zFDBh-c`uK-g;FlS7kb68Vwg1@nRs%cTSue!p11Yuz5=S4zAlcY`% zL-wvsny;#t=-aK3NEBp-DMAUWACn%gz@4ue{VI~}`COpdX)58f8#UTzc8&$Bd{#C| zSL96s)pX5xl(5#a101Sh-r}H(Zi@9p!Baa(I>oPF#@B{DuyrGXVK+$6su@Ol~Pm$ zSR8LeyR|_M2C^i1Fmn8-o%pmh%T!y{?!S=xwm+!XUyJrTDUhbQVzIk@e(zP!QBISJ zz?0}=aJ$A$sY80i>$HYK6dRF7j4t0Mr}NdbDS1S-;AR^&!N^L8(Fi*lXiS@uN>5;Br44iBS9O3w8h1VPer zrV(VZNr|Tx>iIaM6Z|o#-S6HATO#J#^Ra_s+7^&0d+xjBl?{E%VgO5Zv*lhk2TKTf zR&K8U_F;H+$%Wo4^)Ts<0(IYc(&#M;1^*temiG&{_<>CKEHHmV{YjbJPL2cAuE)5? z(t0dXJU+Y{R=<)@BFA*%$W$L3nz;!ZI6q7vx&+_Li6vGIiY~@ext0xZt;h?EzY|_J zQ=fPj=I*RODEIX!scEFP%4hy(`UM3nX@rq)dw$-JhzHnW%F-WtQLA6+mCyc$m^4Fy3hTdS2KebqYK8|yQ-AKuydhsjsr?jeAy^$-c*(r) z)cj{qw;=CJhY#K8i+l0vV|(W4aP+g7rBLx%hQpUBN*_L;nO83dV!&Ia{N5E178;>J zt`wX`)AnW%UB+kuWx^PaJDlaZ^V~My%LQ>>G9;9GZOAGnLqA}L%&Y2guSU#=2CDa6 zq@L6~IV{t~nrjg@3O<*wlY+cEdX8+dV_M%_$YiN&2rS*s6S+ei9lHiZwt?z4Djw$4 z-#X;&Hs5s}6yN@qRKpZUvGA6C7VFz_Huv~^(QVLXd?i}_S=eli^sQ%H zp=<-YbwR-o{ur(pG$VPN_P> zXNcm$6qA82e=zJZJ1$C6gE=}T^{SeGX=sd1Xo_LU^j2_zM5Hy`sx@^35?cR^>$>rO z&ziD5sUGq#539L%JY&Q`xa_*0|2No6cHijP{tC0jw-~|boi2CQ zdLFX!_F{cZsMz-f@frdnzx`c-SK{^5>YK(%2eU$Jy%N~UGt`cHf!d(kEi0(xO4lS72;0#^l9BT@F4WKOsq_YW(fQqebAViAsIb&hY_Ul4)Q{WBOJ} ziF6Gdq8)sIn^xHN6e+Ku>{7X-_JB5o!9oak7crl&P)~irHoz+jEPizoNEzP9Lc~Z<^;Eyc-!_CC1Qj-Uy38bkLa!0 z{Pvzo{Z8Jo-n9wI`rYI-k+sE^UG#5s^of#q^CG((vcH$%Ug3LB`=>eO57tR8R1K-_ z*@pijBWVTO)~(6L%<4KjP`Qboj+Sz#hB6yxGvx z5iIb;MYt5Y_3q-H3n}$AzHB@KSyPw(pJ`YAPt@k`?XF$1V-bea#4X(?BQ4Y?i9%Gu zq@)qXufJCtH;WWeyvRXbDr^FjulElXwo-44+d`q|@6DBn&9^5Z={0o^;xh_wV{wn zP&}9rdwejr(W2_rld;cl@cQYyz=Oz7LihSL`*9IV&hRE@G}^ue6|gHvr*HCBk~y$v zut>{ot=EHcg@E1#tc|+*LD&uY@0#L#Ob>tT2L5|lHQh0c+lUu=`YbGq_Kpum?w&0$ zR>Lo0OkIT4LZOnb2|Z&l&hEZ#Bg$T#mnfijk&o=(l=S~kyj z$S;G}E@(^@8k?2bVI_uwSNf5Dyj7fl0Hh0c)prhH%xbNjve-J#1p*zqo>$h83zdez z2rT09CSkuUS1fCC8iIb=``O|%zZjIMH#q4~QMgAAI$_y~LRt}SkQSJtZlyQK6;<07 zD+;4gkKj1T`mU_u7i^w9MdnL@MlwLN_&O$r#z)AcHN>IL`G#f^t~g}sf!u(&B3~aV ze4-|*=YLz#wl0wf^!Ji#M*UP_J?8D8ajXm)G2`<6&frai@R#k@eMi|iMds-F}&I3zAI zVz&e@P!+cYqrwF6I)*lQV6%7;_p<63rK=iR#Su#qL|@EDf;D- zeCN?w1bj~LC6AxFhqz`d$h7pXP3ltFHFV#{B=keL4EJUT+lf>KPV$iawl{LI-22}< zmshZqflQLOgTPn1UY^+ucNYjyR+*pE+>sbhD~c+*M>IgP$`+OWCFHF+OFpD8f0|&3 z`}>1uDCsDX!Ae8DDPYah^Q{_pGW~oeqPK;AW2A>uK!4D>CE!L&j*~w0yfvyxV`myQ7!&&8Ks6f=D+B#KdjFC>ZS6jm^Wu0?oP6A) zJ3K<$>g1we5@@4EbL693TZwd=f8Zt~i=fBTb6OURF3y|&k}T)Vs3r8*ugy9-YM}od1G#!P z>vzY3J{ni-->7{!ph=r4M>1k_N$?fFMIR8wzGFQ7EI@WHTAt{&pE{QPNbL0mp+tQY zug4)A&bakZW!x5Cyv%ix|12F{Y;Jf;X$ueAk+}SyeUuodCIA+;j;!VkvR|u`Ww6qt zyq=dGPbSsNxq=(&c=z}K1FY27L@)&E-L>pE32;M>=)eWOt=+h%$% zQN0l%GuzBlE0rdGi^ARi%b!ix>q+Lx4k*XIy?bgEC>%|=lXgnOM65HEI~{=VC$!E! zNS%Yq#KQ6k0~OsWv@#=s|MIWvwcTF^Z=C=dLL5kZ+tA5!H=+n>mH#lG;inVaq~U48 zpYO-#ZG=z|ru5LAXZ_ls0J=sw!0pZNx6^+bTu48-S<9cc_G*Eyh39$Fjy?=0U2kD- z`ME@wYn>6xS;DqM;`tUZ_GP4B8T7@$5)?nP@4hGe-=JQI?#B>dL=aa=_ zip_+J2y^cl9v_%hf5ImNUbp{(ehP1j=;WPNq0&zKkcAeIG%PQiFtc?&61Xm<)l?QU6gwuiUDGb82dID z+?P2TD&QNA6i)=ahIn~T)4V2-kmUc(v)+FmS!fca z^qd^Z5*1=hKWhVHj$6xer-DRgzAR}&&S!1r_d7 zX(-{vw?XB%UMXx*JdvwA4OGBfE0t~7Vvj_hO)R5>;r^;KTT!WZB26MiFpQ!z))b5` z@MxC<6@5g6^u>HjJyNNtACL#v6|zrjApQz@Oh`s>L%M#c%vH};9vX7PPKe8(l4fMG?*5@U++VxASx91d zu;?vjIPtau^xR^`8p4>zg6A|ctFdkw=irFv-<=%Og?FRI5i8;xfMtT7YhpHTPh#Y7 zql4C;f7OtMrbp;!^#%>S%TD!yp5MiUuD6Qi9~}#k(eYK0ZzM0SwGD23*kA?JXoVJ> zc&kW#1<9EBF7Z>}Laua5w~i9koDb3BU?UO8}ZHqWx{`Uz}E(y3es11 zt~XG7%Mj|}hYPHKY%rbtr3sLZqo(}@u(w0O)l&gUsLi@fH!n(ztcBr&Un1}JF7Y8d zu>-1u8-dVSwic=>fr@%U36)v|lFbg@w)ET*qUCl4ZS-nK7TUs9jiwdQduALVc({)Y zccM9SWdwg@;h^C zbGFi(aG7z(kWa6h$EH0abLb8B*$r{ zBrLj%Ly4#Cr<0522Q9-hC8GA?Gb@lO-?+kcIU-rZK=LX6j#tLZqSzHFh8m5$if?Vl zHjxawnu3$C8Huc+{26OvS=w7Ew;&0mo{;#flNodb-?%rm9C(VW5D+iYbMC~KWBrL7 zzf}3vm2-5hQ@3s-#b&YKcjR-I16|>W;X(D~6_+=au1>ZP5KMbXz1Bm(jG-@U3qOM3 zjNj4!gWgGFAUh+TqM$Q)PU5wSJ1g|oCGKXp*!i0g1iA@bIesliiUnw}LUl#9LCTu_ z%!K=%AMDwv#TRZw*37Axd#<YZ-Jv% z?(JL8QumjS=O&s-X*-B~Y{ zC9VUgL3UX(5+gmO>~hR~p-fkxHy_$a;qGcx(6@oUL{C3-7(|lmml^`>2fwB;+ADYb zT4HzfUMS+U)j{GW6~efu@3YmI((C}%e(Tc%HxAp_0~`UG?o()X3NB0iQ&bumyUC_yh8@(M&aJ;Lu5Zwm+!3~Cz%7k`N}A$lfd6ah$%l2(CJ!-Qn#>})@R4N_Bx?uhXgGo z=s2C}EbWfScS14a3-0h(@2y*~SDvds&e2`@C9}T=U0YB9So_K;w(fmYW28bx_s&gW zmNy)!A+Z*>iVHor_ZjxI5XNYwZzfQv_TdeQdTqlj?YAQtaR0Dd{uY++r)r`)1FFXY z5{FyThnGq(Ex`J@W_*szDd=^$v7jB!tZeD~db`3Q-86nGUe^sp*VTpN3W)wP$=4{j zF(c{s$z?Qx;cBa;u6+i8r95+yN@k@Ow_#3rKA?z?bXoGp`O|>*fl5m27Q79-{i#817HLQ;lkjoUGd}pfv2L zLg>s7ZuBury2WV3OxM-VL7J_2V)ay+u?wS_{Pnzw?-;0bg$sQ@Acoz|99`p!Z$~1ioX7EOi6r{SvI>wi+ zUZ#H~lm%-AofXQmxjS$9F5t=j#)Bh>yTi`?iSGs{iu)mR2}{!m%TEOdWIJTaace!r zWk}{u+K1DY7=HLsF^QvUy;qZ5`1UU*(bwl=EOIyJ-{gN!=cX9xwdMQKS7YOGF}E)h z@FAH-_>zB-K$alvJ|^IVvFtF+Q=-;}s^d0>Y5mw)*U&ezzU&c}`k%%6jp|PfAjR~h ze)T#(MUSHF)~dIj%jbu-@EUD%I!X>9+azR%S^0k89kXXRp@)LdN(W7S z43|!&?n{AB5&eS;I$G$}9r>%xUQzXC$H5I#?9>;8k;+EhI7?beagfU&17%V(+ZBhxIIl=Dvm+{{4-9ZL_jfreBsh%N3hl+)=QcF_{jQcB6(a5UUhl{ zh4NZEDcO+71E#grT?Gn#AMn;`(ZG%h_Pb%1ww5`KTwEe~zR%ui|BfJW;oIj#l4W!F z1vW!%9Q=b;A|P24L1p5IIDYBmku~%vg1xV}bjfV`xP?orLxyh%@OXsCLKb?-%geva z^L@Dtd{-kCcMI>g1C`94U!S;_YLNzWgw{VHiVnqJSe#KE-?*wxQKe|Z6>shJtxxj7 zb*1HZti~`x6;R^AXW~+_OwL}b26H~&qblD*i=cJ%o1PvsyC>4sxy<}RI1Y4&uY2*` zbil!#4b`|*#Qp{?W|6;U270x3WvtoN8@QynFQ10Ugc_Xxe(fqnlowf@+5VX26umX|Ef>>-<2<>R1`-AM)Wlt?XwGBh)_PjVUW;U`m+Zca7 zjh6uo3oUejE;a|&di{8(qxNoo@@CuMTFc!%QAJ@?E>Vz29*@Y-ML?|RO1zqUA%C0YqdCQos* z{$hUL8~gZTelOH=z0l};p^b6|WoUtA3JYjM?F)#r@eqZS7QP#cJj_{BR-rM~!$_mk zzhLb`EKdVzJfES=B%_m}dD)((4xPIQF8eg~WgY8lw|*P6t~B%j|LShaK{Ci%pW~-4 zNKzrPd$VSLJEpVGtn^C#=4bNnHloQql{=(#|GZ}%dn==REl}=q|MQQcgV0dUGS)=U zh3vcl+NdQ8ZGEzx_Rg$OYb7+w*OD(r{ zL7B9G^wa#EwXhKqM++Ep%1A{GUfABv1dBT_|NLJBfrjQUbH%6nB(p>7Qn5DK(OS{f z?cPXLS(@YS*G%2JO@f!~wN77LHdI5Ss~o+>4N7NBFunwgLw!Ai#JT zWUpjv42x}^*aMoCgiF>}2;6E-dDmj{NHtE=h?LEfZ+<6EnBWd6RHd=&cm7iVIC>%- zt3SNG)Bbgl4?kddLTK(N`{csYO*J`d!S6^oODtML#a!TcPajwOR3y*@T!io~Muz2< z7evOJbC`)>jH)_aJeAoC9RxjX_`ivv#r84@k5~G8mA@!lKAv+42*alH{!WF(J=_iG z%X;FMCxn~Cm+9~RsbP38?jJ4yW^<}zM^b-*?5wSA?&g~2Sq$_PXACV9r67@4CVy{e?u5BXsAt8&b;()E^lN^`3T*$=tv zA?c<0Z*LCAWBbpwl3onU5rDY-hZ8^lR4`Um>%` zE80+(&-Z@_FsIwJO|+#brk*sS@!?16jWUMJG2%O!4`RXSWAY*0Z`H}@~?Y;1k3b(qE_q4hOQY2k} zCwaF)w%&&Ku;-P}+*6kC50cLu;3`_d#K(JGK*~ZGe$*wDCjSpK#s8mqe{z*1evMAv zG6LQ4@O8*4j&}#YrO(KJUgi^n5X>>zEVC1@#Rvn1AKfLP3BJBlg6vpKyN=w$X<#XX ziU1_}wJzd#eH8uUQ|I^HAP-|FAKR}E!LRY}NNgGnX`*+&o_ArN{SpE3`h8M$6ek=M zSr5kc9#D)Cn($H*RO<@eOVK51Q{5e7b;?md_>xqsg;P>;-T1Ze>Iu_LQ)BCj?YQA{ zX2p2_7uXA>BK@m-bC4h-#a5C%#a{y}cEdTK1)+PwCn^0wXdkmw^x`f%-c?a%cuwy0 zK+EKLC%OW$@Nw;UemC^sc$t093ggFt&uYNs4S`Kqc$MOEU_UhKB(Maz$gsR$*){ut z*pu(49imstXR#=^NT0!tIN!NuSnqGo*kcg1A~XD#0nj?4c}b|!m@n2dr$Nkt03L|EwiEC#y+zNtmEcc(rB27;V_8F@q*#*~Q zeN!~>WV2_KuAda6RPv^E5%jQ0J0QbYI`#wZjQb7Cj`h+%uQ$p!(KaVBX+Mr3?q9Hv z>O@>cv#612Prhb8eLu;(Hn3#9-GzUv^rl}a^02ROM;bBlNeLH!-zm+=rC>1`*U8H1 z465E)q)C10#iU%l-Ahi^geJe`Ek6W!e|uSd4xiq0TJ;(2-t4@6E7jup^)tG+<6AbK zpU$Q#E6uyQx@$hol)iOu{4Vz9cCD1&g7C3`vux;=8D0c^03=1So+_~asWqahZ*4eP z_)D&r;!cU;CmR7k( zL~2^$6eJz3ZVTt(+a#RJR?LQfV1Vt#zW0e5-^FhhklaoY8Qho{8?HwLFTZeD>|;Qy z^z1LuC-pL{s5_jez({)|@WUw&2(K~@N83zMGJ4~f<(JSqK1*5b7s z2|}|RPUV?6U9X8IYpezfj4MQ+*{w(5HD&lZ#`?6gnAisNC4<=Uw+8zuKNyA6UC0(% zd{}B(B1F@S1-TVRhm|g4`eSW=Uu>@PX!NqUhJkK=5D|m);k8EArWXCRDoc9b?XCCk> z^SgrpcY-VHRVLeWky6swy)cxEsa-+D^EZ+w*SoT9uw62`o<(iRbL#6JO=@ zN2z6cBQiuG1$JNi;*Q4Ja|~UeRVyJ$!b4_w>zR>Pf)?*j;g# zc;_9E;63n_x5vo4AvYE10%gDKwkqoOQkHFSDLzqEGJFu@616|Lu}LBc4vk?^`CgFO z7@$C-;WSg+8X`*@q28sxb^y7uxDNfzv(Bc-*X;#AibDPNj7G3RC?x7 z#86JQcNaQ=oZN0f*+YAh*Rd5VL$1+qDsN#vF}SrITzbFdbt~!0I&Cjr7?e_kR}8j_ zKguvvx$x3|@B1R?q`W;)(Aim0{PBmAu}LD>bG(WNKUe6W=Pg{P0CIOLt$}&#y&Q93 zc{W0R+~zut;-oq%_|?vFnI>2QsoBbS>`h=IsYq7v819k%ODr)&Hphph%NFh;(^m39 zDpm2pg%jEhKJkkDvyU{p<$PhEnkxw0DPkAkqB^{dGXTib;!!X)}^eVlG)KH~MM}Z(6r1v0KL8XQos!H!j?}RH-11P-{DIzuW zPI&R&?|$!lW4tpMjKPm^&d%Ov@442RbIt82-cL70WQA&L;f8jw6${bLCoZ-yMct8= zHWa!?b++x_9T}gCLkI(Iy|!)XLgPlzE%#aH*)aDo1E1saDN&v95Ab1_L>iL9mHAyH z{sRP1@8$EtslUAsbW!Ntk@ZvYUXPe{R9Mwoft$%NiHU~Oi`%pWZ=o6b2I^3;dW5SI zqly6?G#pW9I*?{1Xah-6C4BeajsMKA6a3$stBm52FkC=0kkOw+L9$lsZ$=1y;BIUi zrYOFRLkA8jS;D4SbeNMwmwCi}ma|UO+nL=raAtVohM4AP(wOE^r0oH8Bc2%ZbF~$u zr!gzbr$`VWp5pebB=-N_&UW*2s0$fBV){O+;Y?!rfe$K?DE@HGhsfqC2QS15iDM$a z%0*JR(LBeGmH;jUmq%}#L31UIq*ckL>C;VUFj#<={ahsQCy(1(5VI#Jx&skr2eWBx zi&kQMet(Z!ESTZ30hO%>Mh037Dk4|_&+7kge1V5l=-|0x82$~}p(J+@2yZdKXF~1{r$r9jqmvV*?Us_Ob=Snos97g^1`w`4fw;p$Kd@f74&9dv-Uy z1nEFpc$ZUvEDL{1`&~1f5j8RV24!(OwVT}iZx{UMeSHc3pW>r_lcc4tw2e=J%+TBX zX3ln_*~XZB_1c|bgnOE}8Uo6|zJX3&WK(nxg&^#J1=8`y>-@(bW^;B*!i zskWQ!JU6+7!;fki-!Gt;VSX+LSK+UDv@_XDKIB(!h-szNs3v{VwVTc4bEzuJ4`eLv zMCMD6-t0gGQWbV;WSC3q(*}~={N1%X&90Ho*>)|&-f1Vk{Da>gvs!53U0~j}Rp!(4 zwUG!KZCH=L4E|vho`}~dJ+jmsMU=ED`?xOupca0BK-$3u zI*}fdwd-hK5ssYW_{|i9mF4Oc;niqrO)ByFmR9qI5iy3O$=neR_MI=9%sL z5&m1R8+u~SLPQl6^ybOs9`fWyhLOoBFUb8MdRF^pE$codP*CgBND&X>bum>~m|e{^ z-UQ;=r(F{iJT*o1rAu+g!Oh?0FXfKIsU$RcmH=3M!Qm0+9<;OS=?Rzc5&AV zfRgs22-C53H_VXpdt)dcppig~+u=wS^%z588=W6$FcA*$fY2)@`-DxRX;AJZ?E(?; zH9@B1GW$o1$InY|Oc1_>MiNo^Q4!BKTIQ3pd*w9~=|-2HPuwqh1*+KE>tksJra6A& zCQvU3Lih*?OZ6X`$>e^{rh&+t8~lwWZcE#wLL6xuz}&M>D714;Bd#O1N?Ij70IVrk zC!%wIB89KLs3=63kdt(X<^9u5W6YJ&4a`=Ee4f$$tK&wZg;o|ZfursyJ9eim^7^mJ0}|jm_nkDdHwJzaf>N%XY^!0 zAUUlO-ZM6#pUABRy1bsOGY>$Ns@WBOlChdAWlN_}_4*^99-#0kQOoCSO_ zT0Z;;WrheUR4pxnrwwgq)21~L!z8|=;~v%OpgyQXXk0Jbe3nw9ODV%{5didB~(V|5)IflEa$!ivJT9?HFOB!(r{$y83u zeMhUANcF~TFvaU)U1|xMqfXE>Cot5j$7!4+?;qck?^d2&FFu@;6!P>gRSa&Sl|{~g zHdri4vm9Yo=xqbBIrg1gssPfaN%ULeRw?L42u-zj3wJO7$Zfg2dkjO(fb%k{BVw?~Bhc=9ctlyZ7tv5q6D#%R3_o?`lK6N4P`hashPd zW?BryLsZ-Fk%g~t-#uw(smf{o-+-%c=(mj@U5EP3nh>`w&pQi|6oRIrwV9B1g6){j zrTFfYc)dovAAp4e;hr3B+ehzG28ge^PyJ~R4~)l)uaWXge}z&J(h6e5#gdMgD>+q1 zOHum)-Jg-Ab-uweQH*8DtdT{YEmCeH6y!q}$GB0oIX+$yr2l&+R$f7RH)9;NLx# zzkN&2Kw%o)qZyQW`?QLn-Sf>}1jYCqdB7w(2O4@+6mg+SSea{h9gpu4phn;O^Kj*? zE?8Zz;9Dv}CN*{vy=@0Ig&^Hi>jE~hi1D6}N67mfK%8KS^#$^N;3pDK!#8#<%Zc}e zYxN+p-6{QReRhrnprP%Cx^@~*3)sgHZxcLwJ4oyja=gT7nz3$;3s3bS4jUUD%0ttRG>yz{VUGV(YV}EFb!3WCo_S=&sn$ z#ZUn^%RQr$nad|VHF^Q70%&Q@hn3Zr z>@FULP*p-WeFU9z_S4%73M4EMc??A$Do&w2^#}!+1h0IpH*)5tlxd2TDlpvT(OO6T z#9p5+p9yajY6qo{um-UZSBliKmsHSrRjua1I}nuU&%FFX8+YZ}&i$HxC@IUm9*G@+ znhO}lq?$3ttNnP!(i8i`I_>Bd%kz&p2G%(??UJ6lJmyoB0S`|)mo;&hymdGHo=>?f zZd|XlDX9oL*|mC!Y++PC**ElvWK!eKGDcNs3$C&?$S`PaxlASqYj50Ee&n&l;bRTR!F`k4}8 zhL<0!NIbtrU3!7Od@?SL>stS=mMGWN3JH|xI{e$i1vUbkpzQ6e9TxKI^KKQ28N{Md1He8OStI*Zen`sZ^d2W9sdtY*~m2eu=m$FBP zA!eBSd1@=++}RlO>EhY>g8;!}!@jEx`#wCM^WWf0_}jm4{A;BA8=*>KdY)V-NL5BT`Lj3~^yRSvbc4qeSQ$-R8|(c_v9ssYXjYud|0{y&Xc)laf)DzwCnEzIZD$ zn0#ZAVK(#-STdpq=Q9X6$3g^>pR`haJsdc#@|?EC@XEdJbwij4y(w2DH66E^NoazY z^jzz}GZ#>LGNtH%7VvO7c0ZjoJkt-0ih)P6yAMuclI zykQiVBV%)d$~{qPL_GiYv*~W*gUA)gj^U^Cxe;@2TtN9iya7Jj2cPNqtCc| z2$P<}{t@z{PaUVY5)?Pg&u!y74i%)$^c)mYe)Ya(obm%kKja`R7vaO~$rr{vFdp=_ zD0ysO#72TEs0)2k>I2VT+xI$`70Vp=GV>I~wXW-mf&gM$+)hOEXCLLmbQDT{=!Rcq z99KM*VCb~bgEXK1yk9+`f~M$mR~a1Qa7xa@a; zHw2+&TISlLvjNt7&r4jPmi;Yy2KSTd8{g(rjCr~Ibh_J-b6*Kxe|DDBzMw76v?f3mTs4$xQxvao4jSC&k$nVT&HZtx& zsBDo-GkNvxy_Ebljm2FU*ZfnTFXE@5d*s}de^YS7s=PYdIo%R3o&n?igv-rC51Jf8)S=&y&J45!r4n|_R&)o4lYUy-W0W%-Ks>(ZK|o}H*o6#bjv9@g8I1`pWs>!?Wd9g7pa z>Gss2cm-TtzBj}zabTC|B<*O+2TP@Ox%nJMl0K84Z(n?orF+{c8#2#V8Fs^e zw_o^o%im`8@Z!N28@JlveByljqI=pG;kS59gAU-kANbI7E9_hGT{LZa%Pbh?J;ILqs-a#>;8~+HQAvB_QuM;x#nhz2TDl#Vhc5{nm76<*v zT!{{2OYtR+Be?zMM*b{#wI|>x@(TcVl93x8O;^QW&ntW$k!2jCN0|qsLjjlG$TmiT#K%+$^d|Co;9RiRjE#h*sAG;HiI& zjwVfl%mxdu%i!M-F`zw>3!o={d&`=bqYU>CBW7jghMJSaGwJ_QL|LHdoMb!wKoDl+ z1#tR)Q>@Gze=1u&3@-nv5czX=l;N#}j`(0u_@ml)qrvGjH>1y_sZUSB?@~F$BNrZS zG~y`^UwgAr1smTJwVB>5D~Ghv8il+qlP^N3(XQu+5VJ}OIbJS8=sht#f>y#IKg5AoIse3H?jU{3{{0Ex-8#2Rb4WWxzj`vq~1TK;o8+ba{lrD+D{G4{f~S& zrjEpHb$2;o&K;1R`e;;(S2cGvSRUCwr%j;A13IqT-5+D$bu!w``W;XnEZ5&g*HIhHq_daAeK{hWb< z9%&Nc#Jdu;lFs8EQGEAJG+Ham^W|>8hN}AV0NllDS==7yfINv#-xqkE4=rFd&#)b$ z9_eO}h}Kq5e3^D9I^&SB9s>=TWO%d4b>T0|M~q^!h3_t&5t>fBn~T15do?O$QTyaa zJzkqde<@Fd_i1btSh_sQKGfr)T)!c6FBemFBIFc^P_O@O!ak~8n<#g|r)nMW11;#m zBmMg0BaJ2Rs%2`E{~y84+arN7j(@ZhA1Ux%KjX{w!`RKDrx}jJx@r82OnDR=dcI&W z?0CqOt_FSoW|v}|J~m2Rp;Gm)+pq8n5+@JPAwC(~QZO3N2F>==>mJ^y`kB+IBrG6G zd1j}@d($QVYhRp4pi2m4?PdnF>_K-Bo;dw-hxN9fW*VPUC6HTNeEof_UidmVca(-{ z)b?AyqdTTA)d&a5A9qd}EyEK(|2^WhAN{MHp+K~NGEE=0%-~}dYpw8tgZY3Qe9gL? z;7?xj5%hVdBp|0E;jmS{TDDqkc7nC(%ag_Jl2{A$wh7+wa77IeE>e4_c`W!%ncd^r zY69hJCmONV!g`07?&xw;yl96Os{gc9?Fo`rxHi15f!qx!7EB%RrGD+dHOiLGfc!6` zuh8rLgfM{WmJBzod zF7X-Awf()D_{cFnf}Gr#9u9SjJ-+F~+g&*MDYa;u&>(PYq8FWAoie_)yIbK3xuXO1vR(ahP)f zwgSVuI_G`?b`yM_^YzizvEzk2euR_+L4Xywx8c5%lg&OoC3^byi$62>zdt$}e~ua3 zmaq6AkbxqGgjj3S9VV2r1BhyaP}yQnSZcYNU;g7x*()eLNyV9awd#*AZc zw(ru$tREQV+7bt*2o%I?pBG3pf>_?y-BJ>EV=E!~PD4ep$Qm$=E`QR#1jt;$#y4ip zTng|wa!eCEn?t_^Xvk2X)%dD92XWT-D&w$ovo(Z>x}hl_LDj?G!(sDMybxBHkqo>p4U>KAHt~+Rt%}bvVUd!yAXTlU$cHLaYVF zg!XhlXwcL-Ar8VxY$I!)v%23pe~WBiB)n##;LnzbBA`Rg^cf(35=Wh;#9h+}e}4V* zCm8hz)?fw-Z6sje#EbW)<%?&7&7}+*~QzTwqwu&09=F z{27~8&ajlv-1o0;IZ22KIet3oLcXc;IN)7h^`SgD;Tdr;$t0&TS8 zxfXmN$Bda&L_^nl)TzOYHA)_K5;`krlf+n4$4&;S&6xREzN5461=_oZ7Y9?M)bUj- zu*9y0+KTV_V}v)0xC6(~g6^0M<_w8mf~m}zL4*V#2s4GdJlen)={0AGrrDSeMZ;`* zOYK0h9Wot?*!GZ`}@pNpTK!xW+3+=n8jK@e4Mu zu07m2Tt&1+n)um6t0^tAyq59d#U>y&6n645b_?G|s0Qhl)R3lkFibG-3KMd4+a)ar z#()_Ip~JrD?bPxGdARz}HW@TKVr(B9sx{^DWWgxh_saUlNN3W>gA~&^BZlvi{YZ?F z!^y-}QmmCXB_(&Pbi^j;gq3KRs0HM`QsSim%pq_mp&Z#A8pao7Pn2eJn14TqnHKIy z@7;QG_;ckFk*r%V*W7)`{(3&Gzu?sYkSKx5)2{btVO~WH(TpT9sX-4+WL~X;+DZDH541CZ5n;b*?5x9RHDZ<>b zB@vV5pP2c9o)oA*b>Q7{f{|c8B$5;!1V`*>iEb0h!C)L*H%ItduJZlEfiJKVM_bi- zOmXjDw>!?l>8n2=nQdX}88a3FLe7zGag5S5Oo$Vm9rVMJy!pAr&v!mkDcx=DH69re|QiZV~9PMAGN& z=`0F#Cp@Rm$ce)aRoXAB4_Tv>Qr5itrV9L6a(_%DA?kR}11l-2n~g{7)=sgh>sE)} zHJf)=o7SW1&a#%=$p0k z>w*)&Ur=_s-vR?iiSWjkg3+i11S;kFn{X~$kJNPj941%+s0$fCC1UuE3lq) z<6)&5H@=+!r>1U%&Jsx_dI1Y9;PsnDZ@+XD#84_GkaI0&fg+maz?8gmbQ~auG|4YB zOX}U32zQdo{1smlx4Ao_cY@#K&-4LK;JR^*^z^rw$ zk1)E<(KNAvDFt>qG>NGhV+j@EOiGJMgmD!SN#Nz~nvf@M%24w&2H}+aZ{X!G11puW z(TXYht0O?I!*z|Ot$ z=}e?yu7TU{VksXwSz|P87Y34zEfT9HQc-Rx3pUZw_c*gvxM<1&X(dO2YCVl^(B$CkkR1j7OI;lIN}X0tCqCOS%sUpjN%WtqT&og*7ul<+%xk6Y&A)DAZx*ap zYBn=kz&@(^YfH8QyVlJkIokMfg<|M1f{b(L8G@ljwx@1Yr$-hrpws`w7?2DJNP`TP zWXvRQQHlZ#YDJ}A9V>|zUzO)`n9mnQ!95VbYu|p%SHIOGB0#cA!MA?fpTAazZZ6H| zM_`vg`gD3i^0?>7`z4<(=H>s{T(2{L2z2fD+HI9)}6A1yXwY6og!R+Hym+(rj&& zA?LOxqDr45qaRq2ey3y~eBU{_QLB>&XVti1I+s5-;l5lTDF-{{4fJ6%R5u>1wq=$N z8!VlgkAAJxN7fXOeT`t23DlY7Q17}aIBHD{>`NTCA`XTeb0o3C*p}8=^i#jtB0W#rcqk(1-;vcwm1DSXolHA2#C;2-G#cXNm)c ze5sMUJ#8Tk`J2W5g_2|H^Z9jE`-yk5Ez_N{rwFKKHg9gxzCzJjU@j38D>ap#ZEIE1 zgkFbnV;Jv2-~^&r@zaM(*qXdWikGoeF&U1EFg2x42`Z6MShGZug1JGju9vl9AN;#R zv3L;y#9ZtpFe=dOg}SWUk4J|Deh;>-79ag+pLpze`lhwX=E_W4ulH41u30lrsDRnQ zLFqtYZo*;c?yW4Yji3WAuj8K4Cx}J<&MD1olR>PtTIyf&OlQQ>x6x}iLxrwYNd+%m z-X?J9b?X1x$fm;+n;}1rvwmLV{a`}JKZNcaw6^pwt&Amk-|ie=h--IvlA|Yd%?e8@ zB%-I&#wK1I=8>#x3A}vNL=qKlVvvv`wHet@LSWZtpM44hF9%|@p-T=Sc+YE4jz#c!dF>gcmjhszR&?o&VwZo zwAqU=IqLoD{Pw>5s5cO+TiaFyXmDhloqv%az>FZ*5!4wI-P^ihIJ998y()_UA}Hgd z&5er$BDDHmovSD2t-A~hUSASQ;b&eewK&*4mv=qLCV~kP237GfPIOj;D)RSsa)I49 zUMzX{by5g|h_z%&C6?ROMjHneGEGdXRC4?~If`1%-)VCdpR&G^A%>3t8~uKyEtL9KT3Cw9PJD5zqv2itVPITwR{U6kF^VCSYFuGn-|Q6XAaB2M z#cq$lhT0#fP266?zL`Cux+E~-y}iBg`~3L3USA0rZpPN)*gHrwa%5?-U}*(Hb&TR! z_3!0dJ6!;PmzAOZ1SHUw3~hz&0do6CQNxuKFphgwlYE0?qx%eHv{#+fQdPV7Qt3Y@ z+`C_df7XxWftr?2O{g=5Z*^#5QGz7U?$;P?-NbD&(31OP7q4W2I&jWdeJ^Ecgv(=I zS3MQl4rd~ICU*B(>lF^FG9KU3LW-9I(DfbM^gf3fwlvc#_Jz7s#Jp0GgILi*<~qWRDugBAOWIs|BGcMz(qHI_h{pbnCyQls4eoe9br;l+ zRbQxSDq(7pID$NbBDK!Dfd7mRt{hP{ZUqX}P9;+On4E%lxSoK_0A8`|YQaxAme+aqocYgv ziL2^AK|V8Cfs~HCuhCO$6c$9uM#P8aX52fyf+mR}~6qpJy}9rPxO zRs+r2PsNIlDmDp4zr0Y!RJY(wBWSu_XNi77hNsEvhEa)^@{ez<8;ypniMSXS2BzPk z0-XZL68mLZjT=HUuUeh%iRv%!2*w@C2-oK~Gh8tfNxStxsl8M;P9MJFeLs6xOmu_g zF1ir@XGOT&<_4tC1TdftXOt?8oOaaS9%tpJY|K!s<}j6wVZz&^1JtEGoI{^tSE3)x zd|Ocv%(Dq23EX5dR^WFm{RR7=3*K|&uSP{1nKK(4k^-6FF@k{UtL za{exE#*sI&6N|mkXBwkBt6SkfX=YS7Z@fixNQFt6?&Z@$U=y-@b1+VZK4{A(>ru4adpXiOc zf%@o(CZit0Sm#2--QLIa`oqA~9E z;a-Foc=>zHQg%#cQu|5PVrre3rx(4~jh}CD;Jhsci*V-vHGcq|`Xv#X$l@MAWeHA` zc|a`Adl&3ZiZyjN_v{@akP)o|4Q>$yC7EOGMz`-&+c`P%V!qWV^zl3xepoeBLG9%q z_*(~c3xm6hSx8{=3JWqFDR6IY*zL6+RT4nqt@_BNYjDX2NU35Y-6nvP(rC--%{Ruh zb^TzhUNOXMTso#ay85nk_%(z5!S3LykF}%LY`V5M@}1Y%+t^U5hwr#jc;p!5tG;Nm zHgejWZa_jwrOH2)GW@`tMn{`+GE;0X_IDibgtf}WSNZxfP#D+f4@zT^pdRH_Tvu}+vGZUYv^`umXc^zM4+V+l+F}U|B$(iYFzWRpW_3w zzc2OfoyMSD?@GMA5^O4s(Xf0lEe6I}&8(lId{JK!IUo~G^#xyJ+)~Cz!Vu!*Z+bF} z5&R{J*)~(*^Q*6hU{*7A9{}f*sMl+!%6){&eKqSNh$)7##4-9dnZ>-r3`b6Qesh0d zr({fYJi~VIUFq3yUD3VHP*Suqo_yds@YiO8*u$>17vj~<^wgGER{Mi-H{Y#Jkeo?a zXR23!*4KWvOVQQSJrU~t2ai?cgq+MUjP}cad!_v74o*(v zt=~F%DX?eL)6ONU)=h#Kh72xDS?UlcuopQ6lrmk?LS=t=socbC%GPg9(M0TMc4FC! zq^48j);3*m+PW!E$$Av53f~sTRab>q>2fDA{Nl11#3rx)WfrlNfIV#W-H9P=D2=TY zgaYOOBMB3LIF2I8R$*{YN4P_0RZ_$e4O~&BTM@FL$Hi(C`oucT!`#eYMOxtxhMD0z zY|Ygi4z>}?C|`W6l4Voa_Kft*c&CkR@aqVGNf|`FU!1Sn|5u{Y>dl%^nj4)~(3hhx ze%9lNAP=D`r-_IdtrzEXD|er4wySl-O(j5CJqSJ|PZf7ueTzh$tU6{#pFJI&+EhsE zEZYtzSmE`HfjH?NU_a{c##i|Bm~};rPFk$Zm!1=?D5NE<2h?BT=2im_+068p1)#l# zX_f|855YLS(YyBGc({kD^^$Ug^BY7q{b}GOg{QK^TyTuyLexL&ZARrs(kxX;pMUWz7;Vstu1yGRrt#4csdJ7G&^w6kTZPFn%*{kNmx5cO~8GvP8$2ND9?E z%3pP-@0Z9e0;C6|xM=rbz8j;usP|PISQEVi!Yh-$&a+V4Y)r(>-mlUI?kUzVJWV^S zYb;iD1mJ@`oPc{HE3*4(IK`E-inylvOV}J3RKFG4Q?o7rabmEIAkI`fwk?g$X~5f% zX{m&?()Vr^R*WRQ<27bg?>3A*@i54|?(dHF`$SNWe!#S=V3-W@r`}XzNi#T5% zJBAaB1{UHCd^o}BI)0i&$V+$<$BRzC(_Va_cai$8nKto=OSp!6KNU}g0HDi99!jz~ zx>s++UNA}`VC5a#SL~s;Wtx0Zn4d{1Wz}=qVYdN9Vsx2y#pycn)5=dz{ zQ^A};L55o6lui4%pN4r|<2{Ou3QP6)-)pcqFdy`&CHi-Hkcvmc`MZ2ouBg)vqpaUU zBYh)q|CWWaeocp@;nK|i*=JrAI{TBL(dNH}ML$|!pR;;;x{*M=)0*{ev{J)DtPS#B z#lv8eFYwLeeUkDo4hHMrbL%Cpy~zc!q#Ui8oPMDTVWQ6CSpF6*^%p;V2+TJs`YeB2 z?4-zbwqV;sLiJs=8dWIQnPz(o4Doxe2)O9*z;>x03bP zbqQ0`#?AU~GCT;Vf->lm#M|>LAZ`}FZdJKwHoMLlj2`W5=KXUk{I5sx_wbXYho}?r zB(Hw1B4;`y&g$vtVBg=_hxmNh&=3WKnQ%BMVFYW+_xQ568yzSM0P zcsLcF^zM$;3|%}9d&o(_d5`fF>R?p{{d(CUzstFGWf>P zuJ5@@SUnZ?fYopF)p-w9a*4Cd)wsANK}Y=+z!`dPn!4%EG-(qDSVCZ~l6aD6*iFxL=uh?mf0ff) z0#WFTEK$epp4H!d3lX^{5{i1Msn*R`{KRten+h4o87b=hAeH&=L+&F4d?u+=JKqHB z@!6(#6=IhJon@SjW~?+$&m2+6aYyZ`T3n8pW4H_N?G{T0aB zPQ?UdGLzV$Vxpl|PuZy@(9@Dp0OO`ohcl37dQ9Y&Mgy7gKnXT=MZI?>pOW-v5ww6w zHg*5ZSmVM`DF&&!@}Rrv4AWUxt)2{`i9P?00*&Uf`zMjIK(ac7&1iDfgQxz7^MvYU}HaN3|HkhG#kapgU@1pHW$6jR`Enl`zU+0T)Qk1xMs*TE} ztU(|Pd?lUvYmn!2a~MJ`8JpfDUe^_yXA5(Y0iTUEIln7+P|1Qn@tOFJCLp{k>& z*}#)P_cbw-;RJD&QKmJ=$J}$UOqAWQf%Gr(h3!@tvWFCE2+e4}Dz4GH8IGI6$T)lI z%~r6qmaWye{~ETAtZ}1+f?79CLm3egzYA>)(^hnszA22ItOlk|)sJ1?qOgvfy_EEI zjNeeo{E*`9Z1&~Oe_VhjT+^8Nw7*8)iA7@;3L0 zQ?FkwQ!tGM5mG-~ARv zv4yi>t^d>dpS#qpk-eV?;w1} zG=1lcFun6tmQb=ChZ7V-T;qDgZBLIG+Voh(*HYtkj%x8QR0{m-3*RluL?5kldM>98 zzhe)uHU+;y7%d5o*s_R8Rad3WuwlsN^zg|!GGC>;mfDL&y7T-5Rp7R3V3=b26^YuQ z-q(-ZQHEQ=ml|3;BsL6sF*iR_bd=$yyo1;TV}Qbk8vw`P$OnXpNA(U7)E}BrTbUcB zabdmCLJ^^#Vz)SE_7y?PeGgukBu;|-er|al*hb4q6vtf@!a&-_zfnB!TsQ4#=vCWs zKel-`taD@Yoz`qcos9(xK+b~9G7Y|*8X9k5Hf_x~!iBH5 zZoMP%MW+UuNkYKn&A-n>VsZ3Mi3t3(T*_SoT05X zSW|c~-(0v>@8R-ZOIW$!hG@_)O=ww4Zw24R(LjR@FgVq1ED1ZP>Uby&#s7w(Lziv?DWF~DRztS63 zgoIYQ&gPbXH$1$Ybu2%au7$YG5A8d$jYJX+EOFJ3{L;YiIMf_H#qb>X2BwC@3JS#M zDv#={`Y-Y!;x>NqWIygb{neytgSW^^lhf1P`6Z=cemkIz3EMMpp@hI`p2zX6+YdP) zCM)^zex8-Pv!efOzhzzoaO5#0I7w2kA+0X<)zKz)P;W>Yr9W`)*$D9%m1Ck#GD69M zS)!vu!OQ*84``^V0O5otmD>#@dr{F+0^pqZ=qT`uk?4S8TmU})@2XFXpx&2|X7C&v z2(uZ`@$wf^kk2I4xX>s4=+n^NnV%;+r$8iox3~(vFM!d+aAJU>P2$agB_VoQG)>XPu2eoVz57p&!|D@2ZIr-r8s$n+d z;Lb*ysw2D8(Ox2WJFn6(yFHi-_0+bkW@$ZQ2V$HgvPA)uNUT#aTLhk2no%K>kBDs5 zY=!B`YeQlX-Q%4uyqxKG(oFewsDAIZbD6gX1dMai}&LU*up5-K6g%uO&mMIN> zjX=Vi`@5&P`=-jpCUDwRAr(w{4RTf+bK`5$!$vt{`}q1#2df5gUfR}Yfj;>80=1W0 zVD613E?l;$PQHl=d$@Y@V=(Q65>y&-%8rUJ_>%V{9Nl!vaPX)!n~n^0nPNAIcqvFA zu~}I4XkzLmDMpsTwBY&0KttE#oq3j9Sx<=1d-KYNYx%0fRYJJI#EH;HE-Kv#2aTH7 zUmS@#3|SPZs&yP>5hol;>L$f5F1I{Iq*I2s7v#;Lcuzk-D!0x0hlttVXY4+5;YC7< z51Ez1=*GDfr({{0c);#Fy&;VUE!Xr?;$Z6!(Mb4lL@W5kQ@ zM@WPl-;(^LQ3JCUm-Pr~`JB}OfhU8fi3)ji^rrv()PP7K$GyPeO4qWEwB+^qPZ<&a zf+f@cz!LB(gM4!5$s*IN92jRbvp!nm#$oGtPLS2JQssQto#qwB9wxUS;l0))daT=5xQUef1|;;ediafsKn7Yw%Z*Rk1?+prQ*f*}j7n5m7z_Z|7KE(s8|XuhG;eS@V{D@1=xV zi?AUGf9V-B0wmLvc|5v^fNkbiumZrKuL(-^iHZ39K67jbm1YfUaJ7!%cuw$rbmjoI ziooN$i0wR*HJR;@YHQL1ki|@mP0`dU5^*1RBi)Z}@Yf91Q|TVGdSn0%k`e{y@NfMh zq2=t9oOIdCT4V=pZoRZDIXi~0a4h2?HV2q88^xodK-iE}_tMuv1rKUT)Vf<8CT{h# zuUjBUNv*66Q}vJLLYA zG-t;6)9x-y_@d5|0!g`PM{t8avgM z6UCa?k*a1B`y+~^n>F<+3Q`)AYKij<4T=cB}-E_EM~pH`zQbUkkCeB^#u zAo8JvK`#CW>Rrm(#CY3=DBXH(+7xqqjrKMzDs6K%s4g>#lFcJkQD=n_Yf8YKhQhY4 z{?5@+@Q!kO<#S)!0Bvp_WbIVw(S9rAL2EGEo}U=iENIF&EVqE<=5)ByAa3p=#;gxp zI2>cT+471-UcGm8(q$ZLF;?I-ocHV(%Q(> z-YlKCfbf!XYnrBlq$spXM`5yrLh2C%v%0>GdWXASQolQM;nDN?z%Oj{tL;_gHqlI^ zieE@gOp~e(<0u-Ala3Y+E(Pr$H!te-Ysx$7*tQBKE>YlX;2`%3x9DgW&gi%x{5zp9ROAc-=OYU&Z%j~A{oN5lCZ&!c5#-yU z0N3xT#6+u1QSP{Q%AL)Ar zdFNo$lFR!^j5}chRLMOu@}=c$UgzcVagk3B<_e6oH7pbLV>_qcsG*|i1P`9um^6kl z9MsluBJ+b@(eRcx3pOW3DB?@(P=7_^ZEmCFJFXdr>mS@9x4R&Uq#j zaq1?Z&EXvCA2ZS8oqre^IUFFwLMhqs6u0Cql*=Se64A!Vi>EU2Zt#dceb(9|%?BRd zsoc@r3r~tZQ`fuD;*v){Cf+V31?2S^+&nroEV=dcb!-|SO(Q6+yg}5O;4x(5XH#@Q zT}_x^P0f=>PcN)6{=V@x3FMjzEY!K0K?zJ

|ZcO99|zD`*s=zl+Lbwv_0Gy~k5bB(bG(N!IT1RVj5( zZJP~!#MeWka|Y=rpQ|R$ow~BuXlT&h!hFoWH!Z!O{9Cg3t(38_3ygq@rY6nKugPvv zuzve%G!q*V@=F-V3GxYke|003O=U4!^9fH6kHSSk^=Du09W)Fs|1f=!t@63;RjTHW zjZ-OR>vl9ZasJnLV--KY@n+hZ``Niz4VUvp4p$?i8)Mnw;1 zB-eF{q44ovBKroD%A*{rB#-fduS)$4=^|j&cz%(YqgC5slE>q6We2;68B#JK3F4_ zFTz8bea~it_m&u6Ufl)7jJa=WvW3*&axA^fzAO)&nEvn4n(&k9mMNXN`nitNF(yX^ zFMbkwRP2|TUU2XTum^-YLf(vhuR3oDmlum%J2d^g)K?jdjSbIVif(1Npgs<@Ws0mbb{rJi!&ICTm*PU=jb1v_pIlSD?ww zFQ*>{*UFsY+8E@FFVLTKD5ac}Ydz}kz7+b>S|sK7caj~_4!2fHYbC+|br|bRcy|AI zLTr^3 z(xuYCJjE=AyL#`^iQhpDvd9_xq<5pi1R^Qads;tJwYc@~bdUvo`j)aPRZa6?nO zPfsaz{11zN`;)ZfO>?@wlumK^^6x_O@6ToGzAa+(>W_|-n5G81?sG)jRzfMWKKF0o zcJu?d)tY+y!9{ywqf%3=x~jUY0*PZ(dH!nLBK#EpG@3E?Vdk z^al^LHs6uZe3dr*9}bsXgO{dcWV^liJa=DWXhv(=n6}Y+J|io8{&V)D=%Lj*x zWcQ9(DMB9go=||<%F*fHTv4Kef?bbx?#_K^Lvpskubw^%Vi~6x8kL$)-P<$ur(*Ww zvtp}n6_C_rWyLwi26O7d1ZQ4k8&I=H98dmL8hUfCLTOrp9(puy<-%n=6A+hV8qNmm z7W`coD@B}dmL3|kI7M`m`x$x}s1zHEpF1=yGV3_wI$Kc$xFV}l&Zt%=tlhU&LhD;z zru;J-=@av-(9~{sUV4M+!x$wpTU9-H$&)$Y_eF6u8do3t=es_QWF;GLUS<5v>*fNb z!!|Hu<0wq~$~sq4aA*-`K)+_UPEIKDY@0P9Ks)?TkYG^gZygPioH;~``gCzY5&Oza zeo1LTrb?5>L+!juO8g~NZKqY!4;6bh3Yv2yU!MFF;nJL-gs+JW&%H$>dy#Sw8(d#a zQzja2tVv(1eOGUf7@T+~*#(zDKmjrS7HL6{z{C z40HC7#OhnsN|~mmmsknLqQbH3f9O_~Q|GGIgr6#(Z5ZUERa~|a#wa2h^6oz=7&PPy zj8;ONAZZ~CWduF#I-5@^P$P+HrYj}FoJ7?_jL`X~;V0VC_`VofUok)boy(vBmFO-?_UnA~PodyYIrrPcvXd_iTIYg6*QD#vRgSl*;!8!Muzmr_ zE{n!YoP6GYDZ-lCN+l5iTui9t>F5>X4Nn8Bhc>siDkevB#-drV()i6zS<_p{{dhf0 z8Bi&pFk;|$EBzHpCFT6QHtDyE0EgXWXR+S{S`U?zoyVI3lxzZjoDm2&w9_ba6%x$V zBDZ*%3k$l*Udr^om2=3_xL@ahTyd_g;1ONf`avA|j^P2>qPww8eKY}fTvkSX3T54& zLd%-4XrV^9Nc3hrPK&AVa4X%#On{>dc0#Q?1T78|VZ^X+P%2xaZhrB-fwEvwLD^p` z+l|_3PxTSUc5SYN#p4c{!#iOH`|+B%JEfvv`cPeCW@WKG^yFLbT_p|KeoeEHpdm?1 zt*QMXQ?c^jB+!v`J28vV055RvG31_Boett%nKh!fl0H59oo6xl$#&rya;bzf>IfTX z)>o=5X61kbaUTvHc*3~9{gbMtRvPS^hCN)vKBa*dG8TogUcmHwsCJROknQ$xy%pp= zUh!eWLuIT<5X2H`1USS`GvSw4yNGd)kDgTRnZEhuO3bt9_<=>)pErg7e%!7ZKt&cg z{2uyJO~1_^U)<1uVb9!iF zXepq-bArEr;8PKMH4fvxE|mAGFlC_{WDAMXN`u-WNB_HFut{0PQJHiE)uKC@{P9ioFB8boqUs8fyVY5pfHA3Mp-mTms z+$1a#ZJfTbxVG$2O7_do5)nw^AUqZ6l++<+u#a6uau|GVx14t^&qeBKTKG;vM#PQ_ z!WW2XKH&#T!ki-9p*1(j{`?)QqbUn@D8C7iA91+u(3ar%<3Tb(&xe;(zheTXEFOV+7N#~n&3^2v19%oEEVk4lU z|D1bdr~w^LcX}yH2zkc?Ggyo^?w1iE==EkiieYVs6h$aY3*IsPuv$2F6B@tg5e4;pQbur&WCM#l z?s{iZY19^z84w`AuF@5pc0D-LBSDyJsyW@;^PEcD15;?Z@_SIbx0e?}nJWtKj~RS? zl~AaRx8Q!-;eDf6qDqQ?o_^UV)24U=Sh;W9Rk+qS=-S-lX`MrStU=aEeO7!5Zv1> z!{XePv%d@y}W6U6kvMH2V%7{XOs zd|LSjIPC7m{$XrD`lRQdB(&%gIoS-=CL4G@tUak~Z-DmeLV3s!`!f3i{1;pooN?aM z=dd>%N^Ge%mBEydY9=3|n!R%Y6d!E(L9F88@p_K0JJ+;iT?3p(*s@WO%%4;)qrT(G zodWaKgoRLi+Xx3CV_Cig;(mu{4jpyb$QvwlkEzq|2p*}SN!^W|lYa~I-L;E*0m`C2 zf>|S0t6u5ZC&6zN)s4~{pnFk_<2VIeX6YL1oY~9J{@>X9u>yuZa-@1hnx%reEMDX2 z>lrvs3^Q*0foAFDx%-$w`+0DVG|V;0DUB3Pyy|P5Hto=de{DeMpnkD7Te;@2h%PyM zEy2~#jkyVQ7@r(+oi}l&2ez?eLPk&}k3;WRFygp?@drUrkTD7MTR7w!e^8nq|Kgk< z{P?2)6i)~*j404^tSV_e|3=rHQaHfE=aA3oFa3!m4~|g8a2(WNw9b1WGrpbAvfwf? z21pT*-6O_S9^HY{rfVp|9%kVN;$ugeW+%Z8!Pjxw0Cntik`n^#?y_q80VWXk$^8t% z*u$ORxfQQtHu)h=_9x%bL){Ah+A=2D_Tf5;fg05d$qzUXus@TxAB8U#p8p+=5i##I zZbKJ(mBrOd%8w>Mrr;$WVl>}bTZ!GTr310@%QKg8xU#-P^d7Mv(srE<14E&dF0*lU zRpRp=M)`S$fg@-5Fv=P{( ztFnRefeyxXK&8sgx^LN`85{%2e?>4O5BI@~ipw=hF^uxI3NYbI#8u%ytIK^S(NhMS z(4_vUPeXbmg?7L?~!-ePraM636)DA+mU&o zC_BmB2@~Ewf|GKI-rz6TSrgNHTe=P@=)9(Yjn8DC$U`~62TohZ^anp-LByItD3kat#q?FdVN>q>D-KO#eO4nF-nFjA zYtLv=ELyitxZnn6S3|)>{VBUWPf`k` z|6*RIH)v)h#)i8>OjJQkAo|GtEHc-t(#%R1UR6;))7JHQC%2Ow^k7gz;*(>;p;HjR$Iy#eGv1fy>{I8Zw}!vF*$1^rN5|7`li)j0FXUYeS?oeexoqIh zV>i|tLKtgmvY*g->3I2d_=V&Gt+Re3>5xMPaRe#5keEfVCh*&wJGK)jjo8_8bPHi<3lj@370p=09UGkFfAVzx#7+6a{z1imoS_e5ACtSSVsLUeCEOl*Pg~0u!5Ocz-a~$cAF4;tuP&Ro)4-GoIeFBnoV4!oy79KX&YJbTN&53Wcaq(%B-o4OCt^89syAao1(({E>L1C76>CrKMxKC`yeYoM+@6eUx%7O9Up^kV*9NOX5=dafrpM{38)b3aE z`%OG_%46E$U2r*~l>W+KLF+X!9hvT3Pm15V92wu&4xegYefRr>I|97(w!h^Eh(2=- z>gGpemeU&-rsMTXrOJ)9WiSNz%CPWqm z!Z^H$)AhrBZVa`>KH^3l!)x-pA_fgK!;ijIZ0W z?TtHT>WI6;l;tZFmznsP_%)fGl3bAv=l$mX#EK5osHXOyaIlgKihaWSEnYR)IURsr z!4#%*;Pgs;7oFbro!%T&LxaWgkUYr<2~L?iN-c?rJ=qheR$^{kXIm8!bETg4YrL~T z5q}fPNOkG?dL-q?5y~Jo3Jv?fLO1j&P-8XOutwM;SPWYYEo)r`zZ8xpKDET4RQSL0 zO7>3HZz;j2^O`mlwa6`DJMEB^#*cfFEr5EE@)z1Qpt6>gFJgaebhj0!gNDiuWwnzH;H4}SZgMOXPEqBQi(}avb zCYXzJt*OfT<1cM_Vp?LXoEb#@<86|pBJVIG7S72-U7#I!q+*}o%pvvL!-FE{mc!0m zrak$xk^|MlWG{)}4C$(LXN-|gs2+5tx-_Oqsaa_>|FR?JVAYn-dwk;*t7GpW`a;`p zQW0_kQ6M*3GaG!hb`?s-`z`WM-_I_#w>Nj>UD_S~rgX&+XM?$Ucy%6G375v7z&3x{ zBWQ2@VZP!r#s@Zq4A9QIoBJ8BDy`DgmmHeHX~*gBb6)S)-B`#FiQ?e6(pvwd@;z%t z5sT6R5t>smYx4sPn!(E#akhJNAMH)F{d~aa&E9*GR}Nz&(~LhHIMDT~Klqrb?iD3k zw)07msuwP89}gX>X#+%DLTg*65~jjBd@DP9gQwnhruj6_UpJHZ-3QG3uxS z5$)!Mwp)?zE}*DRdD}Cr;A+UqoSv1nvvem$<@otQ+m6*w2bq(o`yqOPK@lM-F1kdw zubji7DHWOR{&|#I1@AONC;sYs%B0z>HF;3Qw!;PE?=vosfxs|03O`QDemZV~3n4S? zFtbr~V>HSr*Yg0QRGxw?5N82dxb4qHADOIi%r{N2paqOTsZw{^l+#7N&9}_P`)QJ?~X( z804tSqw(Rm$!hu9**(2)23t5){p=sKJU@n9kfn2xld*T?dq{BkgI66SmJFMNct|Mx z*ox3JC%qApTs$U&7R}!)e&OPcPd)JN_~GCm4Tyl}Jw?omAO;f+fqVZ+dwdzXIeYmN zI`gqVET_*(A_5)&lNKnjp7UHjLwBU-0U;x3{m$boz_>nfz%V3ZApKMsd7Xe7hgtCN zzkdvky^slC<63e6-g;yorPhP?LOz};s77tG7({;t> z8FQsD=_3!_{UsVNS(GX^Pns#(cKG}C%z!gMh;c;2FXQ_iYK%$i%+Z6o?q^?{L6f(s zPsjOSNPqVO^N%Uyk}_|RHdm0!XyvULv*MEOOW04E$Q(*}txBfx=qK2bvh$`?>F4CM zfsp-y9D(8`A2oO)qBHr16@gTBuTU2IwG_-6o$Y9BcYnZF)5hY zY*haJa}8Hy-se%SYnRAD@B2tr_053$(6zGqoZaQ)z0yk~&u%0^?9?X{9_)F-R0xa$ z>v+UH4FjcBGtNWhEove>`K(2jlm zg}<0WGd*OqJKP6|zPHKyyCFTVtZfskd62gu_9%?2f2f`urUrj?YNuuaN9a%%$1BHnbY{R8Q z6h`9|=@?iF9*z>76a>AaL`M?AdziHr)6I#QZf7B3W(d(a(>Vc6nQ+ZO`RNBII3P(! zKW*#I9G+{*BFZQnJ4_u*Qtw>Av~ap|O(YH7M>$#jt1~Wt46Y*yZJ(!19ap$6$y!R= z4-W*SHZ}VC2%0s#eJFwp)UKz!sCN)U%Ena6O`juo%)-j>p(j@U8uOFfFVip3F;XA< zV2TP3S7aLz@i13J_FF9Xk~gVYA$)Vhy;>39;1KTKxzY&;e;(%wpIt2=?~g9JfcUImZyAMGzm>p}vG6iZh=DrO4#^N8oCv5G6ta zmYok-Pe1sVCB@KR=yu7*Q;LIe9>1A2K**x;F4E9taPiZtfqF``=80eWLe)Y~-k(zZ zVsrtJc^VtUCYjA(!3pmD?8kq2W^xXPBy%qH8(VHvS#hZPVC^H|Yu8^WFyWN3DX=RX zHyh)g=0q&E`k}*`FFUVwd*&?L4jDo-k;yfQ97Ys#7^2_(>gV<4iG)=PFKJAN(wFxf zvl>@{RM;C(1@t5|_YSc^Zrk;rAS9&F^!QJClsTe760}`Y5v3(HJE(}8-?tcJ1I&4a z!k2p8UX} z0Zr_a`Wv=kG0)o=o#`o_EK%EfOTsjf{fxd zS0KIWnI}mfxnx*k4@hbB95LS-8r{JjIw$)a2^MW+*B3g=M5V1g-h#9l$L8BZ`EopT zMK^gksz=CvgRKmq8{Ao>A@|mhU>Q!pNWu^KYr4%}nA$qaYFlU}k8Xl7a1aBFF)QV? z`ro5h*{Zay{97VNpf@QDp2@KgI?Gmf(74&RS$ZAc`^OBiq+C*)#DxCQ$7CQQgW=6~ zIT-c2ur#f~LQ0jDvpahcmi%muRDK>{BG+1<{ep~)dDw-_V)xh>Eo-y^(qZ2A-Bx_xo0LXY?odYVGf4Jy6#h;=VsmZg1J)7-Z6 z6gp0_?a&kXdq!_L2GN{&YHK|?d|PbSc2+{32iNerS9cQyw8DcXBUUZu&J?=vn7DBe}SKb~-!`xm7B!hE-TNgMsZ8ln^e`lKE zpZz({u7P#-e^{Ucp1u2 zG1AomNVV(8flO^fPI2NE*O1C#Y^D<|=G2nBx*NF=PXBuDODnhkShW#PxD{4*i*r$V zrqXbTHh&3v1fYgDpR&5+pUcFE6(Pt7ZQiowI{MI1VIlo$$bxkDoAITZE0XQcqvnhwIiN{k8+Z;GYrO?g_7S$J-en6gwf>0ayr9&mP(#7zpeCjT8O{9_Q3=yR#3Nmu zfv^WO$RXH#YTc71M(6KPYQ(x#sD_{hk&lS5LbMc6oVdj@x9@UeQ2>SC3xx0nUW(Yp z6#93w_*F<&@|Yyalp#Tb@(Ax*A=hpESO&51h}K~2(5IB`r@l|h&Zn7xWvlysJd^J+ zqLK~Dod!Sb*cz+N){O;+co3rG+Dk+F z>Ta8F=fKdL{3o~9&$$U@qy@Zbm+tn+Bw_c3XGlmWkwI#KUZj|-j|}*A4pRA~F8d&3 zCVe(#7=i+y$m0FBuYZryd0Z|xa1_17@c&WGJT!^qH!BS@?NI>xk|x^DEgZzTV&%5c zhljJ^!E;d{+cL*3)ws7@ak{*y)Ck#y3=2)p?0Fo!4f$9i+gm)2$>4If2V$hID%)Uy zX3k-LUH)x!3V+-*m0Ul6gPfS?q#*{TQ|u~)_stvdGi(4M@=hV_pgfa)vVs`B05zp9 zwtY+XC{>QdJI^U&R*7R((sZ}B<6*) zF(XM4tl=^6$~+1$m*h6CFuyj#HassKo%S~-7G(|NM|N@#oC6y9b+$=Dx_*hpa~fxX zsPJz`&YZ@$a!T@i<&NieO&j{?hBhjs)DKkAx9{GR%eHlrK417r)9?Kh-I%j8yTD^$ zv_a+D$fL+@vBzKBl)^_t*I1tQS^JLHkW(UcoN$Wd>j=a!!tUQZ3qUQeyZ)aDf9ihy zjVP_@6iV+)iYrgrjyg(lBHvlkJgETv=YMcJ?%fouLVjl*^W`u?s_tYftn!bAvCaEb zLVnWPeyTr4+VBswv`uu3C9_%Yj5cCCRK%_$#;&7K>U2I_dr|4tiF`^Gavau(WSS)H z3cNz1L0boGJ!ToQIZM2rg2nmDe%0yUkc_=>R{R-{>xF)rC*Jezu-V=C0&7%THqJ5$;ssX*uR(&iLs zNw%(pVur;*(33Ew68N|e~ruBDkgg*@XFa-*()i0cMi)uY5bP1yJ?>0FuY`oZvpd#z6Le z>_8H7;p=}Bo05JU>}tlOh+QRY!b;xQlnY3;!zW>t@C{vaR^aTJ`D;_@wC!eTJ7`{o z!IxkK5YqH)OB=OKZ(nc#{0#qyZlQB+(`(!O5Be@&+Fa$<5C4CJCQ#IW50wg6gKKf` z)RE9BqNqxG;Wk$%zLVt}LVqVIQ%M*@{+q^rT2Ray(uUhumZ9eOW+UC3K zI)OF<41e#wEw3}~!)BOBb{>JHE`IZ$t1R3^ZMoStJI!n0s%FGdPdO*}*Ro~cTXX4b z^Tv2Pco;KaXqAd2z_4T1+njDv#=RNP^OaF*6sf9EQmzut&)I_98Gf`xro?di1%+%> zZMG?wXxbYjWCPAWM#)%}p0MvR$J8ec^`fxWrI86yj7;~&_|;a$Yi-7j%6RX5N*t6? zv>?7GrV>(#t?&_qHHBiqE%JO5?%PB*k4us2B*Fzs@b(>j#LL7Hs7;A`q5C%%SR=J4 z0rye1dq~Q8NvX-AEaX%8@bR2W;eekrFjYvY<&xU+By-q-7s(N`05yWBioU$AM^|DT z9!Mx(lxuyfNEKp?KUV0;mYFdpcTVEB;yC=jYzq7($PpCb_6g^!c&5h}=0m_N-7$Wc zofo!2DBQ%9Mh06j{MJ`=rgd;1dG0&3{r!88JSeb9skVQfZpwPjJ?4c#&Fx+QN)6|J zs#gbm_yL+T<<|%I2o)b0TCK+=|-{vC;V}SQ`N) z*Dk^^uE&!&_TxQj6BT&a0tiW{I-8?@q{_hcUiL^s+jULE*Bk@odTUg?;(51?YhE#% z5xnJl6saL#8BtB)jV`suZ+?Uz0@JQC8tj_!f(H}F@rGFF{P`6>8iS$vGn27x>DvC8 z-2s`&Z0<-N9q9`~Pq@G4Q}SVyF%n7w;e)UTI@aPxCOI=qG+xK-E4d2LzIVRmt1ixB zG*Q0zHON~!U^;V_Y4az^gLi_7VL-=Azx5-a1ZC_~(TE3B6L7T!=16t$@Gz$+?dd4` zH%d*-_?vx%OhkfjoGNF%Ghk}{X?4?nh2yG>!w(>MY8S5&Jc zrpUVx;k(1PeINiHd6Wv}HIaK3hBq0}gB=`^ga>(b6`1mPM{^;1A3A?ZVC0_)9f>zWSDBAzzi|-!xe?Z9W|wBffsSM_m+)5j+ZIpj zRT<^qWP{buT=Py+oZ)_s4tf9wt92U!Uui24=+qA&eeD96$2b8fKl;^j#ddVJ6 zoD=;vW#v60l)K>J?I zT1+vePj{tt53iJCTIDB5`+HZlHpRnuKv;p>8x* zN+7bxfQv3ncF!OAtJ5OHxbU`|H*oNV_$Iu0|M9~hm&nn(YMiMRs8KR=Fp0UCPl>VZ z7$?{xv1dxJnHu%MxnX^_9mK3N8(|B}}?Q%WnKaqJ}xNXMKf*OLmq&0J@o^c1gMCMoVZs>-$-w;!;yGrs1!QpwR0 zPe|OGkifhfPKN#&WufSB*Mpn*Rs@Y7>}XB!iWk*6N)-ZAdoL`weCz3vit6XA;}1VU z5|Mw3l;n{-3ve$6axJC<6>5P(%|V=`^6C~?##8sv#2b{F9LmP$Kl#(9@$f&_R+*?K zc&k^V<3k1^bFr;BrxN9aP^>J@G)Yol;g2w^eHc{7*Zq~c z#}dHUSuc zVAQ>whL?oPyjb$^8)=8FuzLVS|Dh{a?6z}8%`vlH+Isez>svle3nqd#_yM{ zGtF+a-GeG8`v?qEymqc!BAyqgO*VRrRT*CW{zK!=@Kk&3c;8VrsnP6w1E&3ZJJCjD z{y$0$ih3S&0p`0t#{N=(c7{d}O~PFeg%$c_=IWs>^jEpJw91Fpk5Kdow7IklX>8rB<^xhy)y^|T71l^$WM zpRAve*KRL3o|%~6!tGwisB1ue{gHn7)9O^QTD#<-qX#44ru>1Cd~YZ#n$zRwzHl!u zvXf)k&)K=Iv0MwHM*f)FP5x}kfbNNP{Sd^84npVBkyV`?I$l9;m{OyXm7fb5AN%>B z#DV=T-G@(Qp(DubKfQ_$1=e3=&YanY2}Q(9XI*ck=;me4n5{n=;sN^zzlm!09j)A3 zxsX%%PImT-guYr2z0we5RJ!_a|5M%NLEVhur9}V7aK*)A!g&Ft0`szY<{-Xu%?PSf z-+aJUgxUYGlRTtso{o$I%rkT!bl>_QkL1p}@P|QsjsT6*YhaRT^$}OI9FiZ@6m`1Uw^y9 zV|NEKHR&q)Z8as@$Yht#_sBQmWXx?1%Ghn`Us&PrtHAo8Xo!z}$IpxiRgCy~C}b}& zB`t$8`C~RWAdOnYJ@E*iK<1d1^Yi zCx2|R(iclV0$P}kLfi6qf_HSk4D6^A`;#_3s6bsLcCj2U(S_&71lI0r#s4PCB}xAH zwLC5XZ-nIhe3f>|q3K@fmBia7Buhdg(6MNe=d>r>7Fe%jCSq)Q*B07t@_o#-SdEx* zhsx-O$;?k{-lUuPV>hK38N1eCOG<%!>bZW4-zh6*eZHPJ3HrXQT_K`@;?uV<*Okc5 zRY>bIS6m|+gafTfF1@RnwjI$oc`R8A%Knd)=dz4{k5_0NbOJaZq9BhwiTO?PW9cbU z%&0Rya|jRlpzXCQ>BzNLl!ZyJ)sjk@55Ce-f%*wtC0gc>S-bc>o|rLM{CuvCVBO<>(^frD zAr>;h=$T25B4kFJ+iCzzud44((ohf>Obk%{@TAPErA;bGetIahi}*1JEnubm?5)w8 z;L8ICE4l10e0}|L^aUYn+H4o*y{Fc+GFd8CxRZ>|ydymH-GxzaVLy8@BId8`hi7?i zd!)(JhuKO?ffbUW-$7+?It{EM)oD>@dBcZv>3yIfV?7#bsc^b3rbays)`L~L_e|?i zMq1RLD8!ohg%<`S+&|cVEu<*ku0RxDwdc3jW^J|)-3{pS;A^P1VmOVUSI7T!BQTPb z+bbPzdvFun6ciojq23&C%!1gjm97)qP<O(0bhGdGh8hE<@-EB zeR>5Y0W0R<7t39JT)v*3GK8jEgROtMk36$H3Hh9USFK@1mb3FHC*`44DDw)#biQzS zr#Za9sAK-hUbCD58C~sp!XZ#>3t1VeQVgy$VQm2fHQr8**-u5kAe;Ng9m?ooh zcJwH4m81_3$4j(!0wLc|)+J}*E42p`j#M%O+_1%2UKsiWYOZfpkC1EEkx(`~K#KV`QC-u?F z{+vaxDBAqGo95{7Sn=IJu~|sWu@_;rIA$;=XBXnDYV$Gd+HV&ZZrhp9@0I~Aub+SX!Ll)~vxlD-?he>ijm0vHRW>K_$F`goS zjnEj!NML>>u?v&pkIleB^{9DPO;ddOqqHK^$Og!iRJ`4w@MibYE`O%c-rk|EUtCgm z*vdeI#q}!+R0*PrS0&6Kn^NS}qz&!cLTMuD3x;bqPvv626~xBKsB`P&Qw%j@yG86s zBQPjdw`8o7Kt^!l zQLRGd0YYX7ryRW)gG{xA^C8BWrxLRd9iY}gn0srr5mQ9rpL{+(g~&t<7{V`ZMLMET zKs=VK4V&V$0P z`6mdSO_Jo9=skD!9O+cP_uz?-D7-pp0tQu>JRh86n$g8vKHA%N1VsFaFreR+I_+uS zp&2JxFx(!wP#ut_l?jvPoJeu6Dyk6xI?gf1Pk9+4Co|j^i$bUJDOt5&;^7P4F@J79Rk>73sgd4K)k0&t6Grra zkPCfSxRZ)kKfi=+2OsZu*HZ;9%MIfPfdI=ZW`Ik_)Dsln4>&_JrI`?=J86$E){OYG znhKr=RT%3R!I`+-Sp*9Cu{(_-uC_ewhfZ3}8eN;1Q@|A-=`|SAaIIx9xePcrwP^M# zlySrVTj8`G0P}t19z$=EbNUatid2Hf1Wbh?>XG`w;i`e=neWrjV&XYX400=bL~&n7 zgem@Y3%^Fg{rQ{yd4KgBq+X0e?~aqsy4_aRco2(N@+Xz8iZ;1lD5kjT|JkqbO&pzn z^$t~%+z=pMqBS!$16ntFL%mjr=pQp*b44!2z9d9Z#>!7WI458Sbg4Ys@D^TsdPA$H z>7UIMST+XA4rfyXl>#N27v`&`>3(il7oZBYYy%mxuJ#F-y2OPPd7%c?BG#%YljgHFbR)`Gf}5sQ zss8j7*xtKZLCDJYZd%y5O6U7EznPv!HM4S^uA}%n1Zv*%7JEbky5KK1O^6P&hsWTxQA z_q5AJ@A}}P$M!_;BfAhk%}s#;Py%Zq`Wo5gut`B@N24y-+UMdGT1=4>*2b~*5DKp= zR;d;yZz&Z6bEN?b(d6K$5qRqhhxt`W0;NWe>cI-x1paidi0JIoiJCo?f)=BU{foMT z2>4C(>z?8?R8NNzQYvYvrf-rwS8PbR?P=W1VN^pQ<+TucU{{^nf!oVUB}&u0beTB8 zqHN3$g>UP;fdJGj_h-u&QD92}Lu5JZYH~U(?V&po@_ICg=2y6;I}z|=SBo!Jbe1xiA9T9XB@wPq4YtJ zB(-P(FVnpP_YYIdcq&i*0)*JCLOTz4bkm)diU)Q@~~5d!sp62xyKq#GSj8%Bi0?Jjeyk10f*^twr4Z zeaj;xcYr*U2Ic%HK^aaIit5zvj(1RhiiQmk z^_BwZE}5*SYkDkOWQS3m)ZO_<1r(`KIBActv!1<&Vp?guTPfXmi?r0lWb8`oKUc0X z{j$g-Gv}!<))vd{+OIkJ1?<4+CS*h1$=0hY>0pplSF7ny^U@>D{`(YRBl63c@rLmn zmE-*TAN(Rs^aAr*bToZwLAQMT&3jT^S^mTkj4G^!YvbWipHzp@v*o!ub*gpm(4EAQ zPRlEXf&76Uq=c)D$1+e;c(*ml5^tc8Q`xl4r#k~oNK!s#C9>&8S2(ZE8Hrqq4n0jq zg@y!i6TZ_hWxY#}4Jxsj3V3=ECeBP;`VLG6@&m#iMWLy_bepSDZy-%`yK@Ge^z0i7 zxmMtFYd(|69KAj~ywEH0M4(QjTb()qITdb1BTMfeWN)amVX_)4e!*iX$E9$?i#*hR zy5ee=X!@@W?&$$k!b^a4E`OG9l~O`H_;zXMJwk3mh9u| z=&gL2${DqHCsCl{H3iGkf1$+3m&Do7kzy?Bns?tKH*r0JVb8(@8f_AKtDZd2(ARUX zDE(E3IvjUZ8!nJf@my@vp_bf0~vTS4GhAmD&Pa&annN+db%co|H z0-5pPcYeTp+L4tt`ahhnF3t$iA3;ic$e11igsgMSN6D0g)e3F+>6h>^Z=!m3hwm&o z<#d&=uR+ed{#HR5)<45Cv6-u3=Jg zmi6l+YHL6Ffu1#bP$42I@~%h4Mm;0A6*2HFNWY8r>q9?-7c_(%f0tj)7Ny+H@f_G9 zijkV}Ae-c)QyB{*M}UgfY85Ap|8s|fFI1sWHg9may+CwKE58s*gNrv6f)!8`O8Xan zbUqE9!BudS7&T~8Cd>2#{h=gR!f-Pv2xyib{*Qx9U6%7w_!NT$s_tu=0aErrU)!1K zu-aq~*$rWw4LOU;WP(G|GMM9?m0!;%u);w4V=z}UzeE!+O?-EE#2mciM+8_V({)W336)%adK7M?pk$)p=+%9_CYgDBevc8lR6I zpnd^6K?Tgf=`z}S%O3r&ibR3$k)PhWKN6KTnd@1cllsVn*Fm1#t>N$+P?u`925R<<9X-FHIO|?S4O!{Nn_VFM#@nq7T9gU7^(+_^@~81Tlihoy zSFQ;Ko&)Af-9TruF&A5Zm&fWOj-PK}@UE#+uYmUWN^_c2H?lkOArZO^?9nC-;5d z<2AA@N5Z2Qo?=2tqmDwb??2H&@}GzwnL`|e(GHMo4kp)F5hReo4IAm+Q%AXE2={#6 zrzVMBASO?k+iIi>GYO`%LF}Z;z#(HPPQ>Xk%E9d~|BmLk;{Qo3KYhAH{1L-^lb493 zQ>G>H2`aff{7J`V0nU7foSyc+#y3Y{(>}J@p~m7*s{dezgK7?`A5NDF{UQWn$jI+9 z^R7BxeJ;={^!!%rzPRq4J19De%R8$EGO-5c5tcaul&c!QpTBu7t?=gVvuIe}#B?ik zE@CP-H*aXK#q=v04RR;Fj0`D{*FP zV77wPye(mTt&$16sRSZHkfx{FvzrNE7gMlM3{{Lu%$LRsdi*I@jKp}B$-$|C9eLOY zwk<2@CPAK{zNMl?e#|n?pge(%E_~9+U^9m0%Lvl&Z$!N%q+dBhPUtmWW~IwB`>F?M zs}6}FF6kV^SD(DolBLSF=p1iN;pUZm1d;k6{HME|yPC~km(l0{vFLq}AWJgneK#zJ zeuzmy3>r-J$lIVuR>1;S#P^`{e--P#M0+tI?s1S)F3Y07APzf|joeAYhCvzgi-+^D zioYuX^YDE@1BbFqZ5BRQ-66W0%te_GC@{qD4?L;}OOJIN*eI{r2G9T82Uug;6H2fC zNZ;aK`i17Bt~5G>&}fp^nWmAIkSYB+ZJ|h|BlCUZFQ{p9BS06{?Fw!)jiJX%7B-Qd zS+tmm)dt4_Zyrm7ZUDaYQnB*Ef$aRc{C`iyEv-h55Q~iZ?O_WE5+0zJ^o4YVE|JdT zUCa+&wpew96B#whQJHJKFb?+4wioO4_rXG}i|XSDc`}3d58O$v$y`z-yHVa$lqM>& z52D!iYqy35kwQ+5wEg8;+b_6E@1hIhp75}35=U%d_FgK*&LJmWGOjgu8f($U{`fU>jy z>bbAuQi1>J(U-hXqh1H1t96JwY%)nMsM?%>#j9ux%)S+?_%#<}X@>gci*a!K1alm4 zk<(SnML+Pyhz$2}kUV<-`azh-!X1>(r=JryAC4Uvf@cQ2pEcIKeUCS5Ajh9V4jnW$ zLlqG#--lz#jc=oeCg10uqfcNE#fLbaJ3|(uj7p1C$B!dULRctywUeG7sr&m@%mIg$ z+S4F)k4O4I95bJ+Y5y^gCT%X%c#rw}>MddJ7u_VMC+pDjRVwYDY1tE$^CDpu&&Pxv zrC0U9c%uleqsuwjbfWf89(n(%gy2U6_q`YUY7cRb<&#fDbF`X?KT}FsD77D?{d4>Ldv)FkLJpgdQl5|~)t#|1 ztfCV7TCyfl;L2nQGU_ozjY4gq?3!YyMyUzFN)heOCFXq9_*M3V&_v+1V+DW5EtPPm z$~B%lbK(P0jFINWCPjY}OI47gNY?D)dnZbFM$$#K6V10ypSxfe0)l4 z(|4`>q@oB1ML&#>!%SXn(7cvKuYaWgHKUH}DG5UABRCa>nnsFh^OxSP$#IO&(T?kIuI1bm#I&$((twiBBty!*E4`<%(OwY0+zD)1Y6ZOK+1}dE$66$7ZC+gt zlH2(IJbbl(ie*pSfP}CSIQT(J*?e+nz`%w`a;DJ7*T@++ z$R2W{*~c4S2vPijb@G*&h;14N{g7?`9~OXFxz#NG&#x#Ef)VH}l+kC9=Cu#aglf_z zyk}rzDT3qx&7VDy+_*_3KcnC_%Bkvx_)^qKycd`wZvc+fEzEA7{nC|1Z^K>vg=+XS zK7Q38h*rNxF)5k7t#ME4yGA-RX=C(F+yAaCX?@?lK)J#BmF!Yhv#qfkJ9_k_@634T zbX+&3sFV^H0aj4%E21AY-d>n}sY5vL8XMzI*1?fEyqA|DsQ8ZWg}*m(cJXuh^?OJN z!yDhSGy~)%mxL#Jw8@K=Cq-?hLIX_5eHG9>bivUv&nPxXVw(% z>`A`tl;%cRtLDYNcPGI7x2IY&Sk1H=Nm=N_U)ht>%txaI4AYMxrkT9h>jslNN9U{r zY5zuKl>JAL>6$wkpYQ31$0@5Urx8mv;mt@5v+;H*6)IP=5Fb~_*vc9M#b{5DoO!kr zon%IL3AcY0Qscp*dcu5Qg?)&F9DBHl9^mrV?2sV1HO3M9nQt3!wz*GsD33OxU!H;U z#*74*{w*KaNWPn|uyayP%~!jma^5C^bZt%IDP1TyoujbMnV5>d&>$&bEfeITxEkcv zC5mU2ul{|zBHwT~^meoiwm_nN6kBk=ry|CAdka&F>4F@3R?aoTg9(H)ofu-yM6#Gh zCpYBKq;hKr4jcJ2ZsO$tn_r*{hI9?TaD+f$<;9MXny~Cq4){(N^y9Y;W9f_-6ac$1 zRN*ZFYWh4Px8HsoQGbhYZ_W9*cBbjUk@P$rnBLYrBHJB|`yGl^?&p_Un{B2L- zCt8oU$2c!-du^6F939&ji+%BfPLKbw#$;j+d^XCt&KB2~qIjoCKJcI`k4XOV+CsL} zL?Pk-MuJZWmg}kHXa&2>)$ErDtJ~-?)rLY9I8v=4RUrG}U-EOd1}1Hz!4&~b%{f=gb>LlC(e%58SJ^oQJ`}!=HfR0`8UMMoz1~>|0Y4^od^M{{`@qq z%ns%NKGFWvOh+>Gb-TT6V%Egexo1mcchn z7hxsIA>dH3)|!+U-)4^+RB=1RW2_qWC6A8eJJIpi zeO3}?M_p)sa=yw9$eQmPAuiH=1K`3O5l>p|a4#Vtwv|L)_?~&b-*5obz)rFBwdPf2 zHWE!MEFWcw-9X!Qf6`m|Hau9N^PFI{oQaFZ3z|i0+R%Br!8x*Wip0{3Ir75!x#h2o1YqUW z3l=5HW7$ojcs^baGe__`VI`qkT2MfQlESenLI3=+S+JI>n$4H;E9|M)3W*~foVUju zBSL@Vn>J#WOJ5qiL-rP#6wGBW3>lrF})TL35-_d*&o zyljcUqe;|T@T9%982H)JV2vh^?!3w)FQbDfLpA+s=oRnZFaVqskwSnBBu{h?;VMPD ze?I;bqm1N0mFF;OVgpZ&jLuGKMc{&AUCJMjpnJ&G8g^>$^mxTAc_wSoEyv{sK+Jm; z(<9gQjU$nUui;a4bd8<(-IqW26w4Z3}sL7HAcVUq1f<)gqCjJSW6S?VL7++&HZzY z&u8H=NKG+ABU$3NbU$zC6@mn)Su=FH923#-@XE2nv_vV!x8im3V=ouk>c=a!lBX==T17ORc`3`lK(9Qa{)PY zv*$+CsQN~JHO)_)rJNRAwf3y=W4mm}&>sgkHDWK>vL`Aq6)Gw+6y1hg=^%^A8x6x) zCgZ8v&z;5Nc4j-_!9g!0rk2v4b{n0l`6r+*A&0>dXN<7|e}g*6{$2ln-v2&*Er;gj zlKQ@%K+>xVw8^OadHYlmh&YuVF&Fs*e>2id&Ygji??mUPb7A2U_cw z0Syly6fpZ&O}~!DD1+6OW{b;7ja8y3&ymztMWGynbsra;q=nFT5jkZWb|%?MCLfNg z&r}FtKDByl^s8EK>zf8WpN5<48&0worgIZqs()ui08l;CnK~qMU!8DYqB5|1tf5C) zb_8@BF0ielMxA;qt(0Fj71in46cV@Vvk(}-4wk8Z*xi)2PvbI5XW7=F@l7H;zbd6P zESu}=GL`^5CNGDjRVWDaot`c&f+zT_lQ;uW$L=(%mt{+S#e z-iJ7#ciRR}GI9V{33f$fC<}Hq%d$gu5cGp#zB(ySUBTUWf)!sqv(uS3vSU1gXnn^f ztwR(_O32^HGgzniJuKPcaOsNR%KFW#6m%@d7xOqIk{6j#@|VSrqWw+H?Emj9Y`8e@RBq5Ch$~RTNUfCoO$~cAvzsIXkE9sLAeSP~!Yk=DX>A4n z^Q8GVpR&a1|DDYrFD7Z#t&RLAOYs0g$=OLVA$*7}@@NP|K^HHJPD31i>wG^%Z)`H# z#lG_C<)P6&!~CYY@+~aQ*}+zjKmAV(ENR zZQ04_z{VURI+gn_16f;UO(}B5)&qZip7&idN`&y@O1RF;6o|9>VuuikZ6d>-{;B;t z{_(A)A`DZ$@KP=d!(F;aOWhOZ=vJe6WPME)Nc1q6vGPI7%}prhcn$CA1TS+Ik&^Gx zd{>7WY4Rxlx3_^$Nslu@|LR1MaqHnC$j(DJBM+rFq$R@C}@t(Ev?#>43c7p80RNV z_*_+?;b|i&{c(4Gi`{rNedr9l|J~fxfmXotzItm{0wNl*cE5WJcW4YCsZn?h-NKy7 z54`WK`6eq$y0`v`xBoukKfWMITfK_m4|>+_N3otgp`SnDca`$nYd9+A&XC#358y!B zVN`Zq;(TA%>#CT<{$*>8i+ju*}Ki8xj4AS z9$n=hxk(0)8naTz9UL2G8A0v-ivtJ!t>_8!bBGCMDDHF$WjV7n`;DBi$$7F7m&mM@ z*Y|#EiVEZv%(O#MTp8*vM$8QrA4n(#W{a4IlmtkLr`dO2gM`>iq+W3QzK~^rB}Cd4 zN2jI2sq7{~6I~%POZYLT&HLn;Vwt5^4*`bv96V!CmhdyUj(ySjP{0ko!*=%NPGX#M zVFWQm?TXC^Ho=_=VK;pSIaHeu^(4+>SP^V8N780Ag+JAw^{!z2bGW~%)A0N*@Fc@- zXr51!y%C(A&g_dLRZqtCdi4J*BEHEF-348Ac=8Bp2Yphqfw{gfkS25#aCZEra@$OY519%`tV&*FHqNsGr5Da=y~_& zfGE1<=4{G66PQ~ypHv8Z<~FqOD7SezWp#ospoe^~_{BY2H6Pkvh5G3s2yt=0o+UBn zrwd@0ZAkKnj9=>Y+wxN;M-G=~TSX1}tM450&w~rd)EOl0Jwny_`ZQcMbGR>R;@Ot0 zcwWW6UfRjq2p;I7-s36gcn7l*@Pw-Kc8!14uf2f?`PTaK72UzpLD*8vY_H2Z8_hdr za<@B_BYppzRfap|PKeIyMz;DTiyX+hBtL$SIuNd~|8QAwT-!S~BNG1IeX146YrUv` zNa<9r+p8%h;HeMhX6v&miApE_Os95{ndW%M<2654#`j#`PBc@&$6$ueYo_%$XQXtn z&F~A&0KQib695S@+X|)Bq_(fqfmH}5e|v~vdz#LmeKkl*kmAn2OAwR3?bm?3Q1bDM zORUJFWhS}bA!`$l?v@MDa9WuuR@HlEbtzKO0)+ zhpeiulS;yx*k(BT)vPy|_A4VH(c(A#@iB{6kWo=1YskjG3FM;pvqy?xETisRxEHtq@PX?_{HL z39?-hOLRYI0!K`!wrHH*>|gzPgCpmz5)u9Sy!cNmjWYRhXkVB5jq136QqFw3o(wOw zAs-Aaf{)C}$Srr_ef=Iu-_Q!z4$p!Q539?J^nAk#Q9 zHlc)kYmK2uF8 z!Qz&9X3Pj;6wpRx)zz7`jVKQ+M2Q_A54}$0lIgQy1cVsj-{3!_r?$14J*;WSG7H-s zfR72!&|#^(8N7WUHzas-C8|nc!ZWWWF7TZ~W!`Da_mt2>Ku5-NeO&8m1JzznX#~Gv z6M2|;F-op1$kxa3-G1g_?0WQGv0)nCMPk%YS%_rp+>YUC;A%;han7f$C2Em4Me{upj zUz6smKYLXcbvdZW$`e}5%L5LjKR7aPN9pr+R9jdMLS!xdf+do%fmP{tHm@^&cNKq# z8JknvIjL2-WZLoJz2Ky%@{n8(%^YB7GW|_%PAt zfdJ;_n~j9e>x(DOrR)(41&NQyero2Wz&_?z*>zp_j!U#WH_h+iB)mat%p_@&!cMGs z_QW{KUv?@&oosZv_Q%LIM%}TB5&sVeBX; zQW*j|Qw(46O>_?IWHkt9{^cGs$CjhTnw`VcfxTr!QZC}$n$e`PDSCHKGXyLg`gXyw z6`zlPGJoPQwPc>X;pkyjNxT+T?%%c~TybYO+bwB^ZLAxsCjxj`NFKOo*gdlL;L;V6 zg@Oh}Ieb&0P8BCSs2p_c9gf_zz%z#p9;w^o2M6H%q@#*&<1;p#DJ%(zM*JDv^HXn! z7R;q_8%1s~%hW`bqmupN@QnPJ8jH*B`b8*V!he z1^`~J@FF)0Uh`Pd%zoReU}yX+Q{<+3;xq7BxzbGzO^XQW!Ot6Gnla>E{-=--IBLK% z2}NpHcqLJ!xtpF(O6u&bpMfGZB~8peA>4d zdb|`Vx6$_N=~|${UVUz5{)S%c*Rx&v$XR1azSrE+Y{M)Xl&>p);$_c~=JY*FgIqv4 zG+x-p$ajlI`>MrV$fn!5@`b=El}j~pgk??KHkp_1^Am_n&_{o5S>Btg3}hg+l3!nI z*mu<((DyrG!lc$B0HL=y%P0aU@(2F8)_9@SK@4-aLR@OxuHoU5<-E<~3-Ma+GocQl zO30oN1+x!7A(Q=qWm=B}d+Fn*kNJtqf2pRoQs_=8Y`)CXvIbrE^kq~+2Y#|Di20{y zJ+Oh&>&IO|B<@_p(1k@0fV>*@fs7p*NM9wikE+EF&Z}S%auJGk%f1l@&k*dWDQi|FvhM!@*{TIe3VoV1<+fO=ON#y|P%kfvC zYGaHByjN>9$dn}QyRfrcANS}POVeaB@hHH$?)NcZzq}TR(4SN2^;i=7QDD~dS=H^=F1q>A)B1UqTJEd zmx&&ENyz-{jw4M;PXis)Q*PVY#cRjNt0YjSN&=)u0YR|gR0c1Y)33lT5t^$I#6dTkca$ zT^y7o8`chvpltYtt*nat^EwVSLGT)89J;A>@aJ$mxDSa0um)fsp# zsTlEus;Ea^tc|=rdFt7Yej~5Nck}GxZg}bI;GcQVwmA@NU3g=$o>bEK>T1Emf1A&& zqVLaXNDZcXw3{b@nJf@&*WS>HO#%3J1X72HVK*q$=`h!TA*S7|H%RN5>+l-NJNE(~ z9sRYS<;OSqPT6_=RpL{WfOc*J=lIPF*jbI^A8z#{pTmBfK#HeP59Bb5rE-rZOg`o< zkQbM!SPEL{3H0$x#!G97UckIuCLCH5g$G7xcQ+V$e$rkTGv|T7-MLl#C7kZqTu1m5 z06a#fG=EK-?bA**|3X?+(r5a-8Iupe)awA4N6l3Q5^m7qSwF=L5Ofxsdw zs=gOsiV%vXQ_cXLS9;fcJlfIYuR1_doX^z9IRYSIeXXw3sdKNiul@$#Bm1|^@#sCk z=(8TC0+_aiZ6{wNlTDorieGceqFsT>WPIdx>&6q4G3GmOItOIYB=xY+CVA4{eRoN5 zJqp9&@=;iq4qh3LoOz?J7FT&cliG!;FOkUa4pFl3#DiSmC|@9sY`--2!!6G14$`aP z^O|7xbTCj>Cr$kgj80%xmNaskYQ1OqOT|Ppe`IL?PT7}J7Ev9Du0gNw=Ymh}MAY(Otq`6Z#NMYGQDFVl-Od)zPg(h$F~{K7 zExkI|vwU4K+Y;ajM7}TiqVZnN7Xc5}|9g{SuqhQ^i7we(gI|qYAkJ13FiyBT{n%BCl>(2rOr4vRXeOsV|x=%)zvcWXgpGHkt-A<^EdKQJUOFH(q!J8VvYC*oQ zQ4F%zNZp^yv58%p;aiRJWcY`w=dg;+7MWEe5-c;mW6KS0{nTT{(M900_32};KUZQs zSwUxfLvJ-IK+FUyYXkGEHQ%w)J~a%(^b>PGv;(o;lv^77l)Nd({5cQK*mvdEM~(kC znhB!DlS`1R0ce&CjR}OWUZ^>6SoD&oD*mZ`S`CXVrH!-M{YU1dI=9FINnpts=%?D! zuiJ&T%HCk>rJGMdgEZ0ODN(_6V#2HCn97Em0}==;gR_XG_cqYdwO0VxeWEk%IOQ>r zPde1qWzdABl@rla{N_s_nHqR)PSkdi9vo<-YK5ah7={mpQu$Ix>#Y)q2mbV1y;{l= z2703U=2yxjJbA%Ufm5wJKmU>{Vo~C{4#pOtXAt3tTM)MiHq3Fx)s_t!fa?wHK0B&r zv1J6gK0VU~H?tr5NtAi7!Gnn2*;7uEy-K%h!+rWj^0Zcz5FuInsTS@BTyFUay~hzx ziQ(Yp^p9hXxNBvzSHM{%!OG6=n&2@5l7-X)Li+7*eOy0DXZNHmmF8JbUcO-9^3>|h zRS&SAL4@@`qQsKFZEbKB2tETJ&6}P@c7u&SO=Q6B8T*j6b#*Wrf5@NGo?DU4O}wd4 z1Le5gABJCt=3O`(z|bQ7mXPHwl&Aa zl?^r{2E}$Ha~yH)=J|<+6`KgfG z<)Gq>YS5)9YqR_;;SrQ^X1mUlqdo($H8`i1>0~S;$RYlMWJ#h@--`yx(`Ae1m-^*q6D`Nx1t;-1Wt1DG}xKT73Y9H zwCC)9Gq^j?4~Q8#1-wIslke|wYy93f{!t)j%DT3n9`pfKZHYn9GebTXwP&s+v^?~|k}kL|J?Qm0=b`VT zjSvG@x!cJL@8j2lZ}@Zg-}wY`z`<+$=FX#RJ@zInh;?R1x#!_~SwT|HX*IB@A|6V| z+!z0hf&Sg}g(6?iUj~22GShOL;p9sJ(%WpL)H& z1*9o2B|W3mkB($P<>?W{3Qzb?PRXVW?50Rno13G=^h>l7;UjXBL12|~`fX5X&Y%d) zi9!}#4lfsG1enO7^(T!4z&!vX)Ih&*@@@2-)kiHQ0>}N6SX0WB^nG*C`sc{5O~ccM z@SFGNteHpxi`8F94mx>Hg7-qzTYudL9^R*Xs*xo`B6ws8x4xQ7+yk`tLd^_wXq5pr zCY1!TBh_fy@h_I{vaWB%c*^6{N9sfPw= zF7_E7b1W~nUQNyWqE#TiltpS5SQ$P9kY#ok;dx%-qnz2=qm7UgGztZ37&nX{Nfalv zp<~$@VP)hsnt`!C&fccxAlNZ(I^{nhDnv8mQ*)Jip|Y|JHjE99xDLpn3Td802>$y( zJ@yCo7`mVw>0}A44FLIH)od$Yy5?UnIATlNa6?Hoisx@Kx7GlCOWG$Xvd?h*hiE1n ziQeWH$f&oIwpX2Hn2n0wqa zRQ zCvusYX>ol^R*ub7xP~V2Iv(nd*B0ayWA;Se&Kw+IHsa?&MXQzmAA_bQ7?6c2Xaa2s}&Bj zhcOK&^xqb`gumKhrgr`G+n$x^vCmrVS+uvnVYyR|4x#R5#G6ztkUG{;WXK5JbeX17br zdc{Z37f0y8S-GMLhIg5*e>*us=AL^G7)>QojN$8`#o;PmlUr#8%{SnU>u(l>>0q6u zU)x#wtT5*C2gXxT0YdN?Pbj_1$UadwAl~k%rd6Qw4Ym#nSQj~gE}w?6DkXgi<)JY@ zUP+WF(v-x`RVBH;9sPB#+M-$cC#UG1))Bc{hA513T)3XJXL?@IgY9Pzz}BnMF9izLw;Xy~?^k+X@y)j09w%uZiau-;ix1{IR;sr2h3e1GP9Kty#J66m zp3W6d=3y8qqs@y4>oA@1U-2=?&!)~O>R0OAJ2M_Kv!&nyyt!|TT_ldqQ$hmyFvux1?nfpk6_rY~zbl=&Jy{Ty@0To3NE+4Zxgo8u19 zJSOqq>*`CY4;QJ$Bv8cAPII*=cqvc+ zngdg$MbUXFAe6n&&LPzznyEll+WAm(b#@@bks{A>v2FG3l;*XDkD~!8&Um7Kr$$lA zHsZKxV(~&Kn(f;E9jW~FZ!!nAkf14ma~nRvFq!kB!~JePw>~NdiPfFkXU%l|^K{4v zPKM8dBY)Dh0#EBJ-(Ze=@NsXgA=bq-1FieF77beuQP9)SIaQrBlkZhaE|yF&&eD{} zTnOn-t@Kb}^c_RDhp`|_!To*t?gNO`+c6X}xvcb2py_XBua8H3_h;W~uYc({q|7P3 zz+S@acHvIftYaPZr?#858z>sV9BB6CN6YTrto(D}2#WDLxXlKoRsZSEXjg|XNL}RL zgeqNpDbz#7g=OoSve?+b6zU`SCgxSchubg{B04k8(+SgB57O*Ou9&=?ut&k4?y=N( z*ZJr9`TOPI%I-)Elr$u^a)I1h1)k@r(RI2F>`4u{u~%2C*IcX}gO=SKXdNVuC}4>F zo}djI5cJ&xcXD+*U0_N2oBH1xwGF8D#cPag#!+m6mh2ksbMM7)ck}`z-_+cwoF8f# z!gp*VN57J34o%&a^0{JjA2)Cu%=3cVRDQ1^E3r!JsuI&$f|k*%u}>^Y3)j?|7G_6? za_IV}8Zq*7L|Sj*)!;~JB`b)na?TTHq`|%i3B%IvYI<)SDHV?{i zCA8xs7Pgnsiw_xYuY6CQ)vCZbD5*1!ZXKWAR5$DG41Q5V=6n3$p|^{4xN6M^;UiVm zQqr#a+;C)t_<{E-^|@ie?qk;JhE*;3qg@zxyP_1;PM`*b(p@s=;eskb7;vR@ITBj1 zmL|LwbgCaz1ZX2 zia8Hrq)R$nAyafUSC1Y-aey#7 z=CSkG@SKl1a%dt@s78pS3e5_<=*J%V!XACQ*t+WSQ4TL#?8g#@4VUVBz0YALYqO+rdu!dVYk)S zw7t$Q_)Mcnh&yPh-Lm4(8%j>iEUB8f%+TS0+! zHSm2BP)_2?e-JDG8J?= zFk^?-#@I#L4AwUzh;l1nl9e+h@!3F2l+_2Z#2|=yU-*%SWN zsxNEdVe5LhCk`hzf3zSW{x5euxxlUdrbRI|Embhb(z}9JRO5!RpIeg$O6K2}mI{jP z5&9)AFJI#Mov&LHq+_6f%EZK%gM0bN{L#T@R)X~T`Es0ph01ajhGsNwRM^`~kUmO) zGZ)8Ko~*rSGZeE``%pDXNJ2XP%%sL{I8LM0`(YQAC?W{0WS${*9PG_ppoFHMDyvXm z2M~W~=?GW+>Q)q4DyX*^3Gbmnh^pt2Hg_M<`|nYy9(^L3Gii6z3rqun zohQVUL!>=Qt^s*^ot&+Nqj5wPX`I-9jI`&Lo>YnhlO zE&-!l@KQ936r9}`)Xh2!(|%(NUx zo+8NQPLp;xlqi#oe?$aT^A^a2-K(5+hlA}zMAp|3D;4IWhWiH8>ZriRtEP!>cIYlE zpFORdg5x!D(t=|!*&^41riY}eC6 zg{wcI8qK+9fIbMvPQ}}7%tc!EmEOK~;?{FU2h#Tvf)pf9l!i z?A{2>bEb#a-|AWi5TtA7>G;t z(kJ-6W3FbC(pi|J+z{{-B80za=WZweW3DHkTlG>VCIHCtn}2>xqcFN$+0VI4NH#CW zo*weP_{NrjI?&`ucrFhy`YEhVs*wri`)6!Q#nUj0I=V{g?EtyTI{RR~)vS<`3{XnY z^MosvSGT|R)3k6zgIq^8bWhf2{XsWJNL_ z%jXR_E7^4?L_XJn2jkk@xo>&UxIz*sUM;HJ;3sF3Ll<$0|K9KQ4D+?|cN>r;192z7 z2vH^4|MbeCeB;+_INPmL z2OvKl>6nZsv@sFiHGf6=I5C9tP;O$v`bv{H^#g%6=%(Hq0nYQ!z~)AW|vMCFQAHnf(`eitTTb;>&lbL4^jGE;u3*!<`bIUGp@-1inkn3^HwW z#o2vP*m6|0!(ExS@fQI>+YO!PEdRDsK@@3^#j17Iyo4)RxSvA8hX{sv%d(657&IIY zWX!73jz3IVB5+iGhk_ilj$#61?9!(=_ZGvy>6a)vQ4UHzAG-wkzB@2O1h8l_gn--tM?7XQ@k)J)N_6qSU*^nFtWUnc0R26__k(fUBN#-*7us z=7Mdd{OCPXbBJ-4NTir!naqw~IgKxer@|kW4RXw9$KEt%TYeOz+O8Bc;Y2xy8_hCy0$v?o2exK(^oa>g68Gx5`uQ0)4;m_s4&?mS>t&leJb(iXgod;T#y!qswQt#m09qb?Qg`- z0FObcrU3<65p8^Q=c@H>ZFl;wUM?5#jxADCo+xaJ+Er#vsCA2iWtJJJ4QK3Wmh=v` ziyII9=9wWOrtfE!bM&b^0!)o^0AU}f<5~s&KKpo*!%k)pK~5yt3>%f80tveQKoIo3 zPCR|=>J_j%S@wina%OSsnDV@A3%nM++jeaaTD*Xy2 z17{uZep2Lyyp|RuC)>iS!)(HiI(oN5!gLh5ts0_Ir})Y0b0-v&Gu3Z=8p%>J9J|#dhW?8=~bNQQK&{JrwKh@d*v$+iKP2nBM;t zRfC+FxcU-ghF-qs&VF zXHD;f{aAYe{@2a{M0?1g&&!KBV6nBvCQ~;nyVm!NLT8Hz{q!1PUs>4}3zO5u@vQN7 zc|tNW*>DPtoWQ%SU6NU|Fv?_@wtWvSpgJDKK4mI&dQ(nAhzMW+(sDd78RVMeyMm=@ z$$SSjCg-rdS4v4>2j zqTs$=&|91KWY#}SeyoidwK1y4>WfXVcaL5A1+KCu1+#Us!V@Gs+NFd7(FeE0*4Yel zw^_y-4~50zo3qlqq8%nqKOt@Hil8|Y4K1Hf)}8g+TM6Ons%mZDFPwLgB$dMH2Cm3R zJ9W^f{TcQW@ecG?w!oT>md!YBZ(1coUQ*CxpR7MWdi!+U!wWp-Cw4w7=0z#tX#zS! zJ;>A;&Pje0acjQ|zj=mfxIL6mOmOcp#%SnjnA^E$b&s8!A|5(;4azn1m&_+n9SJY} zj?8b|@nCqn6a4hqBUpfMtqs~dJUWWkaZ%&l2Gnp;EBh88{>w3_rRySh?V$HkPgKGE zSulG?QS0j;RTHd(6~Ch*uE{1MH*E~J-UX)B2onB(M508xF)G^fOo1z^`TG=yAeXV4 z3u<3a`zlNC|JybFNrw2k8!^x0@ZRo;?X*zn+})F&MxrTZuRW_T4yx?`U<#P8X+XDt zaGKEV0-ODmf z%UBy>`3kHIEbn1R$^mpPTGyq!AY<8ypBeVKH0 z|8~gVM71O8Z$bM1uyTH0;VTKxekT#*JpUf{58UP7jryji8wgryn12&9_wn6vN2}M| zm%d-ZTU3<@`P6WymCqN;{>;PrUKwit*`xdBs;|06#}yaRYT1HkPZG3o*Bac3S~~^| ziR7DnwUWBJ&9qA2&u<;!8;oA$-5&Zm)@-$JoyRmCk^%1ykRLaoEa=q7Yb7#+$^xy{0K+6{VBVjw9H*5CKB>9#USUt zSt9Du+nNlNrC~aAMvb@rzHOYb4p6FaDwE{jRxzo4;UnQ$oZ`i;jJ+f2uaIMb`iJ9uH&9I z5qMTiFgy@AL$Q(3@rqhoZqzk!peIX>$hU&NuwKNgjX{k+)I^j#NI1{uZDD}-M}lkPDOhW{M&D=|ojb5Xnp zJ)(ew_la1T1gaXU10Y09Bd{7%C(7;tjA{%!I?6`GX;l<*4( zy)9mL&UO=-sw@*oRG8a?*rzFm*=E-y(-cV*W%4jBnJScK1Ab2lqF7?A1_ICvBj*&* z;M%@7DckfUdg^wd+r_}f`rX#chG)%6gz()zl0YLF7he}Tf=OeexaY%nA_PydPEPOz zc7q%IYT?LsV%uH6mNTr`;X6ARO#(i$6*^9+RW>xZl$|iK9ITeG<3j$y_x2rH!P$oGOc4K>n+qDQNIyh z3N2OBY%@39*iM|Yk0aC`!{RR{&TR~E>===Wv(QJ3o9>Wp)|C7kN>6$0*SVZ&!zaId z-BTACipA6ibC9^>vb@)+$w;VR@ztfjl^D)rep@mjc+upN?mrm$e>TIPjKrUj;G2vJ z@=C@P3Gn;FJ^O;?^N+l|JasU-z$dE(Q_ehV$fI`909;OAH z;DiwcH|I{!Hy%=*GbzjGn>vHtkrQI^b$nU-&g#wwJqWAs$%`TH#V8M+fVJe%N;?OS zfi6$`a?|DnjYdLaW1r7ROvh4mUh5=2N^T3(6zn8&&#quDy8r-&$-cdCQageWRl>fOHHaBW=RV5}YM zFni-zD^fa?rY)mJr>Xwvd)3(Iu>BjIjKy1G*itZN3^6Jp&Lu%QNgmDmBQnj5nn*LJ zqi^^h$YX~KL)_5r`u*E=4XieNp|h(ZtIt4cpSv&7AxxdaF~;8u6tr*{@7xc9HKSaHESX0~cJsb!{MZk!HbPNPknugx- z5=tnd(mP5B1_(`Bs6nq93oX=8RhmjC^ct^7k*4%cq>6MxukZ15@Av(kKl1nh=Ip)C zKC@@mteHji0eW_1@b7}P9_w&~H!n~)t8cgM1O^pOH}o3!8c`yyKQkC?J)%_Xsd)NN zS|pFWt5JTPqpYD9`UbhQ-B+Wmg*WidDq6#nM2<5_=_xzx{}j_y_sEYfu7lQJ_c!-p zR))Fv^m_G?bW>pCh0U-_ z#Qhapwxb#*D^ZY!WM2!p8lKJhbriSPItu(Ec8B@4cIR@i41gG`$h;krx+Uhi>3 zKlNg4U#>1IyK&v8nOd$i+&O=XY`C8p8aF=DIp5L{%q5(3sDhi!$ovh2qcwOF6Dze# zJypy`_oQ?EUx=H{8!pu99i*Fn*yZ;MA-Y6~^rW}Dsm}x+)t)!RN`jZAF>|)*B=4Ll zqmTB5-@?75C!XFP1ABiRn?OR6OW8|cC4YUYI#&{xJ#h}p`p;!;jhkfcu4OkFl{1Rx ztEKJ8`*E9s`aS6m^t?IpOgS{bPn3EV1oqapnQzeG+4JLHU@dxM%WDY_IB62QzQ7?C zTjcPGtPZfmw^^`VhTFl;j3FMKsq>2`)pQO$w&`jchYwf#9X{3^X^lhBWZ8iE<}9Zu zrkmu~>xcX4<>3M{bz=Nssu`m$QNH6Rny=5W0G%-aVZvW$KTgc~=nrcX&p*zslzuyR z_@&q+-CbRp?R-MHc_CbH^xWR%5)b93h&>hKACO0)N42O{R?1X^yiuq$UR;ib(#d#w zKON^ilV&~nv?Xtcd>D4`NZm@tVnLm{phV&XC(>sWyaQNdup@P8xf2Cy3-WQ!EhWxs zNp8FTZww(uo!t)}IDSE)OxX>hnt@!_v&lcNL4+Yupm|WQwk3O7p9* zdl{|Pe->t4W^hkxftj2Xv!?0v$vIqT%6rA6t?+aAD`gxvm9S#?99i{q$Wv(bS-4cA z`A$a#`C8a%aoVUAMDc#_Gzh)(jwDIQE1ZC~AG{vlcuem`*O5H(aPX4Vyk*F-CA6ZB z)624!%lb>>-eYl%o}~Bt+rM5HFJ^5lUHNt@l>GVS8Q>g|{TsEYeB&@YYwo``6SfeU(8w;#TMs2a9G3m|0 z+Rfn|A-npcFP4Xk6CKi$I@^X}Y5}R0V1G=3F!aQvvO>=5zH?(9p7u@c?NGv;Yvbr^ zY^a?6@1-`#&Vn4tWx^-w0;CG5TwT8K>RU*0T>4Y8vc)QBl|U?oL%S1w&yA3V^$Z$s za5ry#%1&t84L+yzyZUD;+s>9o_n%zFEiZ;FHV7y-+`80VLDmB{3#;S7ikb=8GVV5BbNh_*iix)Qo6`eVY z-PGa9UZrgyTm8JiW7SYzFI?74)ASPMowEZ61fZI|JnuD8;qG*~Y$hzd<&f8^_UGoe zAa#U4;k4XmYX6F}`KXb2@lOb~@>&i8Ivs|rip`YS{Z7W=!4KyzLT%!>wRwg4SSUyT7LMo1a2wBF ze!%b4c2BPhQJx%C^=3JxDK$?_J8rbyXz*4_J#N&_N#IeAq}H?S8gc#$@_#2>BIhT) zm}%b{O-*VY`ufIqG8H@(vtP8JWyfL&=v*b+Na`0hTD5PloQWyR!JeasFwAK}(OQbu$8+W*J zw^m?`Jw`bEupnDJwkr?ru}q+4nnm#72cqgDFEa`UmY- zP`X>r#KZ`5bu~&47puyAs@V1vvm@rvqt&UmJBbzZ;&@CKT~YUgP_5f*MM) z-CjZ-(JajdGc+>Kiw4GquomCPu{Kh%LB#o??=`zJ#X=#$FXuA|JV>L`s^xlrDvku!>TRl#sYTjkT&6>Z%=gAV#X zar{bg4OA$TayRCrS7(!TExMCKY^>vlCG2ux!n$k(t^lgP3XeSz=eP7$)W!LQRJLyR z+(Laf6kk$dRV@69b6|>cb)Fpg?u^pkClJ6Q*xQ4@PYg8tUomqdOfz@%1XWIXv!q?N z?H-tS+=(Q-3>^-0Qft^RJ7M!dV2u;sxl#3F7LMNfQW9djJ9;Y$rHLy|@8E?4L*SJa zGSYcs;75JrkGA6#C7vliI6Pc_v-pl zn#=74uH!(l&&S($oR!~-bZO-}r)9mcnwsj`!hSO`5--*|Zx5Ep@WJOx6cImDA z(DpUUPJRhcUakl$rIv=ym+M`Yb;%>9HvXk$Xfl_0$#B`CPP$;_g z7B6J?u4`!`g*0%TbWx;%wm8i&lh`85jNh!O35Iq3qZIMF+<=NN&RE&u_Re}us?QNnFC@XV#mHLy{Je1 zEU(-m2(~9~alm6xY-N>O&JgcoiKOM?FA%LW<6YXLQXJywtj#>Z zgVJ*E7a07RT6*R956md5#0;oPggGN%aF{E8%v)Jq0@zC6S-o{Z;>RD-MV(|WFWVZ? zlc(p)N25Ch`d+2twP0A}U~7h%U2hJyRw_5<%O+op+4?Wsf8}(s1bR~)x`TD%Kcu(N3yS4a z(_pfECg56NU=7;4jyo}i%76-xVbN|^jF@u#Xp)y|K2vt7FE>f9YQMWg`?QtNpBj0{#me~+UMZY$+-ak@w z_ns~sglHBgvI#j16;Zy-y0nV5_e5nhN-K0HxZqjZ@PsezwA#|hx*LZc0h@kJES74} zFzfmKx@?2Q%ztP9Du+A~-H=hOB00-Uu_S}e}2-G;qMH#1tu!>|4ROOQ31D$o9FJDls%aef#^{dAko3%SG zj&;8eFG9Es4)ie{y{LsvbI3hoyD%0b*JrxT>BL4urVNQ2i&+qFE~BVCpR|y|&chve zPa?$I4qI{h){VOLl#-6E_kd1IAp7u{F*&~WVk+p&;?Bp0+=a)FH$$8FhZUi}$7-Js zb|)O@jk~qay!~m6digG^z2_xY8?9n=HCQAxUUdghXL3@4+Q)C5-L&1Ovr73z50Ak$ zm30d>sjR8@b(1PIVm~fLgY9F>efC$?VvB_19T$k-pS(R}Xeb@Cpl3$LN7ms_2Xj}92J1B5mt)~xUMstk=|+k9nc`EzPb+t#2tjw7 z720UjOPh~pFpim{sy4BoOI>1{I=ZhGGY(8yM8j!~2V6Dm`C)qYCQ?FAEqUf@Pj1Ie zQ6S#0vWGf$xP*HuqIH`KE3BICWN=MMEQvv-;>wvzinF5;&6jF3zR+Ta>cOr{K`BR# zcNHR!3ct^I^2_jA$!@Nax9wg|^K(Haa%Kv8!q4DlT((EKE|9}aJl53&Ai|>^*L46N5e^a}JiC8QJJhchE_777N%hnHNQQkRsu%1KYyH>4Zhb3%C>)HaB z&yz(iCECr~kXtvPh(SWAI#iuqXwi;1X<>sBgD>d~)Zr7pO}&n}-q_VS`or~A|GOA{ zKV_{fezewSd-q^d}3iFyQ!^bQ zg^*N|+hcY&;-u)}5uN4QZ(@`y{5Y+V0mSA<B;1Pm)D|d%s!E9dVxM`z#yF{O}l^J`Vx`dqGBKNdZzSqoki}a6vPNcFG00C)nU7|MuIjBSHFT z1yMRD{q#M#2!0#efuVNaZB|+=oupF)%c43qv_kSRkzX&`LbQif;#>j!^7m=hmST{T zcr+J??FLp!@JbA?Gx$0*gXvRx%9PkH?n@RWSa>>T^gTPBOU$94jN@6Vg>!ljNOFQ8 z%lnVHSoF*WZ6(L_&ml?4q_vl#*^nWi-MmGpu6?$D!VQUI$};*2 zojoiK%wbi~ZWez!{QUDe+Hnq8bDM~{R6{|BN~QZi1ySC!eNG|p(&&aL(|p743iIv> zd&?`9a?leFNB|q<;Bahwwql_7;w-N5uJh=X&EWZD`vT8Gd#Ryf=ro(7_GX>t%v3PG z6@NBI)ghomy&pC5r!CJCbh?5wb>o6vQzrOs*r6wz>i6j&08q>?bPA)wHv@jWXkXeb zqDYH`R(;*BbUI&SoVbM1A^&{jo5%a_do65$Se9743qRu+S{ApdPhEg`BV24;$RCH= z?onwm*XJFI-wbBzEHyfBuM|fkD8)7Vbk|=vlF|L!o(txEy z-7HjMF_4OLOqEYrccJPM=U)-7CoE<%o%FWe=e8k^)Tui(?t*P4FdS5KR1HYD7kpSk-kJ|^{5I!EUv@sRv^S3Mh`l`rx$S4pq6u5_=$S??cWKzjZl@u zJV0hLt1~VC_{%02sm!s5y)L#M-J3Xo&jjaH1v)LcQ<;!9;04|0IAV+bfvnO2x{%YM zPY(b+-w(O_Z_2KBA2jf_YLdjy<6 zzj|I0bX{o$=L&2p!-Em!3HJ4sMW?R`uf?MmK=K4a$Eam1{j8hah2--`HR?|sde5N} z`zzXpj&}*w@8p42SUHhD5@21MEfth30SESV2Bl9Mm&-WjU{o23&7%{0P{^6;YW33c z;4i&9!T8sovNT|Tx|rRdh6RGp0_Pz>CC~mE9)mvoO9AUK7kF@?glXiZZ;+aS!G1_8 zeaPQ@IjUEoCsw#H7~HMv36Y225}0);ktZu-O4PDSQu_q`Z)b@rjm$`~}^<-MTVBuCe<=KyJeBaSlAC>Q-S#O|KR& zCv10ayz>m7`w$N?Kw?O#zU^H=u5Aq?GJgo%^v08Ee}9<2*r>Ms^2 zPToO-Qoz-4sE21+kx?7uXJ3cvsR!J6CXmO(-o|s+IJ99P^yK`0W21GdF6#Qzxd^U^ zxZkv`2Zt7(S%@~RsXAEs%at_`E6?JB%@9ZV?eaXW zn^!gi4|K(`GQ1K}bdK`nA&kTLBX5(_DkfaFeDLZq<)A#qr@yl^$hh}5QDEukl-?5c zNIBu4L%7)i*5&(U{J;UROn*c-Jdu7X&){z4pPYWy5bC*UtLL9mF8ic%d~ZLTk`!@@ z3`#SssgYc-AyhYgt#oHsHDnSnym2Ze+2{YLR5E}r6I@9za1Dzqt51|pSa4y1+$yc> z7AMDk7*C!&tC%Z)%rfhTb%y7xeB3^$g=w#aq88Qysl#Qq1Ln@h19O~U4?s0M(T2IY z&evUTeqWJ$Z|ItZm%CsSui#Zo*SDGN2#3m=sMPjg*i3sT)2_aCy?l=VC305X>a3#i zeYLksj%C7)KeZ^gv6XXBsx<1`oH1yZn9eqqu){C8m@L|nF1ctl0Cc$ldkCp`wj}Kg zj6D`my5Y-w1G8?hLkPwf$6kMH9Pg{M=#}p=a|W%RQCX}ijT9roEX_q!hE@}{R;^Wb zU{f!mV_RDih>gHoanF%&q_i<)f9RSwnP=pkFFUSjc_m@R^X#~hz-u>9l_~w1QPD+S zid?5+SaiJUTIT`W>!M5)?b)N)YzHD8cjUI9B&K*&71*X2YGdzD%Wb1gzQS6)UR%lX z2OOK#V;{86x&{&tK3gmC{dMbNSd~yKg32g zA0_Ky`BlJG2||B=qO}>?%m6`k=I96;sWgAIvJ|y&YwmQe-OX4<3cCA~bGF8+tNB@W zaa@zkq}@sSz$~A`D^&sY+xFqcvE|ySD~}46x=`HY08nru{-b$PdXhv%1w%=I(w#AH z<&mFLmQyzECogHEw#E~i6#fa--79u7rQ0a%W|jGjD^n>??| z4~ZMIZ8bn$(9DuVG=FJ$)R8mWmAl`T+TZi0*)$K$gmMXX^4-0U!ld)M(bAaGCO)t` z=zP5sUv507T*0bz|DeM;Ly1&_A|&Hxml|i=R#qmHktxOUqlXX6vfDf6_Nzdrl4Idd zcG7kH@5<{u^3Xm^f4Ej?&jsT*@V8vGBDvVZ^E(#4sW#CA{e_bf-bh4N+S&+&mvUk0 zEVCdIqKgk5a|nB0xcZyi-z!`Ys^&JUk-J%MKvS%iHMh>$lK9`99Q&VFBA(b(Eb4-E zb(*EWmC-;$ap_TF@fcn@LFPoaH$H^{OvH4JHM&GBA2ZQkddVRVJ~dAH0ohoA_q>RR zi^u{&r}dFN^lm!MJHB#axcXBE#8FNe`y|5=+we8$iFvLh^SH!fy*&Nqr!WTh!8RWu zjKq3Ob|#|v^qZ=uuu4#ic5_@|k)_fnpf5`ZLe)Mu@*P~UI5o6Uj$4nck43nXV;9MM zh4#wK(J(Nlv{YXU-D%p_hh6mysuv-izSjDqnS3wnwQ=>TBkw9r=YmSEAXxM?jtW^`U1@5&Y2Uc=*Z-6zCtTgddBKiF0L%o^PTOw=6dKG(Prb zWJMUu>l7q8z9*GE>C{K43S(Z5o>af&`xuJG)!!%)E%6m*`D?MnBbdvyGB_zaJ;D>D zvJ0>KM<25B2-CCH?wI!5rTr`__lZtwk}x=Kr}&NX)LBIs)L(+OY?#RGW`hzf%W1!J z6x#0iF-Q||AsY+$E|p%vWiI)ak?YL1;UJsuyIZH#f!=HpK5FW`r+lm32VZo=HR6MU{rM!6N^LS-ft+Vpx{?qPGv`NFFyJuNc zJ4$)+-S@<#Uz#iW$gx-j)-mo#6S;e?hw4+NoAbXdg3|ijQ6t3Vw-J2&^^zkm4_eOD zw_OxoyO)dNQmXY9@R@a*36kTsykli?LJAt4vl{;Ud{C%XAuW@TEQQfV^2Vchs^TY>gRSU6K9}}SU1_R%=!bMd&{e71_D;z^ZaqFn(*6{C z3vECJV=Eb{Bj2XNubMnks62FEJQL2L)LW{;OV4F)LP^qm79@5*M)=jzpm1M~LSkqR zgO2+@Zye{1@ErNqi&FW-Q$gV$_?cgT4?nqKf4%sXQnoK(Eoi02zV2Q@YYNm@*UTbU zmahpQEn;AtK^&lx3pXp?+;@1|S#*=xPUU$^OvFvefD^8zSj?1Qad}mSPjGJN9sgha zf2|fzrfHewgNj=^bLfB5X%>FS_<&VvFe}1Qw3& zJG_CJgg24Pomn^cK2|#C&V2mU)rdi#T`r`Dv4PjHrs2ky02*ZS}pFYNaQKnJPBXOi3w~i#N^c^Dzfu%_0gUWdP-?|2z z5zMf{3zCVW*M_oMVWEkgk4pSyuUnn#vN->LT!8OgWsz_YZ(P<%m59tKtK9YsZD_Xb zB;zPrLaonBK_=Y8h-p$1lR*f~frMb>7@W4u{$uw#OucktDb+q-aXKG}-03_ukl!8tGHqkmOYM#u9v^k^$#O8_(W zJy=M@HtPEq?EcOTL>!s)K1MAp(o>oVfo})q66Vf&h&8RrKPmLc?OmMIu~|*rx-c?w zmHPQn)=scO?vL#Tj9K)W_N@f{bswY9{h>wc8Lwj;bz_<%VRcj?Cwfdh zRaNKYHk0xA@Rbc4RZW;>HtTz?LmB8_y|M=`;gvz-TRO*k5z9B#Be@T0@tfh{hjiTM zNr4-!Sh6h>k68Djdo%h-u~rOBUQ_Y6!Qn6iH8lf&y-9son>zGFY*7WZANyk# zcbG+Zq_7e?aV^EcDffFA=9hWY&kPG_!;4PG$G31{%w8;ZyRD($;9?x{vG04pQ_+OJ z!`kBr5sU_0rBi!$$(3Q!OywQ>)u(qeBwCj=B8q{yAaumPU3TLVx8~q#Survwo2w&( z&Hef!6Pz$_vf@$qa_E=3%?#g`8sURNYgoVzv{{oL`yX00_?{?0 zQ$c+yj%&Y!GY+UU3*~??>(#y}$O%Ltd~2>+-xrMXtX;ow3BsOO{(gZjRrY?R8ItD% zuLA&trM^Ukc72vlD9ZBbM5{nH9xn1_vQO%5A89$R5URliYtpTT<0Gyq(vmch`BKlxhee%DjlLO}xYV=!*_=y8*V2D|7NFsn;L8 z6I$M?)TMJ1nID(6%_H2U6Z`SG4bOzVhph$-KpI~VTV#<)dp~IsJjndBf>VU~6Q?{P zwm9m0x(@Bfi@X?Ne_gt5>m4;xX3_Q3!{4S<$07+J$y>mF;=w0SlGZ+HdX!t|C?Rt2 zrZ%ll)c9;<_>GSr-G=w+N9(5?GUJ&=CjMfws^kIPysX*#7i7bhv~%UAPVXUagcWgK zM25uIzbUSF3T{DKOF>sLk4HY0mY*mMT=U-6PJHEV_PO6w z`d^Z(z%LKvvVF6s|7ZXH)CCB0fXwk)S1!9BWaG^D3Aa&~m{ce8s$1(eNWnO2c4~f9<+f?+zsarqaKH${RGN1SLR7t#k_p%2CU2tdo~Nq~%o>Idz1L zA(|tdM>FwmB5Hz=Ut%bd94`TP*Q(=B((?o%emDU*>~(Uvo=|frGaR6 zCW?X-^bWuyBaLicx`^eGe{NJ>)#VDmQk}Vcft%&%6TGK%w$!^YyRU6#F%AV9{NbGO zr46)rme|ddNZ)wQedP6&RsfMdoeNoeMlsx6IMblDFO1?xj1p04Z=y>Z`n7zch;csA zSF{A1qqV3=wM0(6BCv?}bzeL5y-`B9UPah*PA$%{3O-uEvHim!%dy$ zQwyGqm5h}i8Chk!FUPiS8s6@KY{X|b#SA^g3Qrdi0_#zf>i5g!1^n*!u$n4d1Ppc@ zf4;=3vHYh~0?y<5l14sX{$nEDQx!xrE7pC9odUFn7Bfh3Hy(T*uC?f!8qN1iHRb#z zJE6 zr`0a2nJPCcx5QY6`g{&`V?Qze(t2L(!uLvucQ8V=Sfb0v8)w%;?*KJ;pVt4ow&OrB zwp;-hB7n@Db9lXDaNBIE4>^0darVY%YiF;2V3e0Ap5x2-ukD*`4d&`%(O@Zw%%mXz zK~a+&nyz&)O`NZ>?B$+aSel+&RM3gkJ5a}AYqAYbp}05Yt`a!aS49)e6%c78ov08WFw2ymM9N=FW@9?Z>npACIOp^{J{Zqg~g^ zg-Q@g9%8Y#*=&eIlj?E4LhEd0@$=WHsk0k)epk5_YtZ5DeFb*^naq1Nv2qVxTMc-$ zCO_23L7xv?J6+WqWvb4J&9^zqGW@@YQ(7SR zit`#+*Dw3TXScDDweVu%w4;dnd&iBNd$QE3ifvn+!WnU>M^gE@b*!VDPxFp{MfY>h zxZ8AsK)iQ(k5xvQhsR$;<=y0ct5Ym-kX~IJS;01I(RMI_eMwM(H59uS$G$p}p#B~$ zSh)3=Gh+gy{_5DdY$jJBOwS)JYv?#nX?oh$UGqtebkCsnryGTHwr%MiYGL80QDQ14 z8;dZ!I|yhZjY}`kHx>KCb(>9*ynWk&$}EcS;638R!K((6_0h|YRx;4vS>io!-E>Ox z48}fT&mnn<5t8{txxO{w==7-p2Q4eK268B_wU-a2*@>&b*-N%k{873?GR_CLoe|#K zil4fzle%CLRPpfYt6c74`BMs9w3^p5X@WgsOj{P;`Y@gczx(=9CK& z06JOcS1Wm}eILZ4-JC7pB2SLGG4$5rMV}wJ3299@dUt$v^Tm&fxhXk{-IrT&0Pifq z06HCgTtB&j|C6FUuCeE>(bo+VW}H=>W7-Ouef0kMb~|lNc9W_12dee2q&cRK?O&c` ze{D;>R{Xs}D}Ti-R=DlJ+W&#aX3I!<2739OBrRqw)S**5>e{k_O$+g(|Ill~*--Z$ zg76|;*%#D`zs^nl+ShznYwQ;T$I_OmL6;Qep!O29LT1C|udH{-kbGZLhcglbeX>afZf$7G?@wIvzdQ(Iy%S8YDs zR%UT(zo!toc!tMrurG-=N9dn5}x|`$Lf(nDt1K^W_G-+ z)5{#u4%z4-{&QN@nRdISv-A0xe_5{;t5@IyV+DphZ0Vk(F+w6bho;rGQ^*sf8)9RYLoxC$hJk}G^dCmN5IDu~Lv(U4n> z(Mw7%`1bpk*v3wH(&2Zx?-sy}<07~$kOzF+=hrzmgS95|+B>nWNtzK(cmsn^Sed2Y z#VDQ~2jAMOvz~aHN5b1xq(}+KhHu{3_XleXY>BeW+=js-R(C$TUkiFk>R3qbGXKAL z;=Xu+y|gF z6aEUGT^hY&$#teIYvVHYB&y<5s7V{oFd8saRbUHZ`ZK`x{idh+`Q_eFQRg>G#WiseNDcPp*JM`E1?Da{u@E1F88a z*C_=9<+x?pCVA+AbzMysK&N)J03qGL8q87Gq5%U}O)sp%1kk!BlRa=E+kLep^?4b`>I^ z!SpCCdJ&UuY! z1AAE*#);ZNk)@6k6v>7TiQ`jhxzW-~$(JDENdN&uxa7h*y_X@vw(p@0CxO5P>$;sA z7A|PTH0|#=#X00HQgUvcm)Z%WoD$}k?j!1@7K16pcpQ^=pGo_&O1NM%*59DFlCq0; z#w+1twuHO_5q$mgwL1&|C64#7Dd*oA%h!2<@FWt+N;*C^dWqf!lp4p616qUll~@5z zNvlEaDYNd~a~m@eXD3t@&JFV@+V#HB`R-Qv01EYpEf*;fSPygbpnAa9=M#HBIC?(VAj?LLv!)XfJDx5It)iMgG0Bq^{XB$k#f}u@rq&*Ma%()-`qsX^aY0 zlj;RmJG6;-43q5p%VrQ9209WfF&Wu;K=IuSk`)^vO~eftq&BhhnbOmT2||o3OP293 z3Bn@$jBggdP6vQ9B~GiHM(>`%gJQPsl^M1swe7l`+qWX$@OqNXEIi$VE!b?JsG+FQ zz(oJdwfH~y31}wFBrmFRtiUM1)J-oRMF{sR!!}%ou>01s9s|?_aK_Rq4tYwSA=;Na zC1be)cOwwmDf@E{;xuFWo!|3H0VfJoJYG%+K6;_Wb5v;}Xw;~g5<+#&3uk6SgrTsE zWI1pOn?R=rPCN(R?t{D@AZ+bY!y2+>I%szEAQ9}jqmQZET^$$N-T$QvpuZ#mw3z2- zk>SiyuLv{xcI^&y20G1&{2nQ!k>yz-N7k~w(*?+_WtA9M`kkn2VejEs=Ca3_b0y)3 zwBC<9+f{_*8;f#qBl5^waVv#N`b3fFFBbThv%B?TDV@?(6G{r@Z$fpsVJ0(RT(<6V zv#R~gK(f0kh&Zz8J)m4hamV=E8lgF^454^kAMEquy@@+Fu-28E<8aNf^eM=O1+|!% z2&!c6jxG17TPh9nrsKBVJnyA+^K7!ehR6~R-MduJ4C~4 zOGq}fx`t^lGCLAF4aWnx5(Awr#3Rje0;a_pi8N@9N)zH!V-RI)E1qRZ6pkJ z?Q0s%#Qryt;-(H;3u6Rq%m8A-NK}6(_E50cx3>ow9&P1IbV( z?4I+ch-2wzcT>S*o;@vv9>#T3grQ*bPO{lC*YMq5XUK*i2*Y~s@FwU#WHnf1t>8t;%ddY`mCAw0b`DWPDiXU()H+Uh1NX)x7(NcfLi3CbF-0jo+nVo3hwASS5rebB_uB+Lya8mucJ?j z@oN*Kw;4c>o!Q%StST%PiKL%omQ^;%qYsZJaH$O4NS#QarWA@qis~LkGl^<9gUOce zERJ72GJ>BiUy|c3;uHZpnZF?b{4!&v3_6Lk;{uS>fC4|YYYUrED91Y!qZAXP+|vt+ z0Nq?_POwOt#Fhw>e{&|_1Yj2aF~pgF226-6m%*7VL#T|K^Sxt0qb=;Dp5WL8h%wTd zwA_hPhVFbUSQ^t5m(%I$beD%fTJ;WuZ+c>9!@unPOoTfC!Pui-3%uC3*_wzsk#vS- zfTtN=Zk`1S_kE$lS|s%kATQ3s9pUc*2jaim)Zp-4w7BuAT25r^<}bo!%N ziTcaKPbEhDT~}%pz+F$eIYngF@1A7x0!yXKA%k|7`1&MQE&L*8ozBnKqio_{1H>obw$f<3DJPQvN-q}JPey{$t%kW>Yf zSeKZ}ch%G`B#$l=MoM~-k;)A5HpQ*7Qx+-P{BCbYsKF{;CJH@jAX}z1x=t3pYm4s) z)jlz!gIRLK0Kaz<<`W7l8iU zAK4`H$@w_MEqKt&FM9wamGglG@+()V?@ru-*Kp(l?H2WI(1J$&k9&aNCZKT(l$Lz< z%;=g2(C?cLXD#`wHG4l06fas5Bz93xogO%rhFSKUqrgLLTj?oKpgbg??)s3c-B(lcoTWXxv*%acI963s82@XyFlr zBMZ`~X+i(s;=1yB(`{^mRf=KM5wj4~gIWFDGHb{OEi8N~J2=9oO*7e3U-_(Jqw1~_ zGCX0+45H7^ zNv$u%5gifXdbO|ktXOU`m+-99IdTkHRI-h5C>AJRg?dPnKvE1D%X;~p%5E}_DvrYN z?c>kR2aA+4$~?uCnhM#diYov9?>*hGcmwCsO&EYo_d&dU}f2n1oKJZIo$ z=^PMged|n#1hVMOO4V&;t7zOIA+XwHg*;+|IN};EZ{Gq`3iu&cG465NT{;DXz-P-_ z8rAZl%ImZ!+5eW+{mP%iZ+%QouE|fe9eTYbtSX6$CS#hG4p17q0`};d| zQH7$5?`tC}-r4s2ce??fWY#}BF7$Ei$A`OD-5$zIFiT9j19{I!7e;}}$zM8tDG^SV z@p_Z}y3G;)T0aHzuaN~l$&d~@fOukyaF<^6pt3+V8e4pkZlKKHwjBpwZPPsffBH`l zD+|aOBxmQ~d+6)v!sC6_xz7WfIm1Oqng1Rsu*gh^fb0Ksxu1DS(85a(h)&UmNyj3Nz9n}OxoT_RXX%;KHO|F<5%7rTr2oCVrWUQ?m#pbM9d zW~UnjuQKh#mHXuJ{J)t4|B}D>=i2}tmL26Yr4q8Cr$BCCseac92r|e~(;*wx*)kDE z%sHih{!{wytL!^fpWQ!@l70poPX}f8{rgq&rZo(B(soM_r4`TK^)O?RGCsHFhp!W! z-q_sJc8rQ}%K%1h)vCrmKKNqJ^A*A3F#i@>>-)9mQ=U)64@#CfQ1Zau{Bx1%HnkZyW^TlzPD2-qLc*}M2aXT^dd-; zYC$CQj`Rou0--2Uq$V~{5Hy4$RV9G*9#GnKRaj9$gQ0~IWdSLn2!s+K@5R;qzQ6e+ z;q%Gm-nlbp=A3!XbIx%}IB#g|439L`tlt*Sf^C=OOc#hfy!)6(Jnda5dN47u5=pmM zdG%)w93M{O^oue+1=L11(kto!dNG!{c=Jn-cAd5ff3_m3-}B(!&|20=ZN^ zxyQ0>+qf#Ej5|llgT#{o)Gf9Xa*{m(O?m%L&cC0x_PXp-pCAD}$qs=SK;mq7<2Y+H zmeRXd-a|`J!>1%Ig3SmG3L(glV@~8tYD?mU%^%z9G3WyPghK)ii zBESgtUpfDG3_oE01~;t7Lw`pg!93G~$G`P-8lp^L<#uu+s`~CNB{uNn&xp4wZsQt+U(}J5a>(d-K6>bw-)LPGpV6B(?;mgRDUc~>Vj>Da zdha%3Ya0h_!)_S1Iy|q6BXj61Sw`~Db z>0aVHy^3#g=$TG9DikWg(e6yOFxE~JqmS3foDgqr8Bj*w6~`8U0Ux5&*k=;`=7wg3 zRk_DJ02Fe|jJ$mr{kJ7n^ql}NCqxo%@xe$8WeNxFM-YmFKzcY9j=j&vu;+pxSz?w( zWaY2LvWNG)+1o-*C+_Y#e$T$!X5YswscCOAc8u2S?d{uEa4SY8)ZpAs(? z-?kX$cJkP5L)0_;(`Si>&r}bV%9z}Gc-!Xl(YX6EszNsV9;^1=mZ`^oP&;~Z;O*qt z`eN$Z=)(F!%lhNqA>T*?iPRM>-|9s$PQrIFv}bI3e$A=iEnvodVcmkA*RzuitN4BB z&1?%++P^6in%}TSg#vynhm?gRa>oZ+m&qhE4tVycEf7+kFed;l|=YMkIiUb(F zqC8;IN)1Uah{}GHvnW{mtnlNqrj@(&0BNU=IEU?k2H42882;BjAh;m>uixJzw0-ss zzKRj6Q45L40ZWor{3*6ifP*Ur?)Vd$=O6vTKUMg_*qI?EZy|KKP?sYtsCGxSl@SxAxTKGV{K5ab1tOqF zJ%wvy^=drJz3@};BaLmC@(J;4h4lKZsB4WEqPcO!fsnYTX!}gkZ+}mo#@<0bs2?>x zal@-wkQL@R zuO+x4i-e*N(3XT^cfF(E1$92Ylpdd!ad3^~!IlC~NmC0D?D`6H>fLWO`(*iObxPlk z?}{&~d;iJ-EHh9->-2`duDByY28+4h#vp)F?fYgXSRrmz#u^n$Y%BLVX6Gkcs z(k8Ka*R?BBZ4vYXy2tz+s2{z@UGlt8j?g*Cg>{vM@QEPK5vds%H7^^J;^{^c1)PB- z;KubUXQ_-+gv+2B>XZ8UYOVwbk z-1!(szkut7cFgu_-8xTp%}crTd@%nqlSyiVg|jQt1~zT}AZHTmmNfm)&Oa~-b^*o-)^8c+gN_+J{&M5?kK*2F z?7Fdy*V<)1amNRZaPP43`=Ey*A6O6cknwAu6=`v}s_A)yq|rkr+{-kgZWDg|(`DOD z)KoAYlF;)+=m>7;?kESgAM&pIQ3-4kG;^DZDn@p%6xya6hf0R9hg_hv{^<=1ji9!n zAX*7^`*~k+tH5%T&*w|j(Z4Z3smq< zy5$zo#Uplf218ZWEKu;{r9}f7fN5;VuA_ns9yC_Op^hWed!!KtD7q6#<`@T+>%G!W2veAM;j%*PhfveYAK z4X3=>r=rU!e_KfjS3h?YztVb4b_R(yu}u!^?N8A=?&m`Dz-QEq*1p3fo(VZM$+PHC zw7`O|e&_L}IywZ$ES^Knt9TbNy4OIzWXI8&Khg4NX4$5nN$Eo9(+V{rLZES_g3ein z+N?I#PQ`DmIMKkAfn~1I_0-{HojY}M%{S(7dNPv<(=d@<`2p+vbzZ;OXyGFKU+AGc z)pulL!;1$m+LG@U#^l@-mrY%>>%PA*WxtxYq);@!by_F?aZ~+9?*dI++6YAly-Nemk%=kzewCw(wc$iOl_7s#+ zj6h*NC0&d=jVi;usZ**+AyP2opI%>_;;ed#`18!Bj*oIT%Oqf3GUM1WKXadLo$InR zU&6rfuGDj*f462f6ht_{$9Ie95OJiq!iWkmHtnekKoP-yeY9>TWKD|c3Lv_Bsamu< z?&n8`ePx-OJ=fzoJPj^WdrhN~ZFtacq#(v3d=*A7BpfLYSKbQSS5{~@e5~!lDK~2O z7qj3%xZd{&xuPF{S=qgZ<0sp4qvTn|t;fcM7j>NpD?wLBGs-8+-=#n9E_0NxYVz}M z5pHg73E&~l-UyZMzI-~=Z^Z3NUaN}Spgx#~I$rD4Z5z5L4-G@R=}@f)+{23qDo$PA zB3kKa!rz-@e`@%4RTC@}(4}5rWzG=@x4Mr^zVV=ITZQ`Zo#dS3!Rs)6?(I%S=+bZ~ zAO*o|XF$+QTfOfq2ygqa z`V4kEW=FjO9lOLSCW{nDNjJ4$Re0=Ligkz|} zGdr2@)-XsB-Y|BquJfV?Adb@|83v%5RhcWE?7tU zb#Fe0rmVWH5KG$jtof>?jYGHi=d>i0Gam@b!2kxUEWM@U;VPwl!NA?zKmL!6D36}S zuj&~k6=z?>*HoztA{5V*R-6!wy#Is4E7$>Xp8KWTCErPluFozMxxe2F=e7mBO=i9u zh`mTox)t&_<6P>(+d)d?2bc8bxWpMjb9X4|xtze7?_7#E&N4#P5B*27*YzEXRJMaJ zwHVfS<6!_3A#Mrgnn<0Y22`339htU99k9yhjP^WbqF%6|dwxi@Vp&A%z@%@JCN<&A z=Hr6KkF~wV!*vN04Wj3O@c^z%u@5F~@nHIZz94R_3t~;@R1~(+qO z`6gu2WB%1}lG<`y5U)h~dnEmUD`G~!TXcFl%-a1&6TpY4G;ylDE?1-*C|_?}iMh9KPJd*LGGg1bN^}a!8TsxH>$3fPX*v%mH;;d5 zlJR!#;I6KeOG$*HnZ5W7&kzBK6r{;&Y+vvZmQ?rHhdk9`0SJR5f4(Y>9uMb)bDC}) z4IvScIb~(JgM+E=WIPb@@^JWJ+Gh=U@%7^QTD=j6Kwiyiy(z^JKjy~l+(bF?z9Oii zCZZy&@v3)U_x}m^ZrB@87jm%xUlDOTWL+&pesX$>N|LA?)_k&U5V8+sVML+i*N)C? zxYH^DkCqutzR6R|$0_uygi5`rfL*y=r>sqNMoc$LPH#ET$Nk+{js6lS+hDQI_ZUUb z7yC9``MfqcifmluMXlv}xTU34Lh-q>)P@QGuuGaFmgtC|{$V@PuM8{QM7?NL=#%qvb z?fDivO#v-beb{nmd~l`3i{JoT2lv2B(TG+qYI>Ng3ldVDt_zMY`Td(BcaW^=eeJ2W zQ1kNUr{T+{t7$}cOI5pQ>kddOS96<0ria8vXimU(Q`F9A0)H#d#}g|C=mn_o^xJJ- zqj+QO>>n+9@qJIbuqW^8KXY%PGL9(@^OfjUpV>4(TSSr820gH0GHHLgIq@}Lg2b_o zRPG)cPI>I%6;JM4M(%KL>_^_aJ1jgf)LwC@HWx^yLe%snMv^Y_Lc_hcSd0fMK~;g1 z8W_9O(S)o`{elw!*Vr$G>gC|TmU@QdQ4^a%uZ9N09Won&auzN?7ok-(u@Q$}Taeo9 z=@UsG(^%#zBLU11swm8Zo!601Q?1Iub;PVIH-yp3`SVauAh@ev`v=Wvgz*b>ii)@@1b= zM%ONHP5dFZ__K?qE*B2qGoDshw3GU34ej2QOF(;`ZKveeIC<((tFMPGg!nKusGNiP z*t+vQenrt(GA_O6 z|COsZ5M$6Z^<}bm?{+N)hi>2KF5AfCR7p<5P0D(oh@QPh^SbrN`&3z^d57jcFTNs2 z+2CD8SEK`Iu&%wne=BBm2fKpIb4mwN67_3#@bp-j-jBW1xEA_xZSeu&H6hwrRIhQA z&>(!HnJ!CNc9cD+xu!a+Y~uj*>lu{_FDZEU&MRUDOx-PuNzSCG*j+F(ywIGSjR)Pb zYToKhH++5-UZ4~2D2vRXrdP#tZ(Li`i@s~KyA?tmI6WkAfxJVRXci2yTGPr`|MS&_ z!S;6yDc}-d85kVIBw2J({*u6P`Zoo$E74!w&{U1}Y&E3_$+uXM9EOTFn~9c?Ly&R0 z)ZrIh7=wW5h;Fvs9g<_+s2lrDhY8m!(TeD+=u1?c!3BGY5H$_6$fdy1`j)YuWcmG^ zLgtWr$$f8rYC$>v&$~!!*KnNlqPGMtYDfC2GEED`gvS>l>Z-Uuu+Lv%j*Pt-J7=4lHP(J;16$Ya7EP(Qa%gw+V$L6H-Zi8h>lRITK!<`ZN~lKN zXb^JT3^OhZnznrSDp(L4wCUwHF2{ds*m+2-hIWA2nH%@lU$RFrHS(@KrW>qHXS+R8 zQx4g;B-?$vHy*hoGFT{goZ7<=T*6P4R2ap=&z*d66^ZO`!!5$7Cc{Gv_H!Zh#6+lL zB_p`yP-vydX{rV_O}4si)UBj^VnHsYmdKe(@fsD2k3t{6pSW8Sn@((k%0tSnb}ctg zg_sJUKoIa}i;@O4;`=cIc{2cBU04xLr7&)o?|`Ve-^osc$1ikuCkXhz-ReL%D#Dgg zh^a{4KD3n5*?kyQ0H30JX8B?yJRU^&sBddy%DWi6Owe*XHjwtx8#P_DPCmP<6KfVq1-MY>AYk3;q&37YR{2=M&2#a*?@t3 z?s-Kp8^j?(AhZY89>je0H1XJ8Z;evQ%DNs^)Api( z=!9tF6drdIi#;K~biVta_(DQ$8MVdaWyZ`sXr=A}G1sIp$`N-*J>7PnbeYd5@`p9x zq(!K{oS!XdJ_ka1;XTh^D(p{wZd3Fhz_jFTd;4j6NhtmUP*sy_k=ZOwcEvhQKXCvF%IK*c}LjhxnrJ%NA||OIsAX_n2vxL zuBOqcvM9){v*5|E2u%b$7nK9n+D8CXERKIW#_=>pfvvw4I*Ngd!r zH~*j8K$GXLL-;>e7O1ZL(@~nvkmy0gvNv-#AG&xdjrD)7ymfpJa?GWtVH>dq5KE{u zY_T!cPkLfDg?JAi$1cXZEwb^DenCgf;g<#Q^Xtv?bVZ1y5rpapbqv!^$;UUygm8dn z$a!klbuHpA%l6+dYh~~ODxbzU=TSq&Xpro_5Tg5kdf;`I1W8Q9kp!0@HP@tAzXkWF z^xn0Q15?7CektC3cyNe8u;4uS|NpB>1_(h)awOB&!?o}3J?-mR@*TiAkhj-nZK(X? zauOz3P59~qc92f*K!5gL0N8fZ-R0>TjJpQFl74kk_%aH7`d$-8S;^$ohio5i_W$GCf4BJazgt9>#kMI_Nug+e7NE|}!pvaYq`lOlbG5m#RYz2UTbcpJv#ILz2{HXA&bDj$IJ9uI+ zBvegYTP&*@e(Zd*31xA(6L11%@a=rLd@=I>iKB}1-efvI-rvl*(|*jaJkHhk7)^o7 z$?!@B`_JFY@R)5vD#8_bw~J5mpHH?hM?nVQIzIpFVA@^><#iyAj3?s-xVf#Xd6hWi z*3~#e!#7vfylG9Og2n4c`3ud{*=qP}ZquW+#Vvn{^qbQru+xSg-Z0+j%}3?YZMUMt zQHu+6FZlTj9}tlkgORC08z84F=KwU-R<5ztlj)3_z^+3Ny5#QOq<4^nR|0_yQvBep z!3^+39sicm*vME0{2O+2e%zpHhG~X>Fe8fr;lQjoFVgc%-Hz(RcdUOWB~dsGMATK1 zjiZj&K#JH{d8Cr?z2zgU9iO?%K}~ZOW6CXkot?|;c zRJ_7`QS4PvlGDMC{J39?9mB25){5{uPEECU%Yg7gJ2mrO?mLl5WXD*}%!+&_mtb82 zS#5o|UvCYL%inl#-Y=adv(fg^(tvpE3oHsxBE_2Kgtl|U01St7hx`l;xu0=0Y*Ifk z79Lb1NB76PW2~8vj=6Lk^W*Q{?Qc=H+%*-b5v+02RM`=`C=gjsFL8OZ2B|UW8%%N> z*fH^tVwE>H)y7)cGM#~3Qg2$r{u<3EvrB2fqcsywJc(VyPh|HG5D4mufa_oE&;j&G z!Ha<(ZqdqtxIErpD+T;A$_J;Ho39IA&6!cRW2mlDe;j1}t=k<`0CQgmgg|6nKrlLxYw2{hIPbBm~5rfef{at z5MO(bc(JU5TBR@Bv?kRjql|@6RwMboWnD1aYqd1?!FwILr zN_sY=sU6wS^A6i~4}2NOlWU{nD?xK4vE1hBk4>)mDxpkmrKW;w^(sGx`9du?^NS_Q z2LcUbXQF6cz+zeLAqW^AWIGpCLZ1j2@JOk%fAy+SKa;xPFS#Q|ZDOeRpZOt3yF#rF z*M9g*%s`2{(HW+VO{ARzcpkiCNom3tD@NU+7vUEVeV^;@K6ZTOIKBs#4+S$FW)ag6 zZEbzE=M9sutynoc8b9VYxrOt87H3*qou6PM7e7<1;=rlF9#n|P%X53sbT%g-1wO?- z1{>)=-;u9X|1$h_F$W#5_qPv+D_#t;vLXWTh;$y0+TftwFR zNi6^9gH+9?83T;nK?`YUCPdykKe)e$;L&bI9uenOmIRlL9)-b)Lt^0|5%{CaT%FQV zFf}6V|v<$UR;Xo_D7B}dPo>#2WdCOpy#dUD>5Y${G7CW7QsK&V%yz|?e-MaV; z{Hg;=qR>u3t0_E&pC*d8$XInj1z*vQkE20QCC1wA!x~Q~FxBXm(Q)?wsT#L#AyAth zN-OKFzW#aoB%ng#t8N_S9Z~Y*LASlyuLNesqFPK1;KSMa*?LNO1I=$JxtI6HD$z#q zM;dm}m9ffHOG>BCS#qWf1*$aj?WI8)m{HxGHmm<;R~f~6f`GbmRu~N_l>~{JAa4y} znYdmJq`Dc$u2Cs^Np8utZ&Mkn31d~Y=abDZzK6M(4mUTg`wHhgxHdjIb2{oY7Sl@& z?BzdAHbhrN*(b@NCQF54r=MZUYn7Hby1kbFTymtjkQOEIPkw7xPeWr+Y**j<5x8zu zG3@jCvJf+)iYa;*D(k?x;x0S%xOTSh93YK7x914Zv36LDFPs^1n0T=GDopxwhrjKE zK!^~#Qc$fuXv7AAl(X}sUO(+!SIXEzqrYm%OS((6aIb-Eb#%*W4a@iht}1QwZrUAe zhgHS4-fu3zb?rpxY8>q{YL41|o;*dUl+ZWa6tC1two#c~p{Up%Nv*^sAru3mXFuIJ z@_RB~I|)D}wS!f?t9=lPJi2Z!JQ_MnF(t5oF2;LcX7oDqMCk^1~;30Zv3)nvK+E9O?n(&U+~9`^C#UXr>JHJ!$h| z4`VGaMFrd!9yZhvy~^sotuc78P4I!WOM@%e#r`fr16Pp=utuR5A$DBJ-1lI35{D2+ z(8B95==1JPgZ&kd?b@Wcbr=&SZJhmSVD3COJ1WOi+nu}&Xaj9P3AO{SW9(e^)-MwV zroVkeJik{emIsw!O@jRmO7^d|oNWh5{COW0eK5zKu z;bT~?{0zmJdKqm>P4f?|R$bY@EiGGpY#sHo$v>yupE|;r7uxihAOolVFn{bAY;2=^6TGO&0x7_OSHHiSgQwCzwMu>>)N3 z23trj@p!;ac>So>F08UiD^b{t58m`82uyf;ug<%(k239}1J!{?L*#An&5P_x&+IrN z8{eM#{T?btpzGH&a^pmZh<76^kHD2~X;lVqCHdQuuK}qt!Q1V;7j103f+yxM5?X{a zeAqkM;=pOVn&aA}E^sn087XN*RL5zmH?|o+eqKf8Xf7GEGKa+3k;@3ED4DdaOltnf zt$_HKZ?n>{JczbK7YTKa+mj@ZinSYDprc_HxM{yaC>uA`YYxi9NRX#Ko%tf?WbXp4 zc%6*mE_iBp>^U=nKF7yxn9SdHiKz^DyqxW8Wj~!BvQjwvdwohiGX;%GVGaz7GqQsi zhI=cMrcl6P!B&;o;Gm9Mk)X}bHY@|*fO8aj%Uz9Guxye>jlt5`EaL}|Zys%#DvbAG zXTaMps_&d5UnMZV=w3a<{~1qr$-3$t(h|p-|8}u}WCr zm3rdnj@e)Yt?uAk;m6ylDbMlt4$lxVyH6hxkI(E7409b{YPH>{C@K#;@t<A@b(={lO<<{u3mthYS_ z!ar}8B>m)RXj&>@1RO$Edf1N)!nGdT40n`NWi;HSGdc8!e`_(}dq1tEp?sqow<6Ux z6;4|0YJNB{Z%rkmiGS1_@c!Y^r~#*%ZspT6bp&0(CCDxB0voT7tspKF-t-(mRC~?$55%{56I-40ah8 z?GXbaKiJ`9{RtdseS1QZ3+?v(#jrzBZIDna`xyUA0kjr^;@KlX+8VW6iI+^sQ(%2+ zMtxgw$;7>1xBvX}F!TjH^nRKe>?A2mbfYlW4TKj{;Sm_N3?b-f8Of7Zx?+)HJ^TV z9~{ZAoeVYVbi8t3u;?=8dsu(|?04xpK5(28gs6f<0* z`Pc9ZuYm&e`t1eWx<+H5bF6;(mX_#6!Da`tSYuo$G&=m`?kt#lvvK(N+LPI>FnOqG z_@M^kEt&F;YK|VZ-7m%Cb$|__uA1H%B^q*aa{Y%1n&rP8RnP>2P4nW^NLL@uAdo?_ z@J(C^V-U!cCTJR^l6DSKEhDt6K!~Q2URj<~ApVNN4X&JLa0DH+tc2+Gro&F;t9VkT z+Ef1m4>BL(qsHoIBOS^=ENj9$*4%6tp6xg1=G-wC$eWOea?tK;N=>_dtmgPqy?aXI z32)ZNLXc^s4{Oa)lA5AEY7hi#HPz8sVSTXyG;XSL#OLV*Ksj*H_CdUMNE7jR;JEGD z4Y7;k;d)~e<*}F6pN@3w4Uq7SF-zI$cn@1O5!6Q_eJ&l>nrj z+BuK@>8nT^=3^ceHC7=ga;4B`}P3gqo_^=&`S&@7BY9 zB8KPZP`@59z(&hZPX!td-7Q;Q_NBcNn%);#v=t?Jf+x~fij|NGt~z7%tpzETXx)FV z5$+67eSQs6LM2(nIh4S1AO*x=K?sDGSg~c$wiRx~&2+1Mx4Y!x~ zM+DI9sJ7+Qdf3P4MkNTC4pw{JzH1o2YGD$FGmnmz-rHn7zYp$a64!7mIB!frzn0Vt zze$~ceJ1uKvJC_{KXBzLmtMuhQk8k5mOk6qQ@&oNsiDJCzq3@qJe5@8P*nH$-FXMHr*rFQR0Odifs2GQCT$AWL%%{s$;q1|< zJOicq0$Y?oYm{Os0#N`yWn6|xjx9;2%qU?sry%+P@$K*iTm#shjy2227HoF{?3f%vz5&p|-m zBwmWHBU(ZoQ7=ar^tB0mwxgteFta_*^;)}-*Y0~p8mao>b%~I>L8uThn zPCS0gP&D7^hj$LOKj~*&MJEVlGVjpeXZOU57m0K_1Cg|9pf}KR_I0e&y*dgwyqs8D z%(#_!w84^j_wC8K@&I+Yz-=<)EhSc;sNM0^8$22-2fgfnN$8q@Np>EkRwElx+52*N zT)mhrc}a5r4)5OQFt`_SABwP&`Z2q}mS3$o2p%hr0NJOHL(!@sJRuH!o4qE^pBZYj zpeLh-6K;wrqtKX=w^<#WjEeR#whfIX(e6d^Yruh|92}Z=mj%((&>U_zA^QO9vgIc& zp>ZQ$0uOiZjMi*DZ-H!F(;P^t4G`~kIQY?^Z;_n@V>}O9o&t^>g6Xk)i9+`)iCeCkj5lt$i$YG;o|vVf15`vXzwS`a+pU(#irf+&^^Q#N^t! zme5|v@L1-fDidr-%c7(DqgLd}jKbY&x^46c#(uMcHyq7nH`19h5pt8Y0lPQGVOo{L zRnNYf6BIQWi?5oS2K9?ZU-^@lxM{jnk7{x4(hJtTTK#2!C5~^Xz0zO*JXskx1TB*j zF0tFmWS^RoZ12N#IB>X;(}8rn#dlNho8LRi%HB2MkTUlqJ4mr-eGBh*=g7P}+Y4cu z3^(~5$Q6d*JE1K$cy8aPnDx-};P1aBJMqyTUsfeIhDWO|Y2pA>USrhVlsxpYi0(32 zP={xJon^p*izW~)o{bdZ&}`Zm!TyJf`kLPU!TRidtYCv`=8^99Z!PPgVloC2Oo|i> zTC+ogBtM{2k>*gL5<8B2$Ls>*uW@-t-}SI%WP{~DD@ds`S3+=fPNX7tD|F*_-_vtQ1r;Oe6QHw4WckN+>}{Cc$?&zw~K`i^1<**D!hi9#VYi4EZME+N!8Y z_JPQ!e)igwH;dtop$yI=erCI-*;K{~W#FS%a^d``@pAl1;T<}dT8bTW+W!1ma(HOxCDthU@euGFH#X;nCSpL($wZrcm|B* zh&n9*xeKMH!c!e7&bx{;IwXmOh1TzfQKmNdqOp?>(sjt#v>(HL>7;kjc#Xs5)hoYu zNq(LQ?L7@QIRQ{e1#pX!dA{)s;t*CD((yc~m+y+U!d&=o;KIXB z4G2$VH%oIKULifRBxpa$c==F`%$pRNmq0vn>HRK;E-a5@{yCHcs{G#?hrs4X%A|DJM?{6}IyB7(KSr78;DeR`cs!W*$bBz)P&+s(j%2 z94T{#y7q#PBCdZMj#cAn{>*5w;1q}@=`KNO*0jSW>=~oTN`Gd0ijl@DqdxYurH-k# zz~I$C{yQ`z3afx-E5A5cP@<@n8H4XHG`ksNOD-ZwH=YXgjdJAORigb}>nbwHI0w3x zV$8_rir&S~d?OUf%GVf-Pi^!8l_Wm8XR;19qTe$TMedbhwiN7-IUHHa`IRM_CFge! zs&J}(--$bQi`ySb9eR6|XX7aG8lIx+v{wgk=%d&H8B_sJSgBAoUzc1^D4)Z~jQ zod{?PYPf@Rr&|k5+SY9(jS6PVXo|hGa~UP^1mUEodgAE?Z{3jR^wF=4i|@>V1l)lZ zZI%Ca>t}lht${(^rQz8x>6AyryN4S=kiZ1aQ=+UDn|*&i;f+p~2( zvz3)+Nfg_$T`AvcpLbo;fk%?~23lZRM86T!aubN2!`o}>H5wr?65qc2kMzQtj9-3Y zc*E7hSBG1$@x$$000V*QvXN>`$ffr^kGp_~#n+j?V>6jdG7T(n6+c*X?M?dwe<4cm zdexfX2Yh%5<{n5je^gADDyu~G*Tmka4CF_9Q7`llYjA21?euQ&Zrq{kMBP}AgJU?h z&yyErDR6y@&6XvabH^#{IGFhie;W>_X*fkQB{6^GehQ{|wHwr2uG|zvAEH{KqBLuy zC&QpLACPnjvYMAIXi31F>^ciW?U1;+)Y2E3E81(xXYJnm-+)O*U3Oh}la%Brpc@S7 zzh%e*EUYNTva-9^;F#Zn^LjP(!eCruzs7+RXUOgpL+Ulaw_K2*GU`W&EjB=*IKJcQ z<+5oT)V1ZP0UJ3T%t+VDoCS;IT^PkbKajPo*ic6MS=8#whKt$g545_YwoaC?@D}G#}b9c+xHi2%cW~r%#^JMJAx$1j@Q_eK305s*Rh8rldNN zSjZV(kXNC}SZWA{6G^`kUkr;eVdp?F-!Oubi~4G zlO=(EU1oy%Egy!4se3L)qoirs$tQ)PYkHk7Vmi;wnPyb>LH)a`Psh^&#(3txfT+HZ z$@zpEFST~gpee%_N2{Exw(|OmV?}CENsL2&&O5+v*xzzw`J zvhl-dGM+$T<%A7H5d3wgQU`Y(`f5|{VN8luNX&NepuZ{S@Rg58q~%gDMD~^@As>baGxs1_D<15{ z;Z*tGd)+fBP&e@Nw?)8fL~a#8YP7rsA{)=NTj#_Ag0 zy%e#W>iLs+>B)RJJ9iF|ccC;R#IEq1`X(zH4Mp$BJ*tq8u#J<5So9ct-Cckk(iVSn z#Tz_FRYL;GFf*7tQ5r<@%wH?)bCDpDEYK03I72Tng+RcNa~TiLT^akt*7 zgSA!nv+t6pMEFd#VS|UVo^FA?i${hK=sR0icWS2$2===`KpLyWAy9M`{X?R=x10EA zH`K$CN|NNbM?a1`?joLc9kK*6;u6%J|F)ZjDSP(B&YC%mxg$0q9;@36q;B1yCw?D} zBkVkH;+%pWfyZ%emx1*c1wr0=Dz&}oWt-p$>7`!%6lt0l;oXk;%kM7@CRM5nm_o&w zJL4V70}@Gywnufy*Wna87vM)Im`)waA9?Zp_rQQ^%K>!UJnIlzq%}^@&>D|--uAzC zT@%#-S%75-dm&35+1r(8WKAY-Edx@GVkvmE!UI zk%5xKj8J?#PleT7JztG*O(9V{fIi+7>ngE0ZmgF6L)ao9bX&H&cfONCXUBRBwpYB| z;X)q=t*u4-A|C8qV6dLnvHwU$hTISKm;>>2p4P{81#4C>IkaLDs}HMWv>6ZWpcTw_ zy_mlElp?cM_;$Iw(ilS?FH~)yM3P8v!1P&_!$E_)aP?h|EMiHb2e@APxk@OiLh?q-19$2ueb7Oe76K7K2R{$ge-Ho(p zXZ1_16oSwOIMH`C!^V+&-;b-Uq+WoD5pMUX)V~YPf3pQAXuzitd2j~;ElYzsjznhC-)oCHz4?GJhm5`b zfQo@larCgeAD(T#dk^W{z?HQxm%UZD;p^(4R(A&bK^<}9e_zNjVsG&HRbtF9ZM5?1 z|HRcLJwI$IEUE8>F?04nQrN*OUZ>C<5qW$ut($*@NYo?;_Qp(oceFRyxNcjI>%t;2 z9onnbVU}b`;8tGBF9*#t={mgfPvO4XQi+qsy5LN)ZGo&O_F&QoUT-vipjh{6?1Ctp zn6`s7OFqFGzkiNROy5=dH@(Sd&)1e1SKghgr12&*_6y_UsE#^_>3m6BHKOVIjO_Pb zo?RKkk9kE;7l-O|iXEG=0}aJsvFt0y!OD*|U`7ECIEk&Q*lf38Xy|Y4_Y4sJg@8rm z;UoLRxO0a;1HTrY(W5=t?l5*1-w>}{UlB7)Lst4Q8OPd#z!BnxQd#&0y%X&-pSA&8 zpu;7XbYh7$KN^vH+5U0o^7zTuC;s8SiGRg@9?8XFb@dhGKGwv_!5RwY_?zOEIVxXw zv~GW*jLcv6*$$sReg2Pkk}@<&nKP>R3GRdWI};;!v$JROs}{;$Qbv2%S4u7IN27aR z1g~AUA1__WU(Y=-0?j=>BLPIm8lrU|WE?##Cx zQgE40@h`bt{(0ngj{d}a6^}g+W?JIw4_N?z`wpc#ral>hlRD&PPNRLn#8j6+hEYr} zaW3&e3oifrUNR-m7dC()==#Dm+SxjD=Nuks~OBAmnS=O9d*GZ>h<>UaQ-Ex zAvFiG2@@XQG1|NL2ryASu&wK_E(vim7W2Q}wFj~|)I z0(C$2jl<+S`_sphu;r(v{a2`&Az2WC zfap*$Lyq6eUefcn6a~anZWHeyc7!9vB3;Q(&6!P)u7@bTI&Y}ch!tKQ03lwCavR^c) z;S|6l7PYJ`sjem#S;GTTk=!_SEXetn_XhmmW+c0J@aE%%W^lTjIMqj3qimsww%e*Y zYk6yT4)HJNj$&V93ee0_+ym0|VEaC>)J5aVo1(Z$91~-}VO6Q#eqiY+k_-Jv`&QD! zh6bWwPB1V`P-T5of^f$WU+%yo?O(5$NBz0wI+Y1>2wwxZ|MPHDa6d8_6dI&3#3?JO zXG^&u+fXf@$XIibair$VsTEw4N9xUNs3IacIVj8#4BBLZgIbTE!?u+}c$en1VM)(j z4^)_x3VgW&MH{WWBC*&oqqmxeH3qLi@C;bH#s3ET85|^Zo8cXbKg?2vBVijnAtvg! zN|HuFSJCXE(u;vNk7^#B+QWB z6$Q`+YD}wLm4)Uwa+$2?1SxEsthr6p9NrxTjHoA(bTg*~F!fR&iV(4jw3R zvc{S$1n`HktJ{1;K?uE6_}{d6Ll5D%VOCw$@BW<&7?{0i9@4t6`Hrdvvm~l;HXaPm z<3O=ETtAF>8%4m~x#t~Ct@tP2=gw;IQG4w?9$rW`#kcPh(=B*iCH`!upTwE>Xv{}} z31jKqzZhN<>m%(s;{|efpAaM@KCH{UyBXWdsK<{%b*Y}?W+)w)LGgLKgQ4#7#v!j8-bC6JKmhnFj8o+aeBcaqSihy-`d{qQ%oVSHAg0`Jr5*3? z&&<&F6p;sqR`-Gp2de{;3sKpT z`=3m*GHD71{y@%L5PqL5m;bf1?nDh*@O`rdq$XB3BxdyLbv*rj!l35CEZ?>tiSA__ zT@iu9j0kjZl%zOi0842IQc+UCY^~HM@I)!r~Ab{-e@hGg8VNqFy}7Oi=#Wh z)ETQYjE;cH|s%FMAtU>p;a7gsEhl8&00Q;FgR8t8_iX>nqQE#5?bWC@Iy( z25_*vZstHgROuuNZOvpW{G3(KXTuy>+%X>+Z%GoQ*kbx9#^7Q^$c~aAWGdLJyLaZV zm+*VSUHa@|JR`{k^hu1K316_bKLWeoIc_ zi(HX>OE#!@s1h`eZ~GOaW0o7Fo&9Q3L`VDej%xM$Dq#HEN)sl`z@h!`RN+vJC8z#T zzxCP8c^n<@@Z|Chp6?~9Px)1r#ZDhq2==~ea+u};(P1b&v#!}uTS7s=++{h?YPdce zOp~Nxau#sxw6cNY8PIT;59|;mVJM$c!-@v}A5-5Q)>PJgoe+vh6Ht0lnxG)PNfSXJ z1Vnn5C>;_(q}OC{01L&?L=Y?>(tGG6ib@mFC@rBx0TD2Olu!cXyQuU2zWayIJTvo{ zd(S=R?!DJuYwcWwfs1X*{~!hB7WA+2_f&Co7NHP_&I?j}seU&FK-+$zU(u70sz|G# zmcg>KT`5OMG~(5|U(6i>T4^d{v5d8jRfcI-)CJ-NgSCUzgIQ{2R&C$`sZX0O5p)1w zq-5&@_bG6Jje?vi`7!>k`fdLI{o=Z&(#_K|4U)jy-)ZN3Xq3ls_}>5%#y*Tb`@}^- zsp(?#W05W2Kbja5s9E=kpXCIx;!HW%&Q^*}AV;;HjS($nSrD zw=%n<mr2cE zL`MAF8GdpUup-#@xK=HpBr})VkzQg0XmuN(8IYHVL`y^eN6#>R;}p!P#HQs$;5!qZ zqgLf|{(KVfBwxoL+c0lc;JfkDD0h_lBKu)uD;h?)C+!XbdR9)^`txA_T<*n%||4;xR9M z+sY2>^H(d@*PZf+=S-yN0G6S#Jdvua0^XM6wgDW6J2)D70?tH^hR-aH`~;+}jg&$Y zjfAF=V;N@qhu5E7Lc{U5C(Q0w~;jN;GAM3vqyKga*zf z#>e(1#l5F`V@CW$_JYPVGZ<^xf?Zdh|HrxqXdv}*tlkR*Ki~s?cn)M_Nn22tkV?C= z0_R9p>~$;tqO_|agN;3`VbpA|X$>jBEfz2C7LxMinP3!a#+;l`cPEX-OE6OalK*YPHXgiXxV zFRQWj#ggb!bdMCp(IZq+(m%%h4xJ6~x+H;;ArY|ijpm&HWmEv=BEkkhq=0;H8w*Jb zBx(q6S5lUws~9F^7gVuDl(D0I$?+q1XSnJU`0c#~-%J1iG|`t3HvC9v*t}w^jV~OG>R%CkXg%%K=dA zvF&mS4LNO|r%k82JQL2_0`;hI9YDsqSjGg$ObOTZ(t!=ZEWL0EV;3Rv_l$VD|5@*( z6&3R1RAB_Y;p;*vdL3yn{Q0HH4Ni^|Po=7WL%xmdRvu#T^uOREO@8qz+yTn*8J!)& zXAP7cP{MICv-xJ;t2AwM0@AWsk?Z-&B`Nn)3)IE%isB|6!GymX$e@o0NLAD^4vc(4 z-!h~tW*o%7JzT)9EWw=sZvHPl@^xUmdnRfL<&1~PExiw7L0G$nQfR8Rjm29KN1#Ny z+^qNf>%&wuZkT&QwxeoSSnc7Z7(VFzH!)JkkJo8l{TSiFtK)N#63=K?xpc>}>_!m= zrc*;hkI{9EU9 z&X31mAOxZ(gxyi z%ULZfw`4!AzbblI6H`G0*ev0C#8*xd=l##@;I{SkkvI2l@crm+L5vPc$U@@f$@Ev>52m$&pGQmLO zhX({g7%;@Px1~m56O48`L=p7-Xn_we$Gh%h?sIz%ox)Rei%yRD-8BFA?kkM77~^Hi zWhd_E8i_UvGR#|?a7VZxJON(Fh>{TpUvAikZ|>+G=t`wjGbtN9)zBUF5 z?9nllnRX#BPF0)RUV zsZbo2c&7ucU?}~yH|=NL|Mmm3zMQ`($s-`3LBCc3pi7YVxU&>L`a<}@9<`Iy+{xkG zF&yIywKw$vo7>OrC?m%Q(D$IV`bdwf3-R_L#+OO~Ch%SUpE zTySO^#qV>(#b&NC?QW4cig$TpJPPUG+O>0ZlKi>^O7@oR%%M|rsAdLJ>odOt8Jy-~ zUh*6rAg(z+)ewDP4tFNaYpU&Nt)Jsw4S^>v{_4j|VAT2-jUsHTONniq_4}^S_A9{P z`u(~^)&Ku4^{l1AYUfyjJ!cM*UeRlS%0#Aq@!q1r{U-}I0h`Nq6bI6SWhm}u*9X~e zt&NXoq>)z8i`z{Ug>vLP*Z>>XZ}yuh%KFvWd}j~5Qp*0Li0h=ky1Du@549#5e{Eqg zNe;3BjD@$O_+B}~-dNHm6S#E#ddTiye+F8?LZ2nfvkT@r;85eD*QH^1+d`aeVm z(Kw-WpBNw8&otQ+Nt{e#HHC^-o1%;fk0kGy5?<>jSYjE6JTf1v|0C6>4j^FkD5=9u zb9k};zVT9oI0=Zz(%!*qn)p$KxNA@-_hzOV>$d3Jz|uPUwA|9y>Z2B!jm;F>{6~U? z`DNkOMjrRB^wSfG|GAZ+&WhnOrje&sp%zjrChZS| z#p@Fpjk0qqBmyRfsrvbQ-2@>gSHch?q56YBj|3@QL${FiJ%UI#uJFNIkTlg1F_ljT zJ=Zk^UBW~+bj&wV>yZcN{p`u?P@2Q2UUw63?fKe>-<$vNIT{azkDqQ~)BOdU7{`XF z%3<%0e=@ylDK|$KBHa>-Fl*!67Wh~I3O?%nJ+2`Se;Qe&{@O{SB(|?JiQ;To2Xxp3 zxBV-Uuq#YyOljF_Wjjq94>+Xa;8}5%9DALRx{Z4!sJ^Vt)Si3lXjjwmp1_wFq=dv7 zTiK#K&&{$MOT2ldPc5n?kjr$+U^%P7gvv)kf!W#TDown{rOI8y=u-KIy22 z@w0*+39f$ti)U7c#%2N6Xns&G$Ml4&5xT%3(+B8|>X>ul0$RC1WQisherLw6yi9ZE zh{%8VE4JGG0^q-)RB z?#u2zG%gEOO10sO)QwbDI??iU`NDZW;ePoKz9!>Vm|=Gpt+C_-iL;0n03bw_ixUrS7drxSR8!EjxS@Q6*{*!BZf$XKyX+`u zAcG@VJb-&ZBFi~4-?47*3)NH#>Gn26Bsj9YE;NxcAUH`j!0sd-csW_!v0&j(SD?Mr1%IN}WdBg{N55=<@PpzJXCsBgfe`ap%lq3H< zrLp7TE0TCNGzN%H+@XrhSB>T75*|}Z0eq@!F+K_oB@bcvn8O)?23w2un-I0&#^NTF zy=@B! zU-;b8&32EjUV=a14!_xVWGF_twuCY+sk>6E=9XE-QEAc2*%qD>sDdy!weUD=>4nK@ z<$B})=;+wP*CFxDYP^f7#akfxoS}0>E{-fp@^~bZX^MaGy;sB?oA~V0nZM zi@x*E--I{kZ~n}lUc4#&Sfh8jN$NLh#Y*M}@+@q2+p&Q*%m*>Atwqbaf}@p=$e3%T zo`?53)u6|_?QU6`z|ivI#VyGN??iVNDA9iD zDNP918xMp#kCyBq8t$Q*L6AV~G&90^5_FKPa>M}R#K-iaajZ#YJqOFQtyk-ABp+dY z2Gr3N9j_MLZ+87o${i>{1)snGc=K@-XxZ%m4YD$KbhCBN$;Ipid>&SuLcNpJ!s+rD z*b0ECAeLi{#fe$Vo=}a~lp8fR4O0MITYq2XzZ2%&AqD(h{QVbz)HFVOtaRgCyJ5_W7=h3rQ1 z1)CAm*VcC$DV}WtzJK=In_Kmahrlm=T(E^}yO#1V^9_7H+BHUGAO_uzPFH`s7ELbF z1H^|ih5J$Qs|i4`n~xSZH@3L2!nDk!PyF@>p*3o#ii!hJpg*hF`F9oHQCBK>>H%qy z#?Q7~72c}cI=6HF!sN4fE}`&AF1P6cCy8e>d@Nn(7QVJY1m9f8J1AgI-90u}EN;av5AM`Y2SL2tZlWwM$}TBA?|l6KB>2dU59; zd>tmOx-emi8qszl=+DzJ{@JLC<6X?#=`WB85bDcQIXIAxI^q+D|mjO3{04z})my1_ykwJujx zztJwZ4Zr7Ul@TiT#ITL#I4^l9IR>tWu764$37L~5mSNHEJu|?I$!gt)>_k!xJR-N- zvw{rrh&VQrTD*_mUrh6qZ-`5nRQ~%y-i!ojSpNBEgE6jc+zVtbBzg20?9aaf{+xy} z{XwsOz_3AO_BMXMs|*yQ=Yw^B&4QmPU|xU}D;GA{Ah6-zU5`Ki!|#J~ z_`W~!0WfCV5iJ3y5Jq=-7Tu%o0~#hn$*1w^l3M?5v6la-$$!W}mu!7*aw!F8BS(+h zIGVX6t7siKlB@uLu5?_VLklT|l%C}57^Yf^a{OiJUjOI6)`T$^^bw;7gDx_L{-}FF z8+wny;QBHnFu?(d@)+f@W3i`qO*2lh$sf^Wu9R31B1>X}UaEE--Y{?pO#in4pCpIL zt2gn?_}7@6#?GL@YnxdBV3W#R2y@A_`LMr6{AaN;4y6euF(hD-(0kw*$h^5rH}$8> zf3G*?W}waFZzaQhbqrtb#^W|1xvMMjUrjhmPQ|-QiCztaZ_=#Dr)ORoALsxDhlgfu zF`9B3DSlL!4Pg@)`sbiwv*cD9(zsA#Dp`; zjO(`&BaW_ekTk=0J3!cUaN2^&^o(^AH9)H|P)TxVY{ytTK z4X9dOI$8LNcbkEcL#u*tTi^r;c>ed;DgXj}cm#G+DcaaA$Oi^0;$|;9JUZz4B0JO- zdft|hhc89fI1CK|V@yWK`l691P{k$avnYF%sT^J3Agj?e?(19Q(GO%gh{ScJ|4ESj z;9ap52L`IR+3Z67zi7oxvaZ=~5LA;RLGSfabRDEbbfGQb)j&}iLqyewL~n)8-9e`3Fxd1)M{-BYGhsVZK3P;xHB60Y8Aal z!W;fYGfC}7W_(Wvv#|SSbn*)^(>+)aEb_AcZ(nrF*p}Nj?z+V(Dp~UE+pu0BJbRC0 zq%q(tcSJt_uz|BcS-|`Z-Ew`ni^BVw=Z}uT2-cE_=` zKvqor>Bh81N0c*ti%7|rTh^D)EV=w-Y`wj44$WKY!H;WAxLV_5u7+Oc|mSa{|ktIvC&b~ zTe%;#C_?642S#AwlkM79R$S$vf-Ftr)yQE4m8HBmeINZ8-Hq-(Y=y3;D|4xaN_-W> zDnc?sS!=`jJ)@qqtt1E5|M~c&aQ}TGPR1LhZ{=^n{mCcWrVnHi6r|tQf5sz)-+GYe^oR)(L0`1C>egd=au&|Bk;Pt6#(hi5630-ho zM3<|jB{iI6o0I5gul-YaWRw}~ah{&e^5BsD9MN;yHY>p{vg`H>MF1|G81Pqti zCP}K~;Za;hu;^}_) zn};^iQ3Z?zQvQbh7Y0sjny6pb0iShf<_EEgE8WlgBdi|7vVV88Az)rD{M+?cCp7VJ5OxUxcR!)QLuAB2?|NT6w9 zujyt~1Q?ik1Pq~JPGvEBbkuF65qYA24G18UQ^Z&XfN}#Q&*5WYTA-HDS;fEFsFNoS zU!G(VV(@=lfbWNb(|l_l@KvBbdbf{xVLK?3nj%mGVDkqoW1PabTQI^Zig|At zumIXo=G72D$QO}XKV)KyW~%5}0s)rPm6UwB8t(v>q2Zr8S)&o&o3Svm899I)3pJ>X z3*;XXS9bf1S}}Jie|r5L9)CbW*VyOtG4egzyMcT9w6omxc_02cwpo1fjlIpQ9sFrT z(U;n|x7=Mhf4&4Si~odtHmo@F6xYPm^({TTW3ji`k=c#7V zY`{R692T@xODu&H~V(!J#m&UP7$I{ z`-5%8exV;+=DUzp**V`PkyUYQ(Sjj+XQ+Vm(;0bq^kAJa?E{E2x3QSgQ@%zgG0@b- z{b-Ju1BO`id@hThw;>b)0|~Tzr1EmmMqk7-PmDcq{41Be^(PSlB5h*`&uae*B(oR< z`{T_8EYP0O#tS2cB34^m#P_bkr5e)H!TOi;{+(9G7BNmq_(zea(b8x-b9J3wL;n1- zI@I6^Z9vnQ{}8IjtAI{31YMh2qo-1ts&hhhKbE`E|H<-J($@|?+Rr26s3y`Ny9)Pw zdj#k*1-(q8=TQ<;_w4_+(Gi)8|JgR}5?J4N=ICWP?-TZk^rpDCk-~d51*{#_%O|gYVa@@g0H^aJPa2=O%3w2#_N+76n&fKN z45-zfEj(mFXG>f9k71dC`A96aTSu-QB7(qW_g~)3yn?A&YUkTf#mQ&LIg16QkRqRL*oimC5JlbV2J-^#A3z80griw&^h6nu z9Vg>eSXuBV4N?S{3zV;c(3zwHn8L={$rdk4tEOx(Q@z?SG`lGl98!r79 zmLB2V@$BT|q^+$zCS#BC9B>PR*3s>rV{>$tw1kTUess6#O=1Ij3zD1mEd9^s^gHD| z4BStg8Q{Ijg1#ixX=P*8f5OywLlUYO5UpS4!lvJ5@m2#5Lv6uaS|M>jV7t`4UWUJj zw|!1&f0c*1dPPqkZSyS_-;A<6A6Z@aGM<{iaMh~pQE+RqWksAV`c_2@;GQOKm+r_k z0uE=^s1VbXG2X~3mcxVtB%AQuMudAEdvdX~toK5x8L{fCukIAPJVXgMPKR7(6cc>A z!^sq$5n5a94U($5xHBoX$s_q^0eKJ2PJra~e(|XFh}(gX(!Xm=OTcvSO7+^5lwH7# z;~3DgxAsXBa|kkfEbSi%b>*x}h=S_Ch$UaKZPr*<{ zF4Im~fYUNV9~7%r+ycyzaVFzIs`guKpr8kh_V?mE`#cIry?$(En&Hi zVvAVem@p~(wrWjk4wpCyO7op!%W9*#v)eFu|R>e?eq9LFk{+hd2{(DPQwuJ*<)s8pPK>ypK7xDhDr`O6KLZZbza3M+Z&>`<~dg-(zst zt9kVEo<*oo5z=8yP{H~RmacfByyXIKKm-Kp-$cxHX1!`P$wUR2?bcE9x_@|z zVM}4r(yQOgai-{XQ-Y)L0b?wT@XlS|O0)CmHne-44b3%rd;oPz7IwzX1gi9Kx}Jf~ zS_y=;Gv26uN73{f8&np)AR<;`X7$l~Kx~+l__N)e5a@!y9gPh8jHO9evB-~yZg*Gh zGGWWkv~_@5O0F%W{n?iSPY^6fcdjYnOU`FVYrVSMR(?W z@m{Pe)g~vVBT^^0jM5|ZSb8BJ@Wc2?4&YeRLpM7N0fXuouDXeaR2T0fHFLffO8B3G zn^Z6+8nQQWZnQY>a?_b?XxBG!*b{2cGr9YT%c=TR%4JQCki zly2d~jaz+w6r&H8y|?K(l!qVIp(2CJAhDmXwM_$V_78PLwH~pht2>w8AKv;~#j+oY z(|~Wr8)_T|klHqn?Yjf{@OglQdVVbas8;2&Ru*Ml#`cC9iQ7WefoH zGH}@S4Q1be1lLpUnecrlOMx5Pa$14N zuM^kxsoZ>A(1=!AF8h)0}?RGw%jtE}&R zd)03Zb7362t>U!H?wt{;5}Zmgjphjz1`;eR!wZL{&oz*rk_*>KiGz5$KyajRX{+Ei zqtYOCLxcF3v!HJR@+6&smKL&_a1Mig{(cWvY8%J-RTZzUr)8zNC$ODZ+#`!4(HLSt zWAP3IdwjZ-JM+)p^*apvvjT8ecta9$3*-UZ*3Ryk)uZsiBxHibe7iY`m@j7GEYAh?&Fa_8mK4Jr{U9z<-`3Pb{Y$m}9`qMj1ClQ#9KE8Eh*MgHZ*HR(O}f|r)j8(a{207f6%9<* z75b?4;~=8nV%bC$Rf-lZC-Ijf@7d9Y7;gwbl`syO8wzA~e6ut~!hda#$nkvo2Iqkh zbi)Z7-C?kbCOqtocTUgI74xn8X}IT?fF6OOc{F3Bfs#ETE(^S2rMi96cDi=| zaZ=9~pbsSC=qD|GiSe|PacO>?A<(nd=5vbHNEa@xJe9%uTtAlFd8}oS8fGMN3mp8c*d8%G{*ey&fWCm~96My> z1Gw33%wJ6QQ!Zi!T*+L(IKeq#EH{Jepuk*25~RJIQPLNBUdU~$5>jawaZD6@Y&8(tVDhQw8U6$|V)2TF zvIQ1U1%uePwkyyT!Wx4O=QblfX{_XI_aD3N3fMdKS+6~$^`;tEnDB9udd~K&@Ob6} zu6C#VNqUY-e&nC&4HP6#Jf&zA7cNMuU_ZUjwWeqmFc7Y~V@q~e6qfax+ktJ54L zpsn_0y!OvKmr42^W53Khz&Xeucw_m4TVF>E`l>WWH>YoX1shqdYxgzY4xP z@n?)?t>f^J)6KK17L$gdW5TkDInV1L-ZD`eDgAz{fNU*GjY;cvJ?FkuKVmB`pE-k> zh%|Qg*!3s31N~MkjxBP6S`)J=^bReIc4V(#x%J*P4E}Pc`?7P6itBb6cjLZDFsrkz z?sYqaf%b%vTtWiw!Vba-W%G9KIy8SwEK=qSK9%jsE1Y50Cx+Dq8cB zK1%_w=|Y~ft`iSlSBk=kU_toPl5V`!`ZV5UM;O7Y_2WLlp`dlZG!`BK4!P3s(p7F%R1=EkJ0#tjz?0Pqd zh(9g4QwyN9`O^*-f5qFuc*nY|2y0khjw!Y4-(F6!?JJGNi+Ky8A|Ur{a+Y2`E^d;` z_7f}9`2$egyfL^KZ&PJ`pZ8CofgCR6#>sC9tC(+ z`arlqD}kR7%&VM$76r(_rsVwZE$%2|t(M^rJ-}B@R(Qb&7vzSfd9l9GXvUUy$9WM2 zQm&?MSBbv|K)a8=0E~R!$F2m9Y2?*Q4JfDfI1GR+p2uSMJJS2<9$edL6yB=g_vH9vm94-9*?0-uFs%9Tv4)a$ih%A|u2`X`o# zHQTV=za}r0nH&R(1G8x5+MAmj-uUCtcDo_PI=u|}4Q8?}AP&?ub8ee8!hgoIDzxdJ z7;9=<;pehG!y|G9=*}EoGZW_c9(4W^r`O;65ckgp>7;y_K_;P*6Uk{lP1G zO5uYIbFvQJC#;93$r(mCy~KH4BsvV}RnZ&bc!CK^>3YIiF%NryVm#vb(?6*nFxclX zp@0DdU=Nu@dR*BlR`L;`nfvJk=IT-TPuE9H@HTp!r+2$~@$OmmGs&YO1Cg6jbG{RR zTHn0F^u7*;52Vjh`LT9Kj%-Xy5H?I$VZ6~0hx|<4V$d8r81VasT)cIw-}h%7cD`{u z{E~TC%8I&UR7RunstcJ0D22{U0oNRD0yHfHWW(ffcm!ZWwiO}W zqG7)>pU#j=?0RvHb{TKE9z%z^u#TbE+E=QXb=WZuB^D}LBUI0IZ3le2EVLQ;-KWLg zz;LG`->q;xGVpu?zx8a!8*)Gs+;>>il)YMLV`z7pd-4`%tlJ*)o*iba9HF62ryIu6NQc!;`J}>=n=tV9p9ajs)SA! zGF#+?KBfp0{ko)A zQmffJA~9#A!Jz(_tz^6=FugO^c4`IKn4gmW18VjIVEz2Pr%C$3@aM$}vcsC!8S3|~ z$VFj?I?&r;6|`nZgk$>XGxjlYvmKI#TOcSC^?m$fp#9e40%<+L$P63r`H^rThlaZm zWra6hcd&x2KtoDFHXiIZ;NjstXLQ+Llxx(2OLn_I<2SPerzP|1^jRWB9ztojA_#7j z>pr<-a?LC(!Mz)+UP1fX(G?$KnGR-7vUvaUOnL{~wx0BzuQ>suyuY0yet)abd9c|r;0!Dk%Zhm(g-P$c&Y5fpZ zM0>vz+f@`au5p>rh5wHEekVoFenw>=K}tzo;>8G-&8cD{&Vj(-1-GC5NosD^Jm7>r zDq{a(Ri1i{uVgYS<)Ik&XXz?1(2UP*+b+OC2e$4nX^zvcl0^sm+hC8l1o*gXvT5Du z0Jk8lD)ke7b+JW*_@3!Ki$z*WGtp1=A2*DbiE+nNrKLYWbM-Oq_~ej3e#$>GZsB%{ zmNQT*@mdnYw|C8jpbnOgrbZqPsAKuHD`I{nO*Wem)g=l8LMCKGat<0({Okv%C9Xbb z1nR$mz|XIuD*u^tH@{G}IT@)CHn&+cj_BaN`Lvkiw}0MlCbp8d+l4i<>iKk8h+g`W zuW?VFT5h&;Q}!q2=dVRZO}rbr-wuIk!~m1<(iyR5BGMU`YxZx5Fz!i6__Uq_CNLw& z0wdFq!%@Pjs(~ue7~~Za&9R@9@s`qF; zcw=(2m)tMg0qP727(n2>>t;zv^?HUsiyy#rIf~ydmXy+S2#f$IOCqbsK9)@P5Fe3; zGF10Q&!Xo7=oe>KXlYHz=TfP;8{#1*zbY`xm{5ULJ3(3n=CZ8e(C$o?{K8_$)Ya_J z=3*|5#&IixamYwmm>6fEpCr`aWQCaBJlzCZF+!AASV+K#N&8;Lom+5$dbWk65p452CwX4Z*mwq*fme~Hw3UIWyj@?90@Id#d`1-e z-vh1eUl;h(v{MQUnVs9#T2fk`YrgXxVfA2``plKy&baEn2HVwk*}+6Nr)ZT;ByiP+ z8@pXu2Ij7Av7SQkO{9f__9{@Lho}JE$>z%F7>|;b__rYhT`<|?Lpi26l ze5=QYd7a!_=@)#HAm4LedfHP1l!ghlHNLN4M0~o@dfh+5eY{J*)@z~tY?sLgH9FYY z4h2IdMn__gc^3f#X&2|nV0ZGY6-rpvMIW2>-`)KJtGv4Op zV3l34!~OV}h*n`NSIxU$VIdmZsk3dX9uTVZP;xI}MVyfnLOq)-3XX*cSe>&3&76Q2nihVIsov z;PMo-i>vbT)%*ysZ;r-_RKm*i8PCW0dvQAr#akwC;`-k_9RLVK`F+#Rt58-sUFBW{ zoBjz4|7fCMy@8%LfVQ7yi1U%&TVEb-2eZ|(MeYAQ>+dE=TaoxS$NAv_FhzZn!4Y)$ zfosrr{Kt?#vtgv|+sP1j%HStexaPwnUR_4!)KGhI@|1Jal8emj8`8>rjh+O`Fs5vuMX~@i1BbA6x z&cJzQfbAr{MTVFFS`h9!TjK(8?w+hJpA4wF&ZRfrcp>GS+Z(4tseNa16~}6Hdp^sdOeU{WlUBAD>3b8`e}DRK~1pIU0otv3X+-8Ks?KWVP#x;0F5({hCI(7Cd#|t zNWYV!Ao&gAU9b|U%TIZrhASR2-#xptvuUg%_w_va7XBM|ot5zyUQmvt$9$V09yS+7 zx?>>}bw_@N>w=s*PGo1xOOZU|wbuK+>DPVcc;gQlbZ+1`)7fXwnK@LnWEZe@!L&_g zr|+EZo4vn}dfqqtZ)%{Y2=HKEunN{UxYAR&Oy4BUs(+3YbCgOXYd$cfc_=SUcbN<~ zh2AiZRg%EU&NISi)^;6>PE5t`!~RXn?nTkAdR+ttS-<1RW^iCE401|)=JNgd^Pv;= zZ)L!v8Fy5Q?xx%enAz6L3vG~&QV_8VM^4Xb7xHlHn7q;O`u4_b?bgxR%|;EuQ2GU9 z1gvn&C~*J2T=NV`DA+lke70mIW?+Wmf??;A;0=^f6S;LwaK^Mx>h^Ho&?R7XI*Yk9 z9Xx=I+AuZu_j6p@&u^L_iPMd)zBX+JPfclQpO}`FxZ(ff+v@;qrE|jFl+RL~7Y1_6 z-0MUIA8x};Ir3ZNB$j`^yLl@Mq+q^8@xxK^YhP(fu^~|=o6@H=|M-=z$gQ<>aYbI znmXX`Cc-@j60RopWWC@tYc$+;>aAyi|mSfW2xW z9p>;ERWKZ<5FBc3#|>Q+`i~2M8#tRw+U(2QT_4?Tsi3Z$K+j8D56SHDck_9&xX$Z^ zZ#RF*sv>w4x}NcB?X<+V$|U`sED|fypwl__fyLcj)}4r|N75bo!G=2f4y1Es$QVeZ zy2K5|E&emjL!(55d0~xYAb{Q9FdfAz9M$FFrU(95a*ouw8OW~vd^fy4z^J6q!XAlh z6e%S*mY#X?W#Y2KMO1+vP=y(Gmc!gxKPp;8O$MZQvTLu4p;9942?HKpinRn6rll+rU*;%BVyTfZOvAo`gIJBqbB9S^ zfjkTAg!qqC74g*at;F=qJ3IhhroPFH!Jf_xcktH=e@etv1RPBt!Rk5Ps91{E&C9C& zx7Z_Np4`m+>pJD3aub%~{3y1_uVBGL)Zpna)SBRI0C{oEB|fh*r_pssJFD{KH6ZxM z;aUGA0i!Q6Rq4K%2KbVOgl~mIVA56h{#J*EKobzX)Ga>@L4k!f#B+1!M$BtLVIW({ zZ@0z7FilQ(3;xvss(p9-xxxOWh|kC2`}Gd1hK=qIy!chjuGrrfFk!Yjqv|gj>9@fw zc!6$~83%jt>Yi<1(><=cDdl!+=e(YHv*!hepo{1FoF8l2iyFTPebmmg?axY9gfa)+ z2zZW+89C`&5&mNLwL;_j6m{Xsa@4fuK;;yjr-Fj)Nv9KVL6<_>5tUzAm^Do>aH0l?&@DYnC4g$YI~a4qXvAY0LTt>ST-!#a{oFX zTv$B$=qF!QZdpKwfu^%W43D$k69ZUn{y3h>?);j1F@!=a%9O_92uAz3OF8Wa3OnBW zOvpx3dclHoE9ds3VyG9$%U?z5qn)uXgRVrGGXvhL4?n0?|8vC&I-e83qLZoW)svOr zae`hjd&A}NYC^!_Y^)0kG2UxV^%SOXzBgh%DP9R!>OSN#Cq6ecI%W zFD#z}$UdW)svHL>vh@suE|?K1-wel+`2=^WhxM}K&^{{VWjV8&YEnU*!SidRv)sR2 zj662io%C=9m^*=`W-iV816K)dmOP`t_GX<6k6NR1&Ez+hRhNYIlIcaTvRJ89aQKtW zsB(;$3=kZxWE2~B_s_B_2RU-d^2s;*f{RY))^0~5>H4!_IM-|?sRbn!@DqI!ZhW)$ z#tb%PyR}%gzh#=Oz))sJO$OB17B8LZ_tNKM2_p!)BAs~9{;7VV`|~UhC+=R#&4+n; z&P75aH+c_tMgw>zj11%c^?-W8t$8c#uinbr_b5-8`LnxwoEKv>HnpF6p--P zoo-9uTAfab%r3a8^+LWvDZ9XVFU}=bK4@SPUtaPv(saakL}kDy(b5&&V6vV~%9d7; z^*;ffR#5%tEL#?-L`uQIXLKap9hm=KViDC8$Glodn2!c((Rlh<&wk2n8BdqO5yM@L zY(W}JX7*!!0dA6=0e;Tw`h~D_@06B=7Crs+U>!n^`K%zkSBN&sQabJe;WegIN!c3?v$pCt=jc`+$~UJI}%}T+`-L_yOY9|u~KJnx&j{y zY4ISi1Pkx$By1!{JW(+}p2Fky(Qr-uee0hdHp% zF?)IcX;_G1Lsw4*RMwu{ZmyBs-RgNTjIKef_lAlrEPGdNMzg#L8Iv2e!lJ{ks$J?i~I8{2XFsJ`0EZ6gD z#ir_uiLS?>lM5m$+}?>U?Uzr3%ywmW1eZYdF0U8xKKKyso3)8_ApY!k|A{{u8S)o* z2z9Y_x?EMGx71ZDV(t}ixHx0v>+Th|3UzrE<;s($J^P7+D>9?YNFM|8{pgQpC0-c6 ziRZ36wHl++a&R$1%!A-!ujE0P@XE%O;nTd1&HIzNLk4FCCBKz~B+R>ruLM1(P0G%_ z9k{s#(aH8ov@P$}5%P2{_ZC^r<18F#?;XE8>Fk3?oOI@UD8Mah-=*~csBS?W7ppz# zk|BB_Ac=4B^#Q#(Uc;%v{ne!2>1-sLzfbUU26*o4Z1j3f2CKU11K==~^do23$)CL7 z4GpR!O{v`N?KopK84kNUy2CN61j}9bqmktrunrf=F0lVndN%3-5 z1AG8)jj8mCEqkbH?}fKavxxoyDGHQX&g8R710b>w&HL1%qR?P+%J=1gHNkg4nf_GD zHT1P3YDsF+=H2Ao;t0?@gF$LasjoH>5xm2spjtvY&bz|( zGDyYcdKwYJXL(KrW(ES(Dt;IdEw5~Fmq)g;io&_mrNSksTb=HUDHi{<6E-R?ofzMv zIUd0&ctq57S^UxxS!1?xE&AA+4EeZA|DchBqjTl80$QmN~@h2E^Ib` zlL^tT%tbXU)&v<_JOEk^MlL=zR+4ni!mEK>NyU0Vb$@G9Hmd7g#{Z-0y5p(d|Nj{r zmDNclS#|7e$ILj56CH#oJ5(IWCM)9{*Da^AI_5#B&@i+2IbF&+C~<7(TtxPf>~Ve{ zb-#c7JbL6&dGtA-_jt|c>-p?#h>=XBjK39LeV-d^NbgKQ0y+Uv-N`G?<`gaN_yARA zs%`z;`G&@-MIn{1-@g*lWM=s&2JV;#)x?3WW{KKDKg}X&{{V4dI=Rxb^?Jr3e)u<| z?|&_SJ7%A4k~P`v-g-;l@@7q5phpt9oSyrAEhHy1l^^jcOOCl7AOasS8jc?>(}epL zj1Wt$6K>v6Fq#@TE1aAM=2V9Ks`{Cc6xKHJyyna)Y-gJ#dh%Pn~rN?#}A2vW~k7 zQvef@M=9~ap;9zj=*zQsWsO?>sjw*zmefII%>k3~+_53+LIfsMxYQPHZx=UqyrwpB z-fCkijeM#2YrU1D-clyIcZlK|xr}c4dP{T3%Gqp#Nzg0|(jQpu;Q!a6-6jMD36yZP z$UY8l?Hj(uwyTDS7*m9L3bb-hod-C^-+DUAx&)z2V6t9M2%+vfDQBVd`=bMo_O0?< z)I}(s59ro06jxASQ-}oBG?1m^kWQFhTd(pCrBT&vX3-K|G!ZQ_9w6Xk% zf+T%4_1uYj4<~$2NEC04XEd~y)XOS@Ej)z> z1mHl0{Hh-p^9AvcGQZZdl^oj>r;z1ZmZan+l)x^_|HQ6hidey2UAjd)KU@*wm{7r6 z>)bq9N&KmEKE&Ds};PctpgDF%hwJ@OqRU3Gxd?-~^a==W;ie{k8u2~}#q{Lh; zv;5BEOeyw#VKM)=dH1iHeUVlW@`GG_DK8U+k=1XRq?AP7Y^yYnCT@w#e|@yR`fK>= zLpsFSX2Wh|kSr!Y|6%D`arW*dLC-E&?6HQQ#`=O>kD>mU;e0a39sd}|=kwk19O?-- z=s|KyqXUydfQsNv@;Vl)-cn@kr5n=7q50<%e%hkgsLH%CE`GAx^K;oX(&he6+!-Td zQ*m-;Z6sIU#cry@%R+AM(qlFlN}&zo~EK zm27Ua{z3gLocB+2D=_CUd^9a}w};6ce*O}$!y|r_dyJkv-J`!FaIKcPJzf0E|8n~) zHqgY!B=r;EZ}0P`VoJNy^o#qq>}y$)wORExLB{#i;CO=6%dYtVrMjoaIRgE$cOCEe zz&=YskP=01Br*TrS-{*3AKm=Z6iLociRz9HDtsQw1@OD9{C+aTD^vAHI@VsJki=JO`E{ri3v(S$%S zXv-O!vK^7ZyE3b)L`iAq6`3K7XdnwdW?j1*YKox~2v$2zVSBSK0J(4XR6w~ANgyuQ z0`D1_2YCN$Y_unY**!Ju`8q<{ArD2je;Wi#D!x8govYM9mPZzdBO^%mdheI22sMQj zLjpkHiYpM_06UEnYO3NN4+HX5K+CTC9Il|wZvl%(Ol*&z8gW9*?os}MugvU=7`f!! zatGokENwLt<%FLv!6rQ+DG6hb5c5cq{KtAmq zR~h-|69Q9ioHpk&M*nJ3zdg+Ke_ry<%oL;vJ;g~qQ&RtSaRW#I&_~sOc5a>zth9s1P4lWnkEzp${VpefV2^m?)~#9ia>bQp}Y#V zf-Za9TXjZz^hcR?QXf|V^jjK3`$|5f+?(wZ-q@?QItYhzJEqWS=;vSU(%ONDQrS`+ zp9}o)x_oJ{!r^aGr~i(FT1urJ6_kbzS021AR+suG@wjrBit6j$ccb9a7ZFf&|H9h= z_tuK^#bpLL;L71m)ad7?RD5dsB2w^(xIB0lTEn54X1qCc#5&u!3X&$e$!3$6=OyMe zMtFO!)C021ty%qYtg#ZOXb5xD8~!r=X$i%N%z(;YwPd=5DZbOY+ho#|eeG*-J4$7i=RIo`r(qUF?PY@M@!UeofB7BzwrTFJl${6?-ge z=*+k2Pz+i}%+19~-<9uj=W>rdW5`6+IvN&(aeUr4D=fq1%Eq03lf8&6}EzYpalye}#=SUIn z)~fEsKayQ@=nl6hgMN}v=Z zpwlE`4cS!PvdKHYNaYcl#f@zm?b7vjfXbTi~CZffOS>}B~^UPETY>D(Ef3{h#44&7$5ll+zu$oDyk5I zg}16bkeJRS(7)@>r5zs9)-haMqPHRb-)9S4R!{PX zBf3Q${y||27yteAw)gzj%^4goFqUNZAZ#Cn>7H{ek8!tAso}j~V>|K9S!K4v#U5xe zT9MzaAs>Y`0trJ=+j}{&Ha6ISCl-YKal|k+4A48#8-VbfaXoJGeo++D{R(w*GdCCL zd`4C7y>4f0>rZVr52)(2yrxvd+%788Q=VrLp9eCl$?@FnOLBjL<*g7)1{2~R+IG42^1F|60^ z@A>?}&5=)lET(ai3acSqC~%g=+-;|HbW&J1$zqi3wvA>9JbxQ0BlfU)55yFLlipyB zOexdFqcAA>ji?lx5*kwPQuo4GBG-cM%_=(D$f?_-G&IY2dgn$h>ppt4x2s8?h^!P9 zi)u`MNTiQbl;K~KHwvCpbSP0%3#%Qd^eV6GUH3(KkHV4SjUc(9FJ7lg9|)|5Q252} zVEJ1)Y+Rg9*zSwyT!nQ!A?!#ja_`0!{>405>fh`-v)0CvDjfO3dRmDym8s^tKe8m5 zD3h(Yk?ncPYAj}$j5CttCD+H!+;Uo)oN5Q*|!!~+$fl@YZ z$8DDO({0HEJxfl{uH1Wf{(Qr;kF2^Ykz{ZXIEZM}+?Q%z^SAM?tx%0FV%#J~8bjeH zJ~=c%!~wD!Rj(#j)m}&KdCqpM3f+t-Mr6}(Iaijf3muY!h86CD!fbmv#1Quv@1%(R zb`xO5c5VXrT)6fSUA@9;z%ZESp91NdmG=Rj`G9ZD+ez0mU`{#0l+X%1&mro zKIB`Qz*4ZW4hQS`*_0MV#zU-VA_K^+gLj|y@hpxy2t?HrFv9}D zC@sEx**Gy*kg#D2=a@FaVZo5Y1vV)%W&7HI=#Jfg`)u+ILIL(UMOhf8BLXKceYV!) z+_mmaD~@~lWn_RGa*Sdw8+je!Z%zv=$vqnDyUfCX*jZ5CeC``5_WaCF2-96!(n7w zcmIr=DMNOOy2aftj^}fqDLEHOCIT9JUEB@j9vS3%)5831`!WxK$)A)J7rXHGXbt>x zqPqKFmGvSpkflRrzu&Wb!HJkV<~~xDRKZ_s|4~!rBc$vc&(tx91t19P*-NWEu!`j` zdwxf@>eh><-6^=&%_(XwC%Yo1{6GNis$)qf7`-dFDJ$S{{yd`2?%c0XiWI&F8vVdu zE(nqe)ei9IN>YsI0RvJCm|jtFwc^zCtqIUu9SiSM@DlI<*a9(8rM_)v)a%8KiUnZnW4T=?b@!>$7XY2& zfj*JT#ka%xx2k(Q-jXn_NJ>VfR!U}Vczv#CXH_;*ec9Z@jfQT}NV_hMBtw14WIW;eyoV20~-aS4D%Mrh@ zdn8z3Fi)r3%h@H@|KG))R*i)07Y=fJG4gwg1D|Gw3cDu0udn7UAEr!GL<^LUlclQ% z2L9TT>fPQ&nPt&K-CM(trqz#HHt}X&k+e2G%R>D+UfTzTuLzNZ8reu5YMr$Oy4i6K zR=@pN%b(IU_xZdS*7nrGm!)7l*DF2EjLWscgX}f6^*~cRk(f_(C+hWG-w7POTI@FL zLVWzZooh{{G#gY!ta#v>YH;dRF^E<;Mu!jT_mVJGCvg$$tdGf~x|?(;QS=HsFo;(SF_ zQYBFZcwMoHHOc5O{(J80bE54R+8ww@q#!-XIF#vrw?f`jgKQ@Q;o)%tR0~(2qxh!J&w5Y;}NrGxtm}5Fe8e1kD9@NLP=P-oxbLBV%cQtw# z$JO0qkg|Z1LhReS2da_&4!-3%qDJw?Kdiso{@v4-7=nVkwMtC;SqZ zpTQmR2?P)?G}d+JiGOSLRwLPy2RLFsxaK0sxMlQ==iy+Uf)Bo>g8H$RsctW#E;N# zd=%{tvS|zfnyyCtb>e5|ct?G^UrD2j*w4;oEKi<`zLn{=w2#P^%TE3S6q5zn3hm{8 z{8h!jP%0L*B-Xj64m+}R)>Vf`y}oyytF7mGvJQ-x4RyR%7A{$;z;ssBU2=C2jQAnb zE|i*RG=4$y#>LJ6mJiyVJ}{}`ZfZpqEnCM7$L{VIHnQRC#U={ERdc;$CH6`3&?`$Xk|2l~10< zdeb7li&FRH+Bop+cq=SUvnbOn0`@9;XXOL0BC64a6YE`D{PovvrBXs+=agI z5H9{B^}G}U8@ld;9=)`I9o1N0jTQL;#F%)%+NsrkzK;yOf-bQHNe|VH3G5KzD`Bl& zbq2jV?UgebT4xX@3y)ey;WaUG{oBeaU(UZ0ymjpOx%Cc~2F;R4 z%@27A)Ef`hkajN+d*a};4}J0BW@i6f&T(m6V}beCI|(p6p@#b{ZLlaibzpYS1>VHg z5Us=VCeBxPUq{@5)s7e6)7t1?T-j53I}{`%poFIl^szBI_D`8{m`FtJCEssIJ-_LF zOTz6MBY$5cnq*^2Ah1B4lTXzS9;^=1`d!NO;IVqo5q3&bAdRizN(zFmipXD|8HC~E z!L8sD@VCfSd@SP5oqB^cKmkV-o_)L9giSL`j>A#D(wC#u9c|x>yFAxKNP~qP+Ei0I zk#-5jQzdlit0FN3fI7^yw;F#NuKbSNs(Lg@0@frmTTf{t1UE|Uq&_&Kq>G3c>OS=un*IFO zWdK&oH&wX#Tvsb4QW}9Jf`2+#-=B&QF|P*z%Rtbe0Y*I` z6l{kY10Y7oAS5li(AviltuwAaQfoLuqR>0nEEhwilyneT?tY_pTpUZ}FRGyBA%&MD zn^gU^N-gNztp~RsNc`{pR}cjlrG>3!5XJWfo0OUCPMSXaKKIea%h6}M)l0fY?a>XG zZpyNo=(%c7Nl@QsrB+D@i0cspH+F${S3~&)trN_pNgU_4zozhQMQ3YgB?2R*-|~{% z)9Rcj9U(i}l~i#Ht#dtn;ZWG$)8N@`@CLYby@OAn&H*9>K-|e744$@z zZW435P7h}twm%AYPf^FgObQms#|901ch{oCW7z^hum=)OXP`H_adH8;Okx@p% z12$%6t};Ul z@1YHQ7%S92un>)zc|oay`vxkax<@J3D7x?uLEd^P2j_@X*>&PibSybOUR$^ zMD?Bng185Vm@CC1qxx6y*NG<={`F1gwlwP94i9l>l(@L@0#P%!%0;IF+xlm1E$MZp zDT`R_H9+r{DeZHdx%kun9J3n(g@ug$a?YNNRNQdR z#ztK~yiW&Zo`i1<1ad=PwV%DH@cMZW_7;rtoz+z+CJH_YY7&K$-+7WxY+fmcigR;J zzqgWb>&-Vjc`#Npat{eP#RGKN1-R>@Q%9Z?^(!~5$IiMP_c^&Gvi*pVHk!DXaj+XU z1Hp%X7Y>K|j_xk61=x2{r`d>~4Ih@i$hMPs7kf7qQp}+cM_5)}$TBffD)iD+D!*+P zE&xhpX_Uv^h+O`p{Wb7Zsgly+v~#m4VpWMo0suWO$IE;Ndfbkf^lBOwj^Xbc28`>V zc_kYL2U(ZxYE5Z9U%3#Pn%k2s{`ZitX6ZQ}bM)?A^&OSpw`6GQ4;uG{2467ne|7Fj zwW|%_ct?4|t^=er^I{X3`vR{>LkTMqPA>z2X=Qjhb*hA&rRa8Sm!l?n+GTfuUBP|O zQXX1*NP*>z6|O%WEHqd`9Y%51$RbWBJ_DTuPqT~2wt5`dz1V9AU-5ABKVHhuJhN5n zf2FLWr+`vzlrf3F6&V^i({^E31J94Yi^oCSA)U}_a0y5w^{yh+Qj9FRV0i_BS%&hQ z>v=g8T70mWq&4N=`8FwFd>LQs_U_d$Ri@}qqn>TKzSiwvdo1>{30h~g|E{<^1|Sdc z6x%c%V(DVU#3qXTM(?R?uCF~-zR?NVg&eFc54uGaqYdJR?j&VDAr?cL1mUK%bTYzMn?wVuSBxMP~}SyAwIZ)ku79U zR5R!HJ3zl{QFbh(DX)WKGvzv|2%y83e*HO=x}AS2@-L3Vy}yL*(fD>A%3Y?)PCcwm z$a5c2`LMqHBd3Veb=weM@S1^wui$fmnjGdlfy;gmvS|QV=c$Be9s8o||CDxl5S|cl zMu0}1G{CBV+lki+igCa3#DLdq3msG!BvRLZZ~ zqrW({M5FkXKOg;d*(rcAMW}h15&q}i@(TVB;O4OA?*|)2QrH(O>N8X3j=a%tDQMJH zLJHo9fE99up?hl{XE&Z6UgBxs4}P^<2nuV8jZg$jCKxrPkpch*gl;(jUr8odAJ!DG zeiXJm`+lnp-Hw79fJPD}So0^v`PhrucqI6E*JoQarGhjz72R~pj(iMeBrN?p!0ZC; zx8^_gtI+XEOFOY!mgR+fD+;#&h@#|yEm|7_0XTw9bpdDh>5tnl2*Dzocz}Y~eV6gBvsVr z-gX%|LisnZUH;aB-?7q|++-uif|UK4f=Uusp|o3VFZLE@$LMtb7hXy}@rK~?EHD+O zzA#Y(%!aT7h6lGi@!|Ii(>nh&r+_~Q1Bn}s_aCYU-cD4LXH#40vNcd%kFt{p~SHfY$Dp0GiIUW3}qE=8di`EY_fjV%+fw6|?^E_BewGEUV?Hx9W zBJQwgd%f>=FLb+qd+qJG)ZeosfVYfmxCDy_I*HtH-^AQ5;6iSIAo-9P2-*GKzF3Z) z5l)UN$SAYLwHiG4d|m$JxltpH6pSk2R=zLNcA+<++3ny(Xnd9m)%&GG(EpA@_@&-q%D+Go-Z&*!#@@NK z1q`rESONsZ@rLIW5LrL6zovJ6jf2J&aj@nOn(N_s4sp+8aE-M^Ch+;FKY^zC_Pz+= zV7-Qf?!@kkP|N^M$b(&&mmPtmUTGnB>~R(d!+kF<(g7}!6KUl5R#){_StEZBn9!g@ z{lS31O-eKfFu6l!YY>~tA8-EGgFowa7*LSAyQiD*zdk(8N*$&!_x8F?XqW>7)u@L+ zx>p=iLLx+#(IfSd@}VI*03Om!<)EnzOlSVTruNc7Q@eRP^fy*ty){jre;lkX}=FK@Eh#Ve=|@`ew;Q6yBb}Aw7*y*=$5gAZnjZg z1?w*5F@=8q-aeSIJ1&|`8e*JvyX@qCf#OFoX1JZf&m$(Xi6_|tIlAKs10B9%kpMpH zy{F5LPTt}pAn@k>OjcpeO4ctC2nE>J^iPp5@c#ANI^v!@4I=QMz>SsYr+(qFPYE9Y zlpR(){7~9yc=g(b^|09NT}m@B0@u853Y|nu(D#rBHl{r5-~X+=6^Nc#!SAEX)cVO; z)oH|J-2jM#Y%tICTb}J{+$h%?#!z}BJdeV^rK=@W=$68^LOroq`G`Ydxv}A*AYfd{ zbpvF{zOJ|vD4r>_J|N% zTf*UrRi}iX9^@L#A0-15K3s#f9?$%Cf){I&I~R?(_ljO`a6u27%=nNc>}GMdt^E?Pb&o}scD_-5!dJ}r;|sc< zMU|DRDm`tgJz016lb`k%$AY=^`vD?i6DpVj z(4K~wa9BP&l)A5hbaxE>_@xsc4i=Y3%xW=KUFcCnpcyUK=Jfprqjt^-!)XMtJZBIu z_0AI`&bbxaX5@*7zi%qyyt@<&TJ5jUF#w70UGLo^N+!=JoAge5#>}qxQTKtl+rHUj zn?!Zu1OJeigkPn(!uNN`QnP`W)qyHc#aVWYsN9CctP-XqMQ@z=z~P;l8LqHgeD4iy z=`6-ERn@YW8W>lP?(O8hyXzb}^D1z`Kw`{Fd))++@nC&7Nv}$_Bzqh#V|)uwA+2x))vE4d?gnF93v3G7+IC<+8U)9L-l>*p?RX z2>&ZgL=ci{Xp2CM%XyCL#S`P$03=Owp^-$z+Mp2_2OGbbHB#NSHmgXixPflCs@Jmt zMzJ@Ya})cy3*N0BEj}V-D0ye}a!MT?8qB?UfAK8pFx752R<>uBt!!#{kpl4)s+K3+ z3*uBNidngY`6f2e``Q0`XoP#>{18XTHE!8f2iq*io3y4z{|Y@)(lJV`b6#XP-qAu2 zn)LTy?s&LM%(u=-p^LDte_12-%S!F<@86zWPCv_a_0-X$;@p>yo;ZF~-0-N`g$rg! zpFewEa7y7X8^vjNlN?bD`%1bQ_zK&J4?jX7i`wQzgRR;dvbf_jb`@(HFKy=FVAbowl(;q3zH>E;Z*UrL>8c87)+u+-_^!p~3u0`o!A)K9MxiR|Uwt zU58C%u;C-eEey;Y=EoveBl$s&`CKVv{J#<_jg=ykH!HdJCn)DhA>pwS_(bV;c5O8y zTXf6&q?X5@I|Aw*b-Ra?2EsV*LqJT2j`@8*!+-wKr)Wq=%~{BN-+0s4MCJ%AHsV_Y zyF)qp?vfLJiVQ{8@`0+}Dvvo<<3Q@q2<;>-c_d2;5tu6uT1XXw?h$n3Ui1@*lh+|&6mr8*0`#c>DM%bpWoxBGN8)>~~NG~xJ zh;hgZ7*Q+2EyD_*lW?M56iQS;sFDlzmq$m=&qTx>dEgr|dqPtHzJr|>SldpjTXbJ@ z8}7c>W$yUWYx(|~U5S_DWr3q~HRLjOGkuTF6ZTw1R*2zir~)QwAra$T_J#t+4qTez z$PCirwTVv}(wLK;ot68I>MmclMyZ(&Bk9)h??xmdT_5Ot?w2WHtrba~PO-FQ|>x*kqU1L#y)e#q;U7F>{4aNs*!`+0|ppbdLeGv3llvY-mP_xJy zggH$Ztm2^r={^2v%)UgWww}M^E+wZLj|(?Eyg$9Bsfc_NurM$%>@A;Dl6+L@%Lg(~ z!}FiE>L0v#NBiYu;P7YtclTEQQ7MRt8N@tyN)J`yIsEn!T-7Hs)qMT8#0s& z<;!n?qg7Bunx&IKN@nbMNgJmfYQw#zD51d{(^-%7;?u2_dMkT?pQ0c2w1~7zzc_CD zG(rH7fNf3^n3HmzP8Mre&cM&8MNwWL?qE8oKa*vmcI*sVPLj4#hh4lo@M~X5A;Dv= zqJ|I(DmvJB9<K6A9cMcoM>~P|5*(M*?7e_90 zRK*gm0ZLFPW1C^dm86T?GL`c=otTR8)zs?rjF0>I5B8s~ZO(u~ou?Nr@(heRI*xh! zjg{zX(nA(*N_SfBCYu-IuxPoO4~yahS2H&V`<}wD*+)!LYFUp2q>9xL7wk2Kr2-Bdsc@VLfr~!uh0) zE;c8(j-6OSu+6P*r$NL7gD_YqX=#7O<`u|L4faD6gu96@G}{@&UtXW04^P>0=d1=V z?%X@3GJX_p1keo<2DK6T=^!x-QFX}}^xs11n<8I_=CI+_B5jfaXo7SO5%##Jgct(r z{i2jP?6xTY5TjL10xYXT@aGg^$^d?#Dy~|}MR$Es|ENE*Z7==wWq%SMyhPxmFRTov zq>CJZ{%}{>IODyVxmLNYv!#QbuBDhp%14G9_|T>LCP(eEOMo(^U2BA3Daz&K9qg;K(x~^i2C$w39@Q?>*C-{@?R-eQR+7Z=xOe?rr`^pu)_d;ViVks|>B+|>>@Ncj zT!AvF_L<&4B3Zo-%pZ%nv`3NPE1hp@;zdDL&}dNnz>fCo&-31Mz=eD{eGK%+%=iA- zk_F@@+o7X@$9%5W?}lKo=t0nLiEvJmQjI117LPUhH0cniBev9#*c4m1kX=Xm7NH5hQt95x`J{lZv z26Ks?-%Bdn+A%wKXp~(jm2@pH3TKv8vQe3GX!GcIjc=VG6#%U?nErEH6*}%OjS)n7 zjSXzbAisDQ?TiV+r9i0rYg)19u{n(~AMXZ)o|TZ9;9>kt)ge!Q5Yo4aZ@MKj5der4 zzK}-JcchI@=zLakp1uqJ0Nq=DGeohe7}q8NYx4dfE7V*vX$&lsNV*n)FOW$-J{%8_ z(r}Zs03(TVc@pXA-k?DX&c3&{^)UAJid4rABgxWkHAuDK#H0x2dD7p6oCbX(aJ2Fi zUG;xhfFPX|E08F=`fG7+5P)BKt{ znL5rhy)0?Q7$u(+(w_#CIB)f|7)v|s&nWJf>r`Fa;_39 z0J?9yO^k;P6!_s;ng86|={6z8cZwDMne8Gk)aZc(0(07t5B~)I;bt}T>s#x?HQ7J+ zs+2~J~5(i=C0^FgU zpwtK2M-QIlcIUMh#~053?tj3;Lz+PeBkPcHt+)?Y&8tVb*oK;;oHn@Cl|iqfDXo)p+HRJeA(AF`iuhv_C#M-3Y6vFYrV3N7Y80zb3IyJ|2Qp zS-m{QgXYXn89<$?p$u3MbDuvUgad?lWU4Wrn3^Qw4jF%A{=PH0k4({p z0`OLJiw%5bn!sem|G7z=TK`-4V{kqo(4&LifR~{u%_@UL)m(!0BbAY`q2UL7%xBb0 z+FZG;k`xj*@aQPV33w=Iz;&8CYE)04MrhL)0 z+f+804>Zz3hb1b-?$`h|II<;q!=Oc-wDkql8X?M*U_7I6XnRGBfIL0pA&$c9(C4}E zw@<$Fn-kl$U)<`6osRLhhCU^z$zYhB=$2kiJHNkF%~O1m4*YV!)3|x93mM|?BoHaD zxr!kTe1q>C^sc^p>*w0Ic(@~HqzBIzB9mdABk9^>6Wr4m$R$E{j$;UN?2ajy>;;FkDr80XsMQyO-+Z_~7 zLqO&oVRvndgFL6c4 z3q>(H7X`)c-0a}pNOi{2H9xOCsPY=yf2Gjr6M-JRN`kXYIw;#$RS$zS;>^P?4~Ycl z?&-x7>|{BMbt?s>a1#!XPLZ z>GCdC_#kJq=W2*kFX>1PA276 zy$jfx0bGGwVYY!bc;vdCXuTw2UvTs2o>4z_)#jZ1)58B5f?IDMUUtfUI3zGw6|k4E zbVUloS%g(*P2K*rr^;NJ2DlJ_ei#Cwt$-ApaH#~ae;i^HO%F#337c+co%(=G2>?$7 z|M2rFqy$NKKnont{50AQiiJv(CH6~~00*{dgqG7I?(`Cj*|8Qhym#iccZii&`DYJE z1gyj+o^Ow*!QoQCv0GbL6PqyEmet&?Z>kP_Uk%VL;=CJ|6`m0mha=G~4gsE1w>znV zu&aJHMP4)S0R9qfD2gM6ZCt$p!EYaNm`SG>b&JM2?%l~tUZ)Wg{czt~^W~fI z@DCyL>j3C&leUI|ue>2_Iu&?sJP)(#U(GXx@zjcpR!-7(Q?$zK4N?+m z+sMN3>17gT*Nu@%aS$Uk+PLp-KE&1Qw+xej!={&@a%wN}VYs%_>gm>hZnWp58nb(K zQc2e?W4q%B^N}-E+nyL35r#TL#fjUnc2gT~3W^7%nvF{#BgtkCGxdl&79BaE=HpR( zGUZ=Q;|cw9dy7}!ooC)d%W0GIp1WWA$91lMnfJ^0qa6T=wJ+S)8yn}0{SiqymIPiZ zknZWcoD z9-^4j?AO@wg6WUbA8dYoxVAf7#r=JE;xOYq-)P~UUF}30QE|1g%YV2_kzSr1vGgz?(JFRH>B~Zo80+F^r zOnoO`Mgw(J85z_=b(dN0|0Fa2jeI-y-|AAit! z8&IBpxu!=JhIjI;Zgv8;)BCj!?+A3JZ&E0mWM^(j@5z-zeOZ6V&?41d8(Ti!k;6&> z1++iYj`W-h_tf7K)R986)H63>gdlH2M9&1pz_w?8n-T!!qM`(A$UOTRC)m?%-djX+ z%+KrOP#buIl_fqher+#{am*`XUgy38`4|?N`-}PrGs74))P}P0eQ-zc_ilNhVh@_?Sa&4^i`dE_`B5wBW$sBf# zM=GaO28>${;u9s-1`X88DO1vKQj`ml?iV=S#nsVGik%-=WPwnxaiH%J9Whr`RyW`u z*qJ?BA!h*M3V^Blct_oux9D3(EC55vUs}}xQuO?!p`6Pk^J-UDYpxND23%fnqYw>E~ zuF)CIAjr2lvSNN1&I4L_Wy?Xk*yetIgq5dB!7wGP<%lK7EM5tG;UI47bAw16b}9`h z6cuT;7I%AY&as7q?B?<)h?ojE>EI(fvrsaKz}HEi8o4!{?Tzika52YoAib5U*^!oFL2z!k`k8h1t3-VtA=pL3oEuUdPc7EnAru2@rl1f|w^e z&aAT_=oY`E4sLf)s>OSh902fS4Ku&6P6vvVkZiUf9XV8&q>cWN#rwRZkfB{20%0(c zXk7~NamGeq3Aaug^)CuHFQ5+Uo1X4L6>8zbQQF=ddPbPwnw%<6P$6u$sek!c2YxGp zQh-Nsn}2dLgDZnK&oR9^CLdmLUzbgC5jbYuba&vEbQCrleG4lCPVdvh ze*$9@K)#w3vYDVOfr;v%#t^;%arC_2O?n+{kypBWYQ2*h$}wB#hmFG`Xp%`6Tgi~} zjGdg_qfPuSw2hI-Wu*%6lP`5$O7+gUMv1J01DiR!2dh-`9>Y12-XSzEiP|}xMPlP&_z^v zb(9YH{d-M-Mb`P$WCTL7Te9)=P*J>Jiey&FHe;@z2*Gy0qmMDf9b0q*E=}3=C6x=M zjjV2?7OD8l0&+Skg9Ts}e|@Y&8fiv@zaxm9k{7jSUBdoz3LlP^I|;8h$G$CrgvlW@ zh;3c-bP?n6{DV^@+vgc-gU9BFlsB*e4hAhW$|H`5I1Sh66HmVVgdiq!LNOm&&#ejw zF#{Bh!tj+c%aJm;uc}Mzwqrb_Q4KhXbH0-1$HcZ_Km08g`I6WO95Ts#1cHk+(sCK= zm3n<&GK<5WbN5b~FC1QA?oe+9Aw#R?g?7ESpa2y_gEAr|ju3x6WwJ)7<{o~(YsWcD zpa8xSMbNC~`A5w&14J*f>N&M^Hz9XR$xI?+!;HucAeOq=zEAJGd$)TDy>J?+>@d>! zEt<-SacCe+!=Oix!{@n6={|*=qbgU|B;20g{ZoTnk2 zD$@1x%x3J1<#Y3SzUVPghC5vOwS$N!cbtgTh89_5$E)KfWT!H&T+GF6<3w{zNKf6K zTfH)J`3={NrW#3QE^+Ou)3@CF7A2AdSTkm@Y%*F#jILQb9^tXt^zud~=w8nc)N>-* z&kt=JPl!UU1~O(SDU{{_`f4QKT+A94HWQH)`TR}cov#D{z@1%el?v|mYJBsi`WTl8 zn<7c zyu&h+>y~|9aCO(j9j(`ta2INi0Rz?1b#uJ)%n z<2fNX^XH48uv_Qzifmwv7-~b6Tj7(W9gAZ%>ZeS6;46iMAMW9LdVK%a-gN~um37?| zAcM5IpeWr50l`sPs7i4(lmOCn08xqpVGwB|RZ7tDBMu`aW`GC-DD6X&OVg z1so6yp+rzR0@4YP?*NYT@IU`=!$ThK4JWxb=kC4sTI-zc%vx|=NJ}+3O+5bKIN)%_v2EdQ){=mnw;{ewEy7j1d3cW#4J zgjCBy)pR2|AoE>sIK>UXZ#3^XPxvK(qGJOs2reNq&MvK^Mu(UgIu%%S0Ca#UGxou> zYA$ttGcB-@Ocy4`e-78V{yExM75_T-fyhccc8qd)3MHTyI63xeA@pm-t zDv(#Q)=!uCE3_TjUuP82>hJ~nUM}G08wUlLR>q#XmT@>2hK*Fa4j6Rw8Rg-f7bhd zIjPNrdpoVmL@;7k!TqNeK0GTr;YMBi{d3zC3Y{Rhm@B;Dj+)G3KB$#V1{6`smzs@E zX#1Xey(;>#q`yq})Poo!oue!aXfuZPBQ;99CYjS~&t9!{Wl!7RxV=y(cSK!tJG~Rg zx8C%?T8yfpZW+;X5PG#QCcH`1PScgHP5jS4szk+QDjA*yOiw6|cB{Fw)c;a&FZfAvfol^J|g z^IAD8^^BKOUu4ehTYBZeS1n`*e$W(dMAkygf%fp5*4*Q$7%9+O$d|doK{cI9(CP{h zpV`M5M6!rGWOF5+x`ltPdhrQhgE%5~b0@&3fQ zhpCf*Osw69m&CdWW!+*Dv+oShI*$J*c;GTNt^<)VuNgSWVZr8FbBrWFscob(^?r5C z>U7rn`<6+|?ZaB3Cv-%hN{Jxl8I5}`{u{D0YM?a=$8kUqtfRUu*HjM*N|`aSci3ft zdvY_sLX#m{_uinUmeAjeRG&B=r7w~3_Pnt!-k8pGmwvh)CmP|onI}7>p2pG%#g`Xx z4LC#5wRzRm82-0_WNAZA2}Kn_mHUDOW{z=kp~>Aa89v1D&h24MiLPPvMcxMf;K_J? z)#|G{=^5<71apJPVr|5 zPWA`CyFgoa1UQ11yJ#X?gIzvHx}>Zxtb$KNEfzb8?K#`K`PI@&*|+JUyNga5x^M(r zH}__1JKG;v6plJc+m%&y6!xbYT12W?cPm*X|@g-Ds)5c^0myO(KYVe2E z=@|UrOC-x6C)k3XFTV>?z#2CsUxj{QamaKtd(z`u z4$5K5_sp9>MLI`SKxbC>gkdquNBw3LsL12m`q%)Hp&q^+?7;zPD&os;&|+}3Aya6U zU8rzxWz_JGm77c!dY>KTWxdy)x=A1#-#NMSZRD>_ zqIGA;mfi)dB#ms8O}_AFo)e|tm7OCP{mcEIyE4r#TKk^$_&UR*((WK@IsBWyyh3h= z8C;7P?HyP{8E1ulG7+BKamJQu|3odwg><3!5{)*3-EAk(#uHroZ6#xux$67Fn)rT4 z^}xFYDFwAC#i{?$& zQEzC?U1L7lH4|pJKxI{}MrUYcPKhud`BDPNOtOiCpM4r+)Zk`=5zR;*(q0`8>;7(4 z=OfRSUk&pq7qre<#`Lm)yCGXq^+#&IUB}t#eBnh_8=7J#u9{FkX-nyUTb`yZ3svgQ zm~vuU9-SP~43r+zEVy=U8%2W)8+A_l{A_`%O6;*oq`fbf;i}woCLPf6>d;c0s-ZR0 zEG)-ds3NChbTRVn2+zODNE31H3Anw6iu0(SY`fC-v!6IYUha-NkdnaM=la#AEq-D(6L6AfTPc!)%oyw7QW$OZoal zT|#d25~jp}ZM!0o7TMAw%DGZ2xBryKY0Fa^o?0O#NN?)>*n>x^SCuq0$46I==0`^V zt`x@(!zg2x?9+rtu>rX!@oyVJ^HQ=4;o!~@WvEhe#@j=BeZM01T5I)ej1wBcK*gwzODNsZG+!D6~svB$4GeQ;g}Mg2GtHuie9{0^gP-OCS- z{*yn_`YO;0@Pp+v{ST_Er4rBpwpt*T$&4vu+a%LU{JQz5POqojn2*RI=p<}ffg09s zsZJOFdQV~#uv(aP?_z}9?5J)(oBi&ST}Mo;0t7U+51PLWoo38kSJawY)T|XNF8ODs zns?s1mc!%;xZw_nuI1(_$i?_zxoDQdU0g5P5R6TE(?+Ha1{INE54H(O(@f zVZ0$zBeJYA^V1Y-HrlYz0Hy{4`<79(Xywexn>*_YAcl$*4xwoo0Tmu z3Iwzv?cSJJ2Nw6?;^lxoCm<9V4ja6=ePAd=Xy&`sj7GNwbqNxguMQ@P^qFoa z{Z0*8A;Y}B6y}qX2TSa$(<4~WXnvi=b(4V9`9uqa18gy%3934=;%*GZ9H2m4d^!q^ z+(9;YqzPx%o4Z(r`~x!IGQ?N)l4dkP+k5<+4WahV!ZZ(8YOPwtuF25yjC&BZZp_)q z*~eUoXsS%g75<>tidjpEPyc4wv%X@^g=-X;(y$r)+Y7QLw5?=Qnc=35!;Fx`MFZqU zS;*Bol@Veq_Komd0|ouYp1R9?ymKbNqifj2bNk|5F5Q@4`VJrnH-Mr5$-+QP z0DwR$Xv@0_&j0ltGx8j3=&xR&LUAlPqljU22G<(9I__Y9K3H&zv)dlUNEPJzYHaKf z=SjBc8O#>3v4u83Ut#1FR4Ko%v|f-+!N8+YHl$031<0MvWfrF-Ea|VfX#&G2VyzsF z;CrSNWvG$ERpYlV{b->?7JA}?BF66nr(Su!E@pRM<~;sMr)gHwrDH4%Ro}=*{cAR; zFT1l_W$T0J+CAlyTl$z#{8BdnSn~2)01F;nw(e77cdO*{6Cu#t9vc*r?wR_$O91`^ zN5b8%Nv6_b9ei#irU>q1{%QwY@0w^K?H*XpzF8}MP21Sbj5iX)j)4Q43?z$XbPLx^ zmYm>)xk}zROoxx>NinpaXY)UnT*d}PZVt=7&EO4fhooPJ zm0=xtC@=a#@zmMXrZZJ2Jh4vh+0lLYa!jEYWdv9B>H&Vx5BRWEnUNj<)IPTY*3M;U zW)U%LV9#23s)DUEc><0F43c$Aa*r)4)2EQEF&+v1g-c(<76C&gz;vLLhsd@2-vU4{6U~ zw(2jd3xatf{ut61u91t-^)^c(6q|bwI~}^U;mESO5qmX1ov9@d(BTC3dqYry81CZRJteU1pIXu9fTQVG7oF#-_=Gs+x$ zuw~TyX*3vRQ9xY(0hkT+=e@gtU-1pL4$Tup1dQ2jxrBqVTb0GU_6Zy>8P{(qwKkwc zRG0`jNzbpOGsW!RTuGwEsA5U2=&o9+bb{|ZsnG!rV-(0u|I~Ns2nl(Cyb0Z>MecNN zMut=*4rePUO-`dw0*YkP4<~m*I4nDSAD%2Eu~jW(n~igLdhy3b71o|Ssk0~3pWBBW zMu9}%x@jL2pULWZ2wIl}iOnRG^DC33ZL=r94sxgzK2qZ#OkWspq-F2{v-UezVJo_J z3mA$;WdTdaWlXYZqd0SgBmflU__GuX4-{z|+%M2#F=+_MA%xgPYQH^)ZcNeZx$KW=o z@`DE#*aFFcdB8SzL3l0mGm{rVdR*)WF2c-}($43I7RAcvNB6r6l=4O6i9Vs4hUCt- znI~B70>9<=KipZ+%NtM`S>26o#pFyh12vXC4-lA$M+ya`BraGw%g6}I= z(X8VuNMNSmn&;ZHRKkr)f2tVvboWFuw#jSQpica5L2fKh@P-CtEsWG_ zQ;gBLPUj0cNpX7#rsF|jd>7%R4HT?YaI)oUUy>R7OH<#8CeMr1xAI=jMEtB-|tVRzGwik)DhTbmp1(ioi!FM8RdtZ|1PLDqjbK! z#_g~0YU=>M&)+zCD})-s+pdW1kWP=*nhM>hHR9>)1H@t5I|FO|P(Dal+>5 zV%!(Y!}b6UVqeJat$zjI> 3); - - return ret; -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ -/** @} */ + +/** + * @file drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_firebull_stm32f103.h + * @brief GINPUT ouch low level driver source for the ADS7843 on the FireBull STM32F103-FB board. + * + * @defgroup Mouse Mouse + * @ingroup GINPUT + * @{ + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +static const SPIConfig spicfg = { + NULL, + GPIOC, + 6, + /* SPI_CR1_BR_2 |*/ SPI_CR1_BR_1 | SPI_CR1_BR_0, +}; + +/** + * @brief Initialise the board for the touch. + * + * @notapi + */ +static inline void init_board(void) { + spiStart(&SPID1, &spicfg); +} + +/** + * @brief Check whether the surface is currently touched + * @return TRUE if the surface is currently touched + * + * @notapi + */ +static inline bool_t getpin_pressed(void) { + return (!palReadPad(GPIOC, 4)); +} +/** + * @brief Aquire the bus ready for readings + * + * @notapi + */ +static inline void aquire_bus(void) { + spiAcquireBus(&SPID1); + //TOUCHSCREEN_SPI_PROLOGUE(); + palClearPad(GPIOC, 6); +} + +/** + * @brief Release the bus after readings + * + * @notapi + */ +static inline void release_bus(void) { + palSetPad(GPIOC, 6); + spiReleaseBus(&SPID1); + //TOUCHSCREEN_SPI_EPILOGUE(); +} + +/** + * @brief Read a value from touch controller + * @return The value read from the controller + * + * params[in] port The controller port to read. + * + * @notapi + */ +static inline uint16_t read_value(uint16_t port) { + static uint8_t txbuf[3] = {0}; + static uint8_t rxbuf[3] = {0}; + uint16_t ret; + + txbuf[0] = port; + + spiExchange(&SPID1, 3, txbuf, rxbuf); + + ret = (rxbuf[1] << 5) | (rxbuf[2] >> 3); + + return ret; +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ +/** @} */ diff --git a/drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h b/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h similarity index 95% rename from drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h rename to boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h index 01572f0d..e0ab85dc 100644 --- a/drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h +++ b/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h @@ -4,87 +4,87 @@ * * http://ugfx.org/license.html */ - -/** - * @file drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h - * @brief GINPUT Touch low level driver source for the ADS7843 on an Olimex STM32E407. - * - * @defgroup Mouse Mouse - * @ingroup GINPUT - * @{ - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -static const SPIConfig spicfg = { - NULL, - GPIOG, - 10, - /* SPI_CR1_BR_2 |*/ SPI_CR1_BR_1 | SPI_CR1_BR_0, -}; - -/** - * @brief Initialise the board for the touch. - * - * @notapi - */ -static inline void init_board(void) { - spiStart(&SPID2, &spicfg); -} - -/** - * @brief Check whether the surface is currently touched - * @return TRUE if the surface is currently touched - * - * @notapi - */ -static inline bool_t getpin_pressed(void) { - return (!palReadPad(GPIOG, 0)); -} -/** - * @brief Aquire the bus ready for readings - * - * @notapi - */ -static inline void aquire_bus(void) { - spiAcquireBus(&SPID2); - //TOUCHSCREEN_SPI_PROLOGUE(); - palClearPad(GPIOG, 10); -} - -/** - * @brief Release the bus after readings - * - * @notapi - */ -static inline void release_bus(void) { - palSetPad(GPIOG, 10); - spiReleaseBus(&SPID2); - //TOUCHSCREEN_SPI_EPILOGUE(); -} - -/** - * @brief Read a value from touch controller - * @return The value read from the controller - * - * params[in] port The controller port to read. - * - * @notapi - */ -static inline uint16_t read_value(uint16_t port) { - static uint8_t txbuf[3] = {0}; - static uint8_t rxbuf[3] = {0}; - uint16_t ret; - - txbuf[0] = port; - - spiExchange(&SPID2, 3, txbuf, rxbuf); - - ret = (rxbuf[1] << 5) | (rxbuf[2] >> 3); - - return ret; -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ -/** @} */ + +/** + * @file drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_olimex_stm32_e407.h + * @brief GINPUT Touch low level driver source for the ADS7843 on an Olimex STM32E407. + * + * @defgroup Mouse Mouse + * @ingroup GINPUT + * @{ + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +static const SPIConfig spicfg = { + NULL, + GPIOG, + 10, + /* SPI_CR1_BR_2 |*/ SPI_CR1_BR_1 | SPI_CR1_BR_0, +}; + +/** + * @brief Initialise the board for the touch. + * + * @notapi + */ +static inline void init_board(void) { + spiStart(&SPID2, &spicfg); +} + +/** + * @brief Check whether the surface is currently touched + * @return TRUE if the surface is currently touched + * + * @notapi + */ +static inline bool_t getpin_pressed(void) { + return (!palReadPad(GPIOG, 0)); +} +/** + * @brief Aquire the bus ready for readings + * + * @notapi + */ +static inline void aquire_bus(void) { + spiAcquireBus(&SPID2); + //TOUCHSCREEN_SPI_PROLOGUE(); + palClearPad(GPIOG, 10); +} + +/** + * @brief Release the bus after readings + * + * @notapi + */ +static inline void release_bus(void) { + palSetPad(GPIOG, 10); + spiReleaseBus(&SPID2); + //TOUCHSCREEN_SPI_EPILOGUE(); +} + +/** + * @brief Read a value from touch controller + * @return The value read from the controller + * + * params[in] port The controller port to read. + * + * @notapi + */ +static inline uint16_t read_value(uint16_t port) { + static uint8_t txbuf[3] = {0}; + static uint8_t rxbuf[3] = {0}; + uint16_t ret; + + txbuf[0] = port; + + spiExchange(&SPID2, 3, txbuf, rxbuf); + + ret = (rxbuf[1] << 5) | (rxbuf[2] >> 3); + + return ret; +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ +/** @} */ diff --git a/drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_st_stm32f4_discovery.h b/boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_st_stm32f4_discovery.h similarity index 100% rename from drivers/ginput/touch/ADS7843/ginput_lld_mouse_board_st_stm32f4_discovery.h rename to boards/addons/ginput/touch/ADS7843/ginput_lld_mouse_board_st_stm32f4_discovery.h diff --git a/drivers/ginput/touch/FT5x06/ginput_lld_mouse_board_marlin.h b/boards/addons/ginput/touch/FT5x06/ginput_lld_mouse_board_marlin.h similarity index 100% rename from drivers/ginput/touch/FT5x06/ginput_lld_mouse_board_marlin.h rename to boards/addons/ginput/touch/FT5x06/ginput_lld_mouse_board_marlin.h diff --git a/drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h b/boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h similarity index 95% rename from drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h rename to boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h index c4689ecb..a7435c95 100644 --- a/drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h +++ b/boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_pic32mx_lcd.h @@ -4,148 +4,148 @@ * * http://ugfx.org/license.html */ - -/** - * @file drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h - * @brief GINPUT Touch low level driver source for the MCU on the example board. - * - * @defgroup Mouse Mouse - * @ingroup GINPUT - * - * @{ - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -static const ADCConfig ADCC = { - .vref = ADC_VREF_CFG_AVDD_AVSS, - .stime = 15, - .irq = EIC_IRQ_ADC, - .base = _ADC10_BASE_ADDRESS, -}; -static struct ADCDriver ADCD; - -#define YNEG 13 // U -#define XNEG 15 // R -#define XPOS 12 // L -#define YPOS 11 // D - -#define ADC_MAX 1023 - -#define TOUCH_THRESHOULD 50 - -static const ADCConversionGroup ADC_X_CG = { - .circular = FALSE, - .num_channels = 1, - .channels = 1 << XNEG, -}; - -static const ADCConversionGroup ADC_Y_CG = { - .circular = FALSE, - .num_channels = 1, - .channels = 1 << YPOS, -}; - -/** - * @brief Initialise the board for the touch. - * - * @notapi - */ -static inline void init_board(void) { - adcObjectInit(&ADCD); - adcStart(&ADCD, &ADCC); -} - -/** - * @brief Check whether the surface is currently touched - * @return TRUE if the surface is currently touched - * - * @notapi - */ -static inline bool_t getpin_pressed(void) { - adcsample_t samples[2] = {0, }; - - // Set X+ to ground - palSetPadMode(IOPORTB, XPOS, PAL_MODE_OUTPUT); - palClearPad(IOPORTB, XPOS); - - // Set Y- to VCC - palSetPadMode(IOPORTB, YNEG, PAL_MODE_OUTPUT); - palSetPad(IOPORTB, YNEG); - - palSetPadMode(IOPORTB, XNEG, PAL_MODE_INPUT_ANALOG); - palSetPadMode(IOPORTB, YPOS, PAL_MODE_INPUT_ANALOG); - - adcConvert(&ADCD, &ADC_X_CG, &samples[0], 1); - adcConvert(&ADCD, &ADC_Y_CG, &samples[1], 1); - - return (ADC_MAX - (samples[1] - samples[0])) > TOUCH_THRESHOULD; -} - -/** - * @brief Aquire the bus ready for readings - * - * @notapi - */ -static inline void aquire_bus(void) { -} - -/** - * @brief Release the bus after readings - * - * @notapi - */ -static inline void release_bus(void) { -} - -/** - * @brief Read an x value from touch controller - * @return The value read from the controller - * - * @notapi - */ -static inline uint16_t read_x_value(void) { - adcsample_t sample; - - palSetPadMode(IOPORTB, XPOS, PAL_MODE_OUTPUT); - palSetPad(IOPORTB, XPOS); - - palSetPadMode(IOPORTB, XNEG, PAL_MODE_OUTPUT); - palClearPad(IOPORTB, XNEG); - - palSetPadMode(IOPORTB, YNEG, PAL_MODE_INPUT); - - palSetPadMode(IOPORTB, YPOS, PAL_MODE_INPUT_ANALOG); - - adcConvert(&ADCD, &ADC_Y_CG, &sample, 1); - - return ADC_MAX - sample; -} - -/** - * @brief Read an y value from touch controller - * @return The value read from the controller - * - * @notapi - */ -static inline uint16_t read_y_value(void) { - adcsample_t sample; - - palSetPadMode(IOPORTB, YNEG, PAL_MODE_OUTPUT); - palClearPad(IOPORTB, YNEG); - - palSetPadMode(IOPORTB, YPOS, PAL_MODE_OUTPUT); - palSetPad(IOPORTB, YPOS); - - palSetPadMode(IOPORTB, XPOS, PAL_MODE_INPUT); - - palSetPadMode(IOPORTB, XNEG, PAL_MODE_INPUT_ANALOG); - - adcConvert(&ADCD, &ADC_X_CG, &sample, 1); - - return ADC_MAX - sample; -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ -/** @} */ + +/** + * @file drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h + * @brief GINPUT Touch low level driver source for the MCU on the example board. + * + * @defgroup Mouse Mouse + * @ingroup GINPUT + * + * @{ + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +static const ADCConfig ADCC = { + .vref = ADC_VREF_CFG_AVDD_AVSS, + .stime = 15, + .irq = EIC_IRQ_ADC, + .base = _ADC10_BASE_ADDRESS, +}; +static struct ADCDriver ADCD; + +#define YNEG 13 // U +#define XNEG 15 // R +#define XPOS 12 // L +#define YPOS 11 // D + +#define ADC_MAX 1023 + +#define TOUCH_THRESHOULD 50 + +static const ADCConversionGroup ADC_X_CG = { + .circular = FALSE, + .num_channels = 1, + .channels = 1 << XNEG, +}; + +static const ADCConversionGroup ADC_Y_CG = { + .circular = FALSE, + .num_channels = 1, + .channels = 1 << YPOS, +}; + +/** + * @brief Initialise the board for the touch. + * + * @notapi + */ +static inline void init_board(void) { + adcObjectInit(&ADCD); + adcStart(&ADCD, &ADCC); +} + +/** + * @brief Check whether the surface is currently touched + * @return TRUE if the surface is currently touched + * + * @notapi + */ +static inline bool_t getpin_pressed(void) { + adcsample_t samples[2] = {0, }; + + // Set X+ to ground + palSetPadMode(IOPORTB, XPOS, PAL_MODE_OUTPUT); + palClearPad(IOPORTB, XPOS); + + // Set Y- to VCC + palSetPadMode(IOPORTB, YNEG, PAL_MODE_OUTPUT); + palSetPad(IOPORTB, YNEG); + + palSetPadMode(IOPORTB, XNEG, PAL_MODE_INPUT_ANALOG); + palSetPadMode(IOPORTB, YPOS, PAL_MODE_INPUT_ANALOG); + + adcConvert(&ADCD, &ADC_X_CG, &samples[0], 1); + adcConvert(&ADCD, &ADC_Y_CG, &samples[1], 1); + + return (ADC_MAX - (samples[1] - samples[0])) > TOUCH_THRESHOULD; +} + +/** + * @brief Aquire the bus ready for readings + * + * @notapi + */ +static inline void aquire_bus(void) { +} + +/** + * @brief Release the bus after readings + * + * @notapi + */ +static inline void release_bus(void) { +} + +/** + * @brief Read an x value from touch controller + * @return The value read from the controller + * + * @notapi + */ +static inline uint16_t read_x_value(void) { + adcsample_t sample; + + palSetPadMode(IOPORTB, XPOS, PAL_MODE_OUTPUT); + palSetPad(IOPORTB, XPOS); + + palSetPadMode(IOPORTB, XNEG, PAL_MODE_OUTPUT); + palClearPad(IOPORTB, XNEG); + + palSetPadMode(IOPORTB, YNEG, PAL_MODE_INPUT); + + palSetPadMode(IOPORTB, YPOS, PAL_MODE_INPUT_ANALOG); + + adcConvert(&ADCD, &ADC_Y_CG, &sample, 1); + + return ADC_MAX - sample; +} + +/** + * @brief Read an y value from touch controller + * @return The value read from the controller + * + * @notapi + */ +static inline uint16_t read_y_value(void) { + adcsample_t sample; + + palSetPadMode(IOPORTB, YNEG, PAL_MODE_OUTPUT); + palClearPad(IOPORTB, YNEG); + + palSetPadMode(IOPORTB, YPOS, PAL_MODE_OUTPUT); + palSetPad(IOPORTB, YPOS); + + palSetPadMode(IOPORTB, XPOS, PAL_MODE_INPUT); + + palSetPadMode(IOPORTB, XNEG, PAL_MODE_INPUT_ANALOG); + + adcConvert(&ADCD, &ADC_X_CG, &sample, 1); + + return ADC_MAX - sample; +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ +/** @} */ diff --git a/drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h b/boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h similarity index 96% rename from drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h rename to boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h index 2cc58f3c..ca177a89 100644 --- a/drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h +++ b/boards/addons/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h @@ -1,152 +1,152 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h - * @brief GINPUT Touch low level driver source for the MCU on the example board. - * - * @defgroup Mouse Mouse - * @ingroup GINPUT - * - * @{ - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -#define ADC_NUM_CHANNELS 2 -#define ADC_BUF_DEPTH 1 - -static const ADCConversionGroup adc_y_config = { - FALSE, - ADC_NUM_CHANNELS, - NULL, - NULL, - 0, 0, - 0, 0, - ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), - 0, - ADC_SQR3_SQ2_N(ADC_CHANNEL_IN12) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN13) -}; - -static const ADCConversionGroup adc_x_config = { - FALSE, - ADC_NUM_CHANNELS, - NULL, - NULL, - 0, 0, - 0, 0, - ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), - 0, - ADC_SQR3_SQ2_N(ADC_CHANNEL_IN10) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN11) -}; - -/** - * @brief Initialise the board for the touch. - * - * @notapi - */ -static inline void init_board(void) { - adcStart(&ADCD1, NULL); -} - -/** - * @brief Check whether the surface is currently touched - * @return TRUE if the surface is currently touched - * - * @notapi - */ -static inline bool_t getpin_pressed(void) { - palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_PULLDOWN); - palSetPadMode(GPIOC, 1, PAL_MODE_INPUT); - palSetPadMode(GPIOC, 2, PAL_MODE_INPUT); - palSetPadMode(GPIOC, 3, PAL_MODE_OUTPUT_PUSHPULL); - palSetPad(GPIOC, 3); - - return palReadPad(GPIOC, 0); -} - -/** - * @brief Aquire the bus ready for readings - * - * @notapi - */ -static inline void aquire_bus(void) { - -} - -/** - * @brief Release the bus after readings - * - * @notapi - */ -static inline void release_bus(void) { - -} - -/** - * @brief Read an x value from touch controller - * @return The value read from the controller - * - * @notapi - */ -static inline uint16_t read_x_value(void) { - uint16_t val1, val2; - adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; - - palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 2, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOC, 3, PAL_MODE_OUTPUT_PUSHPULL); - - palSetPad(GPIOC, 2); - palClearPad(GPIOC, 3); - gfxSleepMilliseconds(1); - adcConvert(&ADCD1, &adc_x_config, samples, ADC_BUF_DEPTH); - val1 = ((samples[0] + samples[1])/2); - - palClearPad(GPIOC, 2); - palSetPad(GPIOC, 3); - gfxSleepMilliseconds(1); - adcConvert(&ADCD1, &adc_x_config, samples, ADC_BUF_DEPTH); - val2 = ((samples[0] + samples[1])/2); - - return ((val1+((1<<12)-val2))/4); -} - -/** - * @brief Read an y value from touch controller - * @return The value read from the controller - * - * @notapi - */ -static inline uint16_t read_y_value(void) { - uint16_t val1, val2; - adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; - - palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); - palSetPadMode(GPIOC, 0, PAL_MODE_OUTPUT_PUSHPULL); - palSetPadMode(GPIOC, 1, PAL_MODE_OUTPUT_PUSHPULL); - - palSetPad(GPIOC, 1); - palClearPad(GPIOC, 0); - gfxSleepMilliseconds(1); - adcConvert(&ADCD1, &adc_y_config, samples, ADC_BUF_DEPTH); - val1 = ((samples[0] + samples[1])/2); - - palClearPad(GPIOC, 1); - palSetPad(GPIOC, 0); - gfxSleepMilliseconds(1); - adcConvert(&ADCD1, &adc_y_config, samples, ADC_BUF_DEPTH); - val2 = ((samples[0] + samples[1])/2); - - return ((val1+((1<<12)-val2))/4); -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ -/** @} */ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/ginput/touch/MCU/ginput_lld_mouse_board_olimex_stm32_lcd.h + * @brief GINPUT Touch low level driver source for the MCU on the example board. + * + * @defgroup Mouse Mouse + * @ingroup GINPUT + * + * @{ + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +#define ADC_NUM_CHANNELS 2 +#define ADC_BUF_DEPTH 1 + +static const ADCConversionGroup adc_y_config = { + FALSE, + ADC_NUM_CHANNELS, + NULL, + NULL, + 0, 0, + 0, 0, + ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), + 0, + ADC_SQR3_SQ2_N(ADC_CHANNEL_IN12) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN13) +}; + +static const ADCConversionGroup adc_x_config = { + FALSE, + ADC_NUM_CHANNELS, + NULL, + NULL, + 0, 0, + 0, 0, + ADC_SQR1_NUM_CH(ADC_NUM_CHANNELS), + 0, + ADC_SQR3_SQ2_N(ADC_CHANNEL_IN10) | ADC_SQR3_SQ1_N(ADC_CHANNEL_IN11) +}; + +/** + * @brief Initialise the board for the touch. + * + * @notapi + */ +static inline void init_board(void) { + adcStart(&ADCD1, NULL); +} + +/** + * @brief Check whether the surface is currently touched + * @return TRUE if the surface is currently touched + * + * @notapi + */ +static inline bool_t getpin_pressed(void) { + palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_PULLDOWN); + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT); + palSetPadMode(GPIOC, 2, PAL_MODE_INPUT); + palSetPadMode(GPIOC, 3, PAL_MODE_OUTPUT_PUSHPULL); + palSetPad(GPIOC, 3); + + return palReadPad(GPIOC, 0); +} + +/** + * @brief Aquire the bus ready for readings + * + * @notapi + */ +static inline void aquire_bus(void) { + +} + +/** + * @brief Release the bus after readings + * + * @notapi + */ +static inline void release_bus(void) { + +} + +/** + * @brief Read an x value from touch controller + * @return The value read from the controller + * + * @notapi + */ +static inline uint16_t read_x_value(void) { + uint16_t val1, val2; + adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; + + palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 2, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOC, 3, PAL_MODE_OUTPUT_PUSHPULL); + + palSetPad(GPIOC, 2); + palClearPad(GPIOC, 3); + gfxSleepMilliseconds(1); + adcConvert(&ADCD1, &adc_x_config, samples, ADC_BUF_DEPTH); + val1 = ((samples[0] + samples[1])/2); + + palClearPad(GPIOC, 2); + palSetPad(GPIOC, 3); + gfxSleepMilliseconds(1); + adcConvert(&ADCD1, &adc_x_config, samples, ADC_BUF_DEPTH); + val2 = ((samples[0] + samples[1])/2); + + return ((val1+((1<<12)-val2))/4); +} + +/** + * @brief Read an y value from touch controller + * @return The value read from the controller + * + * @notapi + */ +static inline uint16_t read_y_value(void) { + uint16_t val1, val2; + adcsample_t samples[ADC_NUM_CHANNELS * ADC_BUF_DEPTH]; + + palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 0, PAL_MODE_OUTPUT_PUSHPULL); + palSetPadMode(GPIOC, 1, PAL_MODE_OUTPUT_PUSHPULL); + + palSetPad(GPIOC, 1); + palClearPad(GPIOC, 0); + gfxSleepMilliseconds(1); + adcConvert(&ADCD1, &adc_y_config, samples, ADC_BUF_DEPTH); + val1 = ((samples[0] + samples[1])/2); + + palClearPad(GPIOC, 1); + palSetPad(GPIOC, 0); + gfxSleepMilliseconds(1); + adcConvert(&ADCD1, &adc_y_config, samples, ADC_BUF_DEPTH); + val2 = ((samples[0] + samples[1])/2); + + return ((val1+((1<<12)-val2))/4); +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ +/** @} */ diff --git a/drivers/ginput/touch/STMPE811/ginput_lld_mouse_board_embest_dmstf4bb.h b/boards/addons/ginput/touch/STMPE811/ginput_lld_mouse_board_embest_dmstf4bb.h similarity index 95% rename from drivers/ginput/touch/STMPE811/ginput_lld_mouse_board_embest_dmstf4bb.h rename to boards/addons/ginput/touch/STMPE811/ginput_lld_mouse_board_embest_dmstf4bb.h index 7246378d..a2d38d34 100644 --- a/drivers/ginput/touch/STMPE811/ginput_lld_mouse_board_embest_dmstf4bb.h +++ b/boards/addons/ginput/touch/STMPE811/ginput_lld_mouse_board_embest_dmstf4bb.h @@ -4,123 +4,123 @@ * * http://ugfx.org/license.html */ - -/** - * @file drivers/ginput/touch/STMPE811/ginput_lld_mouse_board_embest_dmstf4bb.h - * @brief GINPUT Touch low level driver source for the STMPE811 on the Embest DM-STF4BB board. - * - * @defgroup Mouse Mouse - * @ingroup GINPUT - * @{ - */ - -#ifndef _GINPUT_LLD_MOUSE_BOARD_H -#define _GINPUT_LLD_MOUSE_BOARD_H - -static const I2CConfig i2ccfg = { - OPMODE_I2C, - 400000, - FAST_DUTY_CYCLE_2, -}; - -/** - * @brief Initialise the board for the touch. - * - * @notapi - */ -static void init_board(void) -{ - palSetPadMode(GPIOC, 13, PAL_MODE_INPUT | PAL_STM32_PUDR_FLOATING); /* TP IRQ */ - palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SCL */ - palSetPadMode(GPIOB, 9, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SDA */ - - i2cStart(&I2CD1, &i2ccfg); -} - -/** - * @brief Check whether an interrupt is raised - * @return TRUE if there is an interrupt signal present - * - * @notapi - */ -static inline bool_t getpin_irq(void) { - return (!(palReadPad(GPIOC, 13))); -} - -/** - * @brief Write a value into a certain register - * - * @param[in] reg The register address - * @param[in] n The amount of bytes (one or two) - * @param[in] val The value - * - * @notapi - */ -static void write_reg(uint8_t reg, uint8_t n, uint16_t val) -{ - uint8_t txbuf[3]; - - i2cAcquireBus(&I2CD1); - - txbuf[0] = reg; - - if (n == 1) { - txbuf[1] = val; - i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 2, NULL, 0, MS2ST(STMPE811_TIMEOUT)); - } else if (n == 2) { - txbuf[1] = ((val & 0xFF00) >> 8); - txbuf[2] = (val & 0x00FF); - i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 3, NULL, 0, MS2ST(STMPE811_TIMEOUT)); - } - - i2cReleaseBus(&I2CD1); -} - -/** - * @brief Read the value of a certain register - * - * @param[in] reg The register address - * @param[in] n The amount of bytes (one or two) - * - * @return Data read from device (one byte or two depending on n param) - * - * @notapi - */ -static uint16_t read_reg(uint8_t reg, uint8_t n) -{ - uint8_t txbuf[1], rxbuf[2]; - uint16_t ret; - - rxbuf[0] = 0; - rxbuf[1] = 0; - - i2cAcquireBus(&I2CD1); - - txbuf[0] = reg; - i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 1, rxbuf, n, MS2ST(STMPE811_TIMEOUT)); - - if (n == 1) { - ret = rxbuf[0]; - } else if (n == 2) { - ret = ((rxbuf[0] << 8) | (rxbuf[1] & 0xFF)); - } - - i2cReleaseBus(&I2CD1); - - return ret; -} - -static void read_reg_n(uint8_t reg, uint8_t n, uint8_t *rxbuf) -{ - uint8_t txbuf[1]; - - i2cAcquireBus(&I2CD1); - - txbuf[0] = reg; - i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 1, rxbuf, n, MS2ST(STMPE811_TIMEOUT)); - - i2cReleaseBus(&I2CD1); -} - -#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ -/** @} */ + +/** + * @file drivers/ginput/touch/STMPE811/ginput_lld_mouse_board_embest_dmstf4bb.h + * @brief GINPUT Touch low level driver source for the STMPE811 on the Embest DM-STF4BB board. + * + * @defgroup Mouse Mouse + * @ingroup GINPUT + * @{ + */ + +#ifndef _GINPUT_LLD_MOUSE_BOARD_H +#define _GINPUT_LLD_MOUSE_BOARD_H + +static const I2CConfig i2ccfg = { + OPMODE_I2C, + 400000, + FAST_DUTY_CYCLE_2, +}; + +/** + * @brief Initialise the board for the touch. + * + * @notapi + */ +static void init_board(void) +{ + palSetPadMode(GPIOC, 13, PAL_MODE_INPUT | PAL_STM32_PUDR_FLOATING); /* TP IRQ */ + palSetPadMode(GPIOB, 8, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SCL */ + palSetPadMode(GPIOB, 9, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN); /* SDA */ + + i2cStart(&I2CD1, &i2ccfg); +} + +/** + * @brief Check whether an interrupt is raised + * @return TRUE if there is an interrupt signal present + * + * @notapi + */ +static inline bool_t getpin_irq(void) { + return (!(palReadPad(GPIOC, 13))); +} + +/** + * @brief Write a value into a certain register + * + * @param[in] reg The register address + * @param[in] n The amount of bytes (one or two) + * @param[in] val The value + * + * @notapi + */ +static void write_reg(uint8_t reg, uint8_t n, uint16_t val) +{ + uint8_t txbuf[3]; + + i2cAcquireBus(&I2CD1); + + txbuf[0] = reg; + + if (n == 1) { + txbuf[1] = val; + i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 2, NULL, 0, MS2ST(STMPE811_TIMEOUT)); + } else if (n == 2) { + txbuf[1] = ((val & 0xFF00) >> 8); + txbuf[2] = (val & 0x00FF); + i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 3, NULL, 0, MS2ST(STMPE811_TIMEOUT)); + } + + i2cReleaseBus(&I2CD1); +} + +/** + * @brief Read the value of a certain register + * + * @param[in] reg The register address + * @param[in] n The amount of bytes (one or two) + * + * @return Data read from device (one byte or two depending on n param) + * + * @notapi + */ +static uint16_t read_reg(uint8_t reg, uint8_t n) +{ + uint8_t txbuf[1], rxbuf[2]; + uint16_t ret; + + rxbuf[0] = 0; + rxbuf[1] = 0; + + i2cAcquireBus(&I2CD1); + + txbuf[0] = reg; + i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 1, rxbuf, n, MS2ST(STMPE811_TIMEOUT)); + + if (n == 1) { + ret = rxbuf[0]; + } else if (n == 2) { + ret = ((rxbuf[0] << 8) | (rxbuf[1] & 0xFF)); + } + + i2cReleaseBus(&I2CD1); + + return ret; +} + +static void read_reg_n(uint8_t reg, uint8_t n, uint8_t *rxbuf) +{ + uint8_t txbuf[1]; + + i2cAcquireBus(&I2CD1); + + txbuf[0] = reg; + i2cMasterTransmitTimeout(&I2CD1, STMPE811_ADDR, txbuf, 1, rxbuf, n, MS2ST(STMPE811_TIMEOUT)); + + i2cReleaseBus(&I2CD1); +} + +#endif /* _GINPUT_LLD_MOUSE_BOARD_H */ +/** @} */ diff --git a/drivers/tdisp/HD44780/tdisp_lld_board_olimex_e407.h b/boards/addons/tdisp/HD44780/tdisp_lld_board_olimex_e407.h similarity index 95% rename from drivers/tdisp/HD44780/tdisp_lld_board_olimex_e407.h rename to boards/addons/tdisp/HD44780/tdisp_lld_board_olimex_e407.h index 7eda4e38..12407356 100644 --- a/drivers/tdisp/HD44780/tdisp_lld_board_olimex_e407.h +++ b/boards/addons/tdisp/HD44780/tdisp_lld_board_olimex_e407.h @@ -1,59 +1,59 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/tdisp/HD44780/tdisp_lld_board_olimex_e407.h - * @brief TDISP driver subsystem board interface for the HD44780 display - * - * @addtogroup TDISP - * @{ - */ - -#ifndef _TDISP_LLD_BOARD_H -#define _TDISP_LLD_BOARD_H - -/* Configure these to match the hardware connections on your board */ -#define BUS_4BITS FALSE -#define PORT_DATA GPIOG -#define PORT_CTRL GPIOE -#define PIN_RS 0 -#define PIN_RW 1 -#define PIN_EN 2 - -static void init_board(void) { - palSetGroupMode(PORT_CTRL, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); - palSetGroupMode(PORT_DATA, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); - palClearPad(PORT_CTRL, PIN_RW); -} - -static void writeToLCD(uint8_t data) { - palWritePort(PORT_DATA, data); - palSetPad(PORT_CTRL, PIN_EN); - gfxSleepMicroseconds(1); - palClearPad(PORT_CTRL, PIN_EN); - gfxSleepMicroseconds(5); -} - -static void write_cmd(uint8_t data) { - palClearPad(PORT_CTRL, PIN_RS); - #if BUS_4BITS - writeToLCD(data>>4); - #endif - writeToLCD(data); -} - -static void write_data(uint8_t data) { - palSetPad(PORT_CTRL, PIN_RS); - #if BUS_4BITS - writeToLCD(data>>4); - #endif - writeToLCD(data); -} - -#endif /* _TDISP_LLD_BOARD_H */ -/** @} */ - +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/tdisp/HD44780/tdisp_lld_board_olimex_e407.h + * @brief TDISP driver subsystem board interface for the HD44780 display + * + * @addtogroup TDISP + * @{ + */ + +#ifndef _TDISP_LLD_BOARD_H +#define _TDISP_LLD_BOARD_H + +/* Configure these to match the hardware connections on your board */ +#define BUS_4BITS FALSE +#define PORT_DATA GPIOG +#define PORT_CTRL GPIOE +#define PIN_RS 0 +#define PIN_RW 1 +#define PIN_EN 2 + +static void init_board(void) { + palSetGroupMode(PORT_CTRL, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); + palSetGroupMode(PORT_DATA, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); + palClearPad(PORT_CTRL, PIN_RW); +} + +static void writeToLCD(uint8_t data) { + palWritePort(PORT_DATA, data); + palSetPad(PORT_CTRL, PIN_EN); + gfxSleepMicroseconds(1); + palClearPad(PORT_CTRL, PIN_EN); + gfxSleepMicroseconds(5); +} + +static void write_cmd(uint8_t data) { + palClearPad(PORT_CTRL, PIN_RS); + #if BUS_4BITS + writeToLCD(data>>4); + #endif + writeToLCD(data); +} + +static void write_data(uint8_t data) { + palSetPad(PORT_CTRL, PIN_RS); + #if BUS_4BITS + writeToLCD(data>>4); + #endif + writeToLCD(data); +} + +#endif /* _TDISP_LLD_BOARD_H */ +/** @} */ + diff --git a/drivers/tdisp/HD44780/tdisp_lld_board_st_stm32f4_discovery.h b/boards/addons/tdisp/HD44780/tdisp_lld_board_st_stm32f4_discovery.h similarity index 96% rename from drivers/tdisp/HD44780/tdisp_lld_board_st_stm32f4_discovery.h rename to boards/addons/tdisp/HD44780/tdisp_lld_board_st_stm32f4_discovery.h index e9a7ae33..43e161f1 100644 --- a/drivers/tdisp/HD44780/tdisp_lld_board_st_stm32f4_discovery.h +++ b/boards/addons/tdisp/HD44780/tdisp_lld_board_st_stm32f4_discovery.h @@ -1,122 +1,122 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/tdisp/HD44780/tdisp_lld_board_st_stm32f4_discovery.h - * @brief TDISP driver subsystem board interface for the HD44780 display - * - * @addtogroup TDISP - * @{ - */ - -#ifndef _TDISP_LLD_BOARD_H -#define _TDISP_LLD_BOARD_H - -/* Configure these to match the hardware connections on your board */ -#define BUS_4BITS TRUE - -/* Configure the bitoffset in the dataport so they match with the - * hardware pins. An offset of 0 means bit0 stays at bit0 of the dataport. - * If the offset is set to 3, bit0 of the nibble will be positioned at - * P[A..G]3 of the hardware-port. - */ -#define hardware_offset 3 - -/* The port where the data is sent to. In the - * low-leveldriver het hardware_offset is taken - * into account. If for example the hardware_offset - * is set to 3, then de data will be sent to - * PE3, PE4, PE5 en PE6, if the dataport where GPIOE. - */ -#define PORT_DATA GPIOE - -/* The port used to controle the controle lines of - * the display. - */ -#define PORT_CTRL GPIOD -/* Pin to controle the R/S-line of the display */ -#define PIN_RS 0 -/* Pin to controle the EN-line of the display */ -#define PIN_EN 1 -/* Pin to controle the R/W-pin of the display. - * If reading of the display is not used disable - * reading in the gfxconf.h and put a dummy value here - * as it will not be used. - */ -#define PIN_RW 7 - - -static void init_board(void) { - /* Initialize the ports for data and controle-lines */ - palSetGroupMode(PORT_CTRL, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); - palSetGroupMode(PORT_DATA, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); - /* Set alle controle pins to low */ - palClearPad(PORT_CTRL, PIN_RS); - palClearPad(PORT_CTRL, PIN_EN); - #if TDISP_NEED_READ - palClearPad(PORT_CTRL, PIN_RW); - #endif -} - -/* This is the low-level routine for sending the bits - * to the LCD-display. This routine shifts - * the bits so they match the hardware port. - */ -static void writeToLCD(uint8_t data) { - palWritePort(PORT_DATA, data<>4); - #endif - /* send the low-nibble */ - #if BUS_4BITS - /* in 4-bit mode the high-nibble is zeroed out */ - writeToLCD(data & 0x0F); - #else - writeToLCD(data); - #endif -} - -// static void write_initcmd(uint8_t data) { -// write_cmd(data); -// } - -/* Write data to the display. The - * RS-line is pulled high and than the - * data is send. - */ -static void write_data(uint8_t data) { - palSetPad(PORT_CTRL, PIN_RS); - #if BUS_4BITS - /* first send the high-nibble */ - writeToLCD(data>>4); - #endif - /* send the low-nibble */ - #if BUS_4BITS - /* in 4-bit mode the high-nibble is zeroed out */ - writeToLCD(data & 0x0F); - #else - writeToLCD(data); - #endif -} - -#endif /* _TDISP_LLD_BOARD_H */ -/** @} */ - +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file drivers/tdisp/HD44780/tdisp_lld_board_st_stm32f4_discovery.h + * @brief TDISP driver subsystem board interface for the HD44780 display + * + * @addtogroup TDISP + * @{ + */ + +#ifndef _TDISP_LLD_BOARD_H +#define _TDISP_LLD_BOARD_H + +/* Configure these to match the hardware connections on your board */ +#define BUS_4BITS TRUE + +/* Configure the bitoffset in the dataport so they match with the + * hardware pins. An offset of 0 means bit0 stays at bit0 of the dataport. + * If the offset is set to 3, bit0 of the nibble will be positioned at + * P[A..G]3 of the hardware-port. + */ +#define hardware_offset 3 + +/* The port where the data is sent to. In the + * low-leveldriver het hardware_offset is taken + * into account. If for example the hardware_offset + * is set to 3, then de data will be sent to + * PE3, PE4, PE5 en PE6, if the dataport where GPIOE. + */ +#define PORT_DATA GPIOE + +/* The port used to controle the controle lines of + * the display. + */ +#define PORT_CTRL GPIOD +/* Pin to controle the R/S-line of the display */ +#define PIN_RS 0 +/* Pin to controle the EN-line of the display */ +#define PIN_EN 1 +/* Pin to controle the R/W-pin of the display. + * If reading of the display is not used disable + * reading in the gfxconf.h and put a dummy value here + * as it will not be used. + */ +#define PIN_RW 7 + + +static void init_board(void) { + /* Initialize the ports for data and controle-lines */ + palSetGroupMode(PORT_CTRL, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); + palSetGroupMode(PORT_DATA, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); + /* Set alle controle pins to low */ + palClearPad(PORT_CTRL, PIN_RS); + palClearPad(PORT_CTRL, PIN_EN); + #if TDISP_NEED_READ + palClearPad(PORT_CTRL, PIN_RW); + #endif +} + +/* This is the low-level routine for sending the bits + * to the LCD-display. This routine shifts + * the bits so they match the hardware port. + */ +static void writeToLCD(uint8_t data) { + palWritePort(PORT_DATA, data<>4); + #endif + /* send the low-nibble */ + #if BUS_4BITS + /* in 4-bit mode the high-nibble is zeroed out */ + writeToLCD(data & 0x0F); + #else + writeToLCD(data); + #endif +} + +// static void write_initcmd(uint8_t data) { +// write_cmd(data); +// } + +/* Write data to the display. The + * RS-line is pulled high and than the + * data is send. + */ +static void write_data(uint8_t data) { + palSetPad(PORT_CTRL, PIN_RS); + #if BUS_4BITS + /* first send the high-nibble */ + writeToLCD(data>>4); + #endif + /* send the low-nibble */ + #if BUS_4BITS + /* in 4-bit mode the high-nibble is zeroed out */ + writeToLCD(data & 0x0F); + #else + writeToLCD(data); + #endif +} + +#endif /* _TDISP_LLD_BOARD_H */ +/** @} */ + diff --git a/drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h b/drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h deleted file mode 100644 index a0eed13b..00000000 --- a/drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file drivers/gdisp/ILI9341/board_ILI9341_mikromedia.h - * @brief GDISP Graphics Driver subsystem low level driver source for the ILI9341 display. - */ - -#ifndef _GDISP_LLD_BOARD_H -#define _GDISP_LLD_BOARD_H - -// For a multiple display configuration we would put all this in a structure and then -// set g->board to that structure. -#define SET_CS palSetPad(GPIOE, GPIOE_LCD_CS); -#define CLR_CS palClearPad(GPIOE, GPIOE_LCD_CS); -#define SET_RS palSetPad(GPIOE, GPIOE_LCD_RS); -#define CLR_RS palClearPad(GPIOE, GPIOE_LCD_RS); -#define SET_WR palSetPad(GPIOE, GPIOE_PMWR); -#define CLR_WR palClearPad(GPIOE, GPIOE_PMWR); -#define SET_RD palSetPad(GPIOE, GPIOE_PMRD); -#define CLR_RD palClearPad(GPIOE, GPIOE_PMRD); - -static inline void init_board(GDisplay *g) { - - // As we are not using multiple displays we set g->board to NULL as we don't use it. - g->board = 0; - - switch(g->controllerdisplay) { - case 0: // Set up for Display 0 - /* Configure the pins to a well know state */ - SET_RS; - SET_RD; - SET_WR; - CLR_CS; - - /* Hardware reset */ - palSetPad(GPIOE, GPIOE_LCD_RST); - chThdSleepMilliseconds(100); - palClearPad(GPIOE, GPIOE_LCD_RST); - chThdSleepMilliseconds(100); - palSetPad(GPIOE, GPIOE_LCD_RST); - chThdSleepMilliseconds(100); - break; - } -} - -static inline void post_init_board(GDisplay *g) { - (void) g; -} - -static inline void setpin_reset(GDisplay *g, bool_t state) { - (void) g; - if(state) { - // reset lcd - palClearPad(GPIOE, GPIOE_LCD_RST); - } else { - palSetPad(GPIOE, GPIOE_LCD_RST); - } -} - -static inline void set_backlight(GDisplay *g, uint8_t percent) { - (void) g; - // TODO: can probably pwm this - if(percent) { - // turn back light on - palSetPad(GPIOE, GPIOE_LCD_BLED); - } else { - // turn off - palClearPad(GPIOE, GPIOE_LCD_BLED); - } -} - -static inline void acquire_bus(GDisplay *g) { - (void) g; -} - -static inline void release_bus(GDisplay *g) { - (void) g; -} - -/** - * @brief Short delay - * - * @param[in] dly Length of delay - * - * @notapi - */ -static inline void ili9341_delay(uint16_t dly) { - static uint16_t i; - for(i = 0; i < dly; i++) - asm("nop"); -} - -static inline void write_index(GDisplay *g, uint16_t index) { - (void) g; - palWriteGroup(GPIOE, 0x00FF, 0, index); - CLR_RS; CLR_WR; ili9341_delay(1); SET_WR; ili9341_delay(1); SET_RS; -} - -static inline void write_data(GDisplay *g, uint16_t data) { - (void) g; - palWriteGroup(GPIOE, 0x00FF, 0, data); - CLR_WR; ili9341_delay(1); SET_WR; ili9341_delay(1); -} - -static inline void setreadmode(GDisplay *g) { - (void) g; - // change pin mode to digital input - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_INPUT); -} - -static inline void setwritemode(GDisplay *g) { - (void) g; - // change pin mode back to digital output - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); -} - -static inline uint16_t read_data(GDisplay *g) { - CLR_RD; - value = palReadPort(GPIOE); - value = palReadPort(GPIOE); - SET_RD; - return value; -} - -#endif /* _GDISP_LLD_BOARD_H */ diff --git a/drivers/ginput/touch/MCU/ginput_lld_mouse.c b/drivers/ginput/touch/MCU/ginput_lld_mouse.c index 1bb7cd50..a64bf6cb 100644 --- a/drivers/ginput/touch/MCU/ginput_lld_mouse.c +++ b/drivers/ginput/touch/MCU/ginput_lld_mouse.c @@ -21,15 +21,7 @@ #include "ginput/lld/mouse.h" -#if defined(GINPUT_MOUSE_USE_CUSTOM_BOARD) && GINPUT_MOUSE_USE_CUSTOM_BOARD - #include "ginput_lld_mouse_board.h" -#elif defined(BOARD_OLIMEX_STM32_LCD) - #include "ginput_lld_mouse_board_olimex_stm32_lcd.h" -#elif defined(BOARD_OLIMEX_PIC32MX_LCD) - #include "ginput_lld_mouse_board_olimex_pic32mx_lcd.h" -#else - #include "ginput_lld_mouse_board.h" -#endif +#include "ginput_lld_mouse_board.h" static uint16_t sampleBuf[7]; static coord_t lastx, lasty; diff --git a/drivers/tdisp/HD44780/tdisp_lld.c b/drivers/tdisp/HD44780/tdisp_lld.c index 2232955c..7b731c34 100644 --- a/drivers/tdisp/HD44780/tdisp_lld.c +++ b/drivers/tdisp/HD44780/tdisp_lld.c @@ -17,15 +17,7 @@ #if GFX_USE_TDISP /*|| defined(__DOXYGEN__)*/ -/* check first if the user has defined his/her own lowlevel-board file */ -#if defined(TDISP_USE_CUSTOM_BOARD) && TDISP_USE_CUSTOM_BOARD - /* Include the user supplied board definitions */ - #include "tdisp_lld_board.h" -#elif defined(BOARD_OLIMEX_STM32_E407) - #include "tdisp_lld_board_olimex_e407.h" -#elif defined(BOARD_ST_STM32F4_DISCOVERY) - #include "tdisp_lld_board_example.h" -#endif +#include "tdisp_lld_board.h" /* Controller Specific Properties */ #define CUSTOM_CHAR_COUNT 8 From 15c57f82ea3f89609982989b08f95d8390cf1bb3 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Oct 2013 01:10:36 +1000 Subject: [PATCH 140/160] Removal of obsolete reference to GDISP_NEED_ASYNC --- include/gfx_rules.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/gfx_rules.h b/include/gfx_rules.h index 853d9e8a..534c2cc9 100644 --- a/include/gfx_rules.h +++ b/include/gfx_rules.h @@ -87,10 +87,9 @@ #undef GWIN_NEED_WINDOWMANAGER #define GWIN_NEED_WINDOWMANAGER TRUE #endif - #if !GDISP_NEED_MULTITHREAD && !GDISP_NEED_ASYNC + #if !GDISP_NEED_MULTITHREAD #if GFX_DISPLAY_RULE_WARNINGS - #warning "GWIN: Either GDISP_NEED_MULTITHREAD or GDISP_NEED_ASYNC is required if GWIN_NEED_WIDGET is TRUE." - #warning "GWIN: GDISP_NEED_MULTITHREAD has been turned on for you." + #warning "GWIN: GDISP_NEED_MULTITHREAD is required if GWIN_NEED_WIDGET is TRUE. It has been turned on for you" #endif #undef GDISP_NEED_MULTITHREAD #define GDISP_NEED_MULTITHREAD TRUE From 553dea5fcdd38a8bbc09c9181199916fd36a841b Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Oct 2013 01:11:25 +1000 Subject: [PATCH 141/160] Make the hardware depedant options clearer for the widgets demo --- demos/modules/gwin/widgets/gfxconf.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index 602a559c..7899bfb8 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -48,8 +48,12 @@ #define GDISP_NEED_CLIP TRUE #define GDISP_NEED_CIRCLE TRUE #define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_SCROLL TRUE #define GDISP_NEED_IMAGE TRUE +#define GDISP_NEED_CONVEX_POLYGON TRUE + +/* The following are optional depending on your hardware */ +//#define GDISP_NEED_SCROLL TRUE +//#define GDISP_NEED_CONTROL TRUE /* GDISP fonts to include */ #define GDISP_INCLUDE_FONT_UI2 TRUE From ffee80299d616f1b634eacb514fcd7b3e4dc1a02 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Oct 2013 01:12:03 +1000 Subject: [PATCH 142/160] ILI9341 driver fixes --- drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c | 33 ++++------------------- drivers/gdisp/ILI9341/gdisp_lld_config.h | 1 - 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c b/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c index e5c4b7d0..33ca68d4 100644 --- a/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c +++ b/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c @@ -60,22 +60,6 @@ #define delay(us) gfxSleepMicroseconds(us) #define delayms(ms) gfxSleepMilliseconds(ms) -static inline void set_cursor(GDisplay *g) { - write_index(g, 0x2A); - write_data(g, (g->p.x >> 8)); - write_data(g, (uint8_t) g->p.x); - write_data(g, (g->p.x) >> 8); - write_data(g, (uint8_t) (g->p.x)); - - write_index(g, 0x2B); - write_data(g, (g->p.y >> 8)); - write_data(g, (uint8_t) g->p.y); - write_data(g, (g->p.y) >> 8); - write_data(g, (uint8_t) (g->p.y)); - - write_index(g, 0x2C); -} - static void set_viewport(GDisplay *g) { write_index(g, 0x2A); write_data(g, (g->p.x >> 8)); @@ -259,9 +243,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { LLDSPEC void gdisp_lld_write_start(GDisplay *g) { acquire_bus(g); set_viewport(g); - #if !GDISP_HARDWARE_STREAM_POS - set_cursor(g); - #endif + write_index(g, 0x2C); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { write_data16(g, g->p.color); @@ -269,18 +251,13 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); } - #if GDISP_HARDWARE_STREAM_POS - LLDSPEC void gdisp_lld_write_pos(GDisplay *g) { - set_cursor(g); - } - #endif #endif #if GDISP_HARDWARE_STREAM_READ LLDSPEC void gdisp_lld_read_start(GDisplay *g) { acquire_bus(g); set_viewport(g); - set_cursor(g); + write_index(g, 0x2E); setreadmode(g); dummy_read(g); } @@ -331,21 +308,21 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { break; case GDISP_ROTATE_90: acquire_bus(g); - write_reg(g, 0x36, 0x20); /* Invert X and Y axes */ + write_reg(g, 0x36, 0xE8); /* Invert X and Y axes */ release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; break; case GDISP_ROTATE_180: acquire_bus(g); - write_reg(g, 0x36, 0x80); /* X and Y axes non-inverted */ + write_reg(g, 0x36, 0x88); /* X and Y axes non-inverted */ release_bus(g); g->g.Height = GDISP_SCREEN_HEIGHT; g->g.Width = GDISP_SCREEN_WIDTH; break; case GDISP_ROTATE_270: acquire_bus(g); - write_reg(g, 0x36, 0xE0); /* Invert X and Y axes */ + write_reg(g, 0x36, 0x28); /* Invert X and Y axes */ release_bus(g); g->g.Height = GDISP_SCREEN_WIDTH; g->g.Width = GDISP_SCREEN_HEIGHT; diff --git a/drivers/gdisp/ILI9341/gdisp_lld_config.h b/drivers/gdisp/ILI9341/gdisp_lld_config.h index 8246934d..ba9c05bc 100644 --- a/drivers/gdisp/ILI9341/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9341/gdisp_lld_config.h @@ -25,7 +25,6 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE //#define GDISP_HARDWARE_STREAM_READ TRUE -//#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 From ab4091b366009209928cfa392b04c590ed50196c Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Oct 2013 01:12:42 +1000 Subject: [PATCH 143/160] Updates for the Mikrmedia STM32 M4 board --- .../ChibiOS_Board/flash_memory.c | 14 ++++++++------ .../ChibiOS_Board/flash_memory.h | 4 ++-- .../Mikromedia-STM32-M4-ILI9341/board_ILI9341.h | 8 -------- boards/base/Mikromedia-STM32-M4-ILI9341/readme.txt | 2 -- 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.c b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.c index 1965ba35..a27a3db5 100644 --- a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.c +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.c @@ -70,7 +70,6 @@ void flash_read(uint32_t address, size_t bytes, uint8_t *out) { sector_read_cmd[1] = (address >> 16) & 0xFF; sector_read_cmd[2] = (address >> 8) & 0xFF; sector_read_cmd[3] = address & 0xFF; - uint8_t dummy[1]; spiAcquireBus(&SPID3); spiStart(&SPID3, &flash_spicfg); @@ -81,7 +80,7 @@ void flash_read(uint32_t address, size_t bytes, uint8_t *out) { spiReleaseBus(&SPID3); } -void flash_write(uint32_t address, size_t bytes, uint8_t *data) { +void flash_write(uint32_t address, size_t bytes, const uint8_t *data) { static uint8_t flash_write_cmd[4]; flash_write_enable(); @@ -90,7 +89,6 @@ void flash_write(uint32_t address, size_t bytes, uint8_t *data) { flash_write_cmd[1] = (address >> 16) & 0xFF; flash_write_cmd[2] = (address >> 8) & 0xFF; flash_write_cmd[3] = address & 0xFF; - uint8_t dummy[1]; spiAcquireBus(&SPID3); spiStart(&SPID3, &flash_spicfg); @@ -112,14 +110,18 @@ bool flash_tp_calibrated(void) { } void flash_tp_calibration_save(uint16_t instance, const uint8_t *calbuf, size_t sz) { + if (instance) return; flash_sector_erase(0x0F0000); uint8_t calibrated = 0x01; flash_write(0x0F0000, 1, &calibrated); flash_write(0x0F0001, sz, calbuf); } const char *flash_tp_calibration_load(uint16_t instance) { - static char foo[24]; + static uint8_t foo[24]; + + if (instance) return 0; + if (!flash_tp_calibrated()) return 0; flash_read(0x0F0001, 24, foo); - return foo; -} \ No newline at end of file + return (char *)foo; +} diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.h b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.h index 5be7523f..2dcc9206 100644 --- a/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.h +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/ChibiOS_Board/flash_memory.h @@ -1,6 +1,6 @@ void flash_sector_erase(uint32_t sector); void flash_read(uint32_t address, size_t bytes, uint8_t *out); -void flash_write(uint32_t address, size_t bytes, uint8_t *data); +void flash_write(uint32_t address, size_t bytes, const uint8_t *data); bool flash_tp_calibrated(void); void flash_tp_calibration_save(uint16_t instance, const uint8_t *calbuf, size_t sz); -const char *flash_tp_calibration_load(uint16_t instance); \ No newline at end of file +const char *flash_tp_calibration_load(uint16_t instance); diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/board_ILI9341.h b/boards/base/Mikromedia-STM32-M4-ILI9341/board_ILI9341.h index ec7292eb..c73c68a9 100644 --- a/boards/base/Mikromedia-STM32-M4-ILI9341/board_ILI9341.h +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/board_ILI9341.h @@ -36,14 +36,6 @@ static inline void init_board(GDisplay *g) { SET_RD; SET_WR; CLR_CS; - - /* Hardware reset */ - palSetPad(GPIOE, GPIOE_LCD_RST); - chThdSleepMilliseconds(100); - palClearPad(GPIOE, GPIOE_LCD_RST); - chThdSleepMilliseconds(100); - palSetPad(GPIOE, GPIOE_LCD_RST); - chThdSleepMilliseconds(100); break; } } diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/readme.txt b/boards/base/Mikromedia-STM32-M4-ILI9341/readme.txt index 79b430d2..961f9793 100644 --- a/boards/base/Mikromedia-STM32-M4-ILI9341/readme.txt +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/readme.txt @@ -12,5 +12,3 @@ As this is not a standard ChibiOS supported board the necessary board files have been provided in the ChibiOS_Board directory. There is an example Makefile and project in the examples directory. - -Note: The video driver currently has bugs! \ No newline at end of file From 9b9a57c2c9dfdcfd96c04960e10f89e2a621e808 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Oct 2013 20:25:41 +1000 Subject: [PATCH 144/160] Better debugging for Win32 driver --- drivers/multiple/Win32/gdisp_lld_Win32.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/multiple/Win32/gdisp_lld_Win32.c b/drivers/multiple/Win32/gdisp_lld_Win32.c index 7d7abb06..65baf903 100644 --- a/drivers/multiple/Win32/gdisp_lld_Win32.c +++ b/drivers/multiple/Win32/gdisp_lld_Win32.c @@ -487,9 +487,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ void BAD_PARAMETER(const char *msg) { - volatile int a; - // This is really just a point for us to set the debugger - a = 0; + fprintf(stderr, "%s\n", msg); } #endif From dc24af70eab4f62ab4702bf8ca81c33f544cc5bc Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Oct 2013 20:26:19 +1000 Subject: [PATCH 145/160] Win32 board definitions. --- boards/base/Win32/board.mk | 3 + boards/base/Win32/example/Makefile | 195 ++++++++++ boards/base/Win32/example/chconf.h | 536 +++++++++++++++++++++++++++ boards/base/Win32/example/halconf.h | 342 +++++++++++++++++ boards/base/Win32/example/readme.txt | 9 + boards/base/Win32/readme.txt | 9 + 6 files changed, 1094 insertions(+) create mode 100644 boards/base/Win32/board.mk create mode 100644 boards/base/Win32/example/Makefile create mode 100644 boards/base/Win32/example/chconf.h create mode 100644 boards/base/Win32/example/halconf.h create mode 100644 boards/base/Win32/example/readme.txt create mode 100644 boards/base/Win32/readme.txt diff --git a/boards/base/Win32/board.mk b/boards/base/Win32/board.mk new file mode 100644 index 00000000..be5740ef --- /dev/null +++ b/boards/base/Win32/board.mk @@ -0,0 +1,3 @@ +GFXINC += $(GFXLIB)/boards/base/Win32 +GFXSRC += +include $(GFXLIB)/drivers/multiple/Win32/gdisp_lld.mk diff --git a/boards/base/Win32/example/Makefile b/boards/base/Win32/example/Makefile new file mode 100644 index 00000000..66d4b918 --- /dev/null +++ b/boards/base/Win32/example/Makefile @@ -0,0 +1,195 @@ +# +# !!!! Do NOT edit this makefile with an editor which replace tabs by spaces !!!! +# +############################################################################################## +# +# On command line: +# +# make all = Create project +# +# make clean = Clean project files. +# +# To rebuild project do "make clean" and "make all". +# + +############################################################################################## +# Start of default section +# + +CC = i686-pc-mingw32-gcc -g + +# Turn ChibiOS simimulator on or off - uGFX doesn't need it but you might for other purposes. +USE_CHIBIOS=no + +# List all default C defines here, like -D_DEBUG=1 +DDEFS = + +# List all default directories to look for include files here +DINCDIR = + +# List the default directory to look for the libraries here +DLIBDIR = + +# List all default libraries here +DLIBS = -lws2_32 -lgdi32 + +# Make sure this empty for now +SRC = + +# +# End of default section +############################################################################################## + +############################################################################################## +# Start of user section +# + +# Define project name here +PROJECT = uGFX + +# Imported source files and paths for uGFX +GFXLIB = ../uGFX +include $(GFXLIB)/gfx.mk +include $(GFXLIB)/boards/base/Win32/board.mk + +# Imported source files and paths for ChibiOS +ifeq ($(USE_CHIBIOS),yes) + CHIBIOS = ../ChibiOS + include $(CHIBIOS)/boards/simulator/board.mk + include ${CHIBIOS}/os/hal/hal.mk + include ${CHIBIOS}/os/hal/platforms/Win32/platform.mk + include ${CHIBIOS}/os/ports/GCC/SIMIA32/port.mk + include ${CHIBIOS}/os/kernel/kernel.mk + DDEFS += -DSIMULATOR -DSHELL_USE_IPRINTF=FALSE + UINCDIR += $(PORTINC) $(KERNINC) $(TESTINC) \ + $(HALINC) $(PLATFORMINC) $(BOARDINC) + # ${CHIBIOS}/os/various + SRC += ${PORTSRC} \ + ${KERNSRC} \ + ${TESTSRC} \ + ${HALSRC} \ + ${PLATFORMSRC} \ + $(BOARDSRC) + GFXDEFS += -DGFX_USE_OS_CHIBIOS=TRUE +else + GFXDEFS += -DGFX_USE_OS_WIN32=TRUE +endif + +# Where is our source code - alter these for your project. +MYFILES = $(GFXLIB)/demos/modules/gdisp/basics +MYCSRC = $(MYFILES)/main.c + +# List C source files here +SRC += ${GFXSRC} \ + ${MYCSRC} + +# List all user C define here, like -D_DEBUG=1 +UDEFS = ${GFXDEFS} + +# List all user directories here +UINCDIR = ${GFXINC} \ + ${MYFILES} + +# List the user directory to look for the libraries here +ULIBDIR = + +# List all user libraries here +ULIBS = + +# Define optimisation level here +#OPT = -ggdb -O2 -fomit-frame-pointer +OPT = -ggdb -O0 -fomit-frame-pointer + +# +# End of user defines +############################################################################################## + + +# Output directory and files +ifeq ($(BUILDDIR),) + BUILDDIR = .build +endif +ifeq ($(BUILDDIR),.) + BUILDDIR = .build +endif + +OBJDIR = $(BUILDDIR)/obj +LSTDIR = $(BUILDDIR)/lst +MAPDIR = $(BUILDDIR)/map + +INCDIR = $(patsubst %,-I%,$(DINCDIR) $(UINCDIR)) +LIBDIR = $(patsubst %,-L%,$(DLIBDIR) $(ULIBDIR)) +DEFS = $(DDEFS) $(UDEFS) +ADEFS = $(DADEFS) $(UADEFS) +COBJ = $(addprefix $(OBJDIR)/, $(SRC:.c=.o)) +AOBJ = $(addprefix $(OBJDIR)/, $(ASRC:.s=.o)) +OBJS = $(AOBJ) $(COBJ) +LIBS = $(DLIBS) $(ULIBS) + +LDFLAGS = -Wl,-Map=$(MAPDIR)/$(PROJECT).map,--cref,--no-warn-mismatch $(LIBDIR) +CPFLAGS = $(OPT) -Wall -Wextra -Wstrict-prototypes -fverbose-asm -Wa,-alms=$(LSTDIR)/$(<:.c=.lst) $(DEFS) + +# Generate dependency information +CPFLAGS += -MD -MP -MF .dep/$(@F).d + +# +# makefile rules +# + +all: $(BUILDDIR) $(OBJS) $(BUILDDIR)/$(PROJECT).exe MAKE_ALL_RULE_HOOK + +MAKE_ALL_RULE_HOOK: + +$(BUILDDIR) $(OBJDIR) $(LSTDIR): + mkdir -p $(OBJDIR) + mkdir -p $(LSTDIR) + mkdir -p $(MAPDIR) +ifneq ($(USE_VERBOSE_COMPILE),yes) + @echo Compiler Options - $(CC) -c $(CPFLAGS) -I. $(INCDIR) main.c -o $(OBJDIR)/main.o + @echo +endif + +$(OBJDIR)/%.o : %.c + @mkdir -p $(dir $@) +ifeq ($(USE_VERBOSE_COMPILE),yes) + @echo + $(CC) -c $(CPFLAGS) -I. $(INCDIR) $< -o $@ +else + @echo Compiling $< + @$(CC) -c $(CPFLAGS) -I. $(INCDIR) $< -o $@ +endif + +$(OBJDIR)/%.o : %.s + @mkdir -p $(dir $@) +ifeq ($(USE_VERBOSE_COMPILE),yes) + @echo + $(AS) -c $(ASFLAGS) -I. $(INCDIR) $< -o $@ +else + @echo Compiling $< + @$(AS) -c $(ASFLAGS) -I. $(INCDIR) $< -o $@ +endif + +%.exe: $(OBJS) +ifeq ($(USE_VERBOSE_COMPILE),yes) + @echo + $(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@ +else + @echo Linking $@ + @$(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@ +endif + +gcov: + -mkdir gcov + $(COV) -u $(subst /,\,$(SRC)) + -mv *.gcov ./gcov + +clean: + -rm -fR .build + -rm -fR .dep + +# +# Include the dependency files, should be the last of the makefile +# +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + +# *** EOF *** diff --git a/boards/base/Win32/example/chconf.h b/boards/base/Win32/example/chconf.h new file mode 100644 index 00000000..759f6be8 --- /dev/null +++ b/boards/base/Win32/example/chconf.h @@ -0,0 +1,536 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef _CHCONF_H_ +#define _CHCONF_H_ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + */ +#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__) +#define CH_FREQUENCY 1000 +#endif + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + */ +#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__) +#define CH_TIME_QUANTUM 20 +#endif + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_USE_MEMCORE. + */ +#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__) +#define CH_MEMCORE_SIZE 0x20000 +#endif + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread automatically. The application has + * then the responsibility to do one of the following: + * - Spawn a custom idle thread at priority @p IDLEPRIO. + * - Change the main() thread priority to @p IDLEPRIO then enter + * an endless loop. In this scenario the @p main() thread acts as + * the idle thread. + * . + * @note Unless an idle thread is spawned the @p main() thread must not + * enter a sleep state. + */ +#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__) +#define CH_NO_IDLE_THREAD FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__) +#define CH_OPTIMIZE_SPEED TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__) +#define CH_USE_REGISTRY TRUE +#endif + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__) +#define CH_USE_WAITEXIT TRUE +#endif + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__) +#define CH_USE_SEMAPHORES TRUE +#endif + +/** + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special requirements. + * @note Requires @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__) +#define CH_USE_SEMAPHORES_PRIORITY FALSE +#endif + +/** + * @brief Atomic semaphore API. + * @details If enabled then the semaphores the @p chSemSignalWait() API + * is included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__) +#define CH_USE_SEMSW TRUE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__) +#define CH_USE_MUTEXES TRUE +#endif + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_MUTEXES. + */ +#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__) +#define CH_USE_CONDVARS TRUE +#endif + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_CONDVARS. + */ +#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__) +#define CH_USE_CONDVARS_TIMEOUT TRUE +#endif + +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__) +#define CH_USE_EVENTS TRUE +#endif + +/** + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_EVENTS. + */ +#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__) +#define CH_USE_EVENTS_TIMEOUT TRUE +#endif + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__) +#define CH_USE_MESSAGES TRUE +#endif + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special requirements. + * @note Requires @p CH_USE_MESSAGES. + */ +#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__) +#define CH_USE_MESSAGES_PRIORITY FALSE +#endif + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_SEMAPHORES. + */ +#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__) +#define CH_USE_MAILBOXES TRUE +#endif + +/** + * @brief I/O Queues APIs. + * @details If enabled then the I/O queues APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__) +#define CH_USE_QUEUES TRUE +#endif + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MEMCORE) || defined(__DOXYGEN__) +#define CH_USE_MEMCORE TRUE +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or + * @p CH_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__) +#define CH_USE_HEAP TRUE +#endif + +/** + * @brief C-runtime allocator. + * @details If enabled the the heap allocator APIs just wrap the C-runtime + * @p malloc() and @p free() functions. + * + * @note The default is @p FALSE. + * @note Requires @p CH_USE_HEAP. + * @note The C-runtime may or may not require @p CH_USE_MEMCORE, see the + * appropriate documentation. + */ +#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__) +#define CH_USE_MALLOC_HEAP FALSE +#endif + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__) +#define CH_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_USE_WAITEXIT. + * @note Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS. + */ +#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__) +#define CH_USE_DYNAMIC TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__) +#define CH_DBG_SYSTEM_STATE_CHECK FALSE +#endif + +/** + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_CHECKS FALSE +#endif + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_ASSERTS FALSE +#endif + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the context switch circular trace buffer is + * activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_TRACE FALSE +#endif + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) +#define CH_DBG_ENABLE_STACK_CHECK FALSE +#endif + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__) +#define CH_DBG_FILL_THREADS FALSE +#endif + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p Thread structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p TRUE. + * @note This debug option is defaulted to TRUE because it is required by + * some test cases into the test suite. + */ +#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__) +#define CH_DBG_THREADS_PROFILING TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p Thread structure. + */ +#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__) +#define THREAD_EXT_FIELDS \ + /* Add threads custom fields here.*/ +#endif + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p chThdInit() API. + * + * @note It is invoked from within @p chThdInit() and implicitly from all + * the threads creation APIs. + */ +#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__) +#define THREAD_EXT_INIT_HOOK(tp) { \ + /* Add threads initialization code here.*/ \ +} +#endif + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + * + * @note It is inserted into lock zone. + * @note It is also invoked when the threads simply return in order to + * terminate. + */ +#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__) +#define THREAD_EXT_EXIT_HOOK(tp) { \ + /* Add threads finalization code here.*/ \ +} +#endif + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + */ +#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__) +#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) { \ + /* System halt code here.*/ \ +} +#endif + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__) +#define IDLE_LOOP_HOOK() { \ + /* Idle loop code here.*/ \ +} +#endif + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__) +#define SYSTEM_TICK_EVENT_HOOK() { \ + /* System tick event code here.*/ \ +} +#endif + + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__) +#define SYSTEM_HALT_HOOK() { \ + /* System halt code here.*/ \ +} +#endif + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#endif /* _CHCONF_H_ */ + +/** @} */ diff --git a/boards/base/Win32/example/halconf.h b/boards/base/Win32/example/halconf.h new file mode 100644 index 00000000..81dc4dd2 --- /dev/null +++ b/boards/base/Win32/example/halconf.h @@ -0,0 +1,342 @@ +/* + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011,2012 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @file templates/halconf.h + * @brief HAL configuration header. + * @details HAL configuration file, this file allows to enable or disable the + * various device drivers from your application. You may also use + * this file in order to override the device drivers default settings. + * + * @addtogroup HAL_CONF + * @{ + */ + +#ifndef _HALCONF_H_ +#define _HALCONF_H_ + +/*#include "mcuconf.h"*/ + +/** + * @brief Enables the TM subsystem. + */ +#if !defined(HAL_USE_TM) || defined(__DOXYGEN__) +#define HAL_USE_TM FALSE +#endif + +/** + * @brief Enables the PAL subsystem. + */ +#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) +#define HAL_USE_PAL TRUE +#endif + +/** + * @brief Enables the ADC subsystem. + */ +#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) +#define HAL_USE_ADC FALSE +#endif + +/** + * @brief Enables the CAN subsystem. + */ +#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) +#define HAL_USE_CAN FALSE +#endif + +/** + * @brief Enables the EXT subsystem. + */ +#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__) +#define HAL_USE_EXT FALSE +#endif + +/** + * @brief Enables the GPT subsystem. + */ +#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) +#define HAL_USE_GPT FALSE +#endif + +/** + * @brief Enables the I2C subsystem. + */ +#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) +#define HAL_USE_I2C FALSE +#endif + +/** + * @brief Enables the ICU subsystem. + */ +#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) +#define HAL_USE_ICU FALSE +#endif + +/** + * @brief Enables the MAC subsystem. + */ +#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) +#define HAL_USE_MAC FALSE +#endif + +/** + * @brief Enables the MMC_SPI subsystem. + */ +#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) +#define HAL_USE_MMC_SPI FALSE +#endif + +/** + * @brief Enables the PWM subsystem. + */ +#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) +#define HAL_USE_PWM FALSE +#endif + +/** + * @brief Enables the RTC subsystem. + */ +#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) +#define HAL_USE_RTC FALSE +#endif + +/** + * @brief Enables the SDC subsystem. + */ +#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) +#define HAL_USE_SDC FALSE +#endif + +/** + * @brief Enables the SERIAL subsystem. + */ +#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL TRUE +#endif + +/** + * @brief Enables the SERIAL over USB subsystem. + */ +#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL_USB FALSE +#endif + +/** + * @brief Enables the SPI subsystem. + */ +#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) +#define HAL_USE_SPI FALSE +#endif + +/** + * @brief Enables the UART subsystem. + */ +#if !defined(HAL_USE_UART) || defined(__DOXYGEN__) +#define HAL_USE_UART FALSE +#endif + +/** + * @brief Enables the USB subsystem. + */ +#if !defined(HAL_USE_USB) || defined(__DOXYGEN__) +#define HAL_USE_USB FALSE +#endif + +/*===========================================================================*/ +/* ADC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) +#define ADC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define ADC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* CAN driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + */ +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif + +/*===========================================================================*/ +/* I2C driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the mutual exclusion APIs on the I2C bus. + */ +#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define I2C_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* MAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) +#define MAC_USE_EVENTS TRUE +#endif + +/*===========================================================================*/ +/* MMC_SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Block size for MMC transfers. + */ +#if !defined(MMC_SECTOR_SIZE) || defined(__DOXYGEN__) +#define MMC_SECTOR_SIZE 512 +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + * This option is recommended also if the SPI driver does not + * use a DMA channel and heavily loads the CPU. + */ +#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__) +#define MMC_NICE_WAITING TRUE +#endif + +/** + * @brief Number of positive insertion queries before generating the + * insertion event. + */ +#if !defined(MMC_POLLING_INTERVAL) || defined(__DOXYGEN__) +#define MMC_POLLING_INTERVAL 10 +#endif + +/** + * @brief Interval, in milliseconds, between insertion queries. + */ +#if !defined(MMC_POLLING_DELAY) || defined(__DOXYGEN__) +#define MMC_POLLING_DELAY 10 +#endif + +/** + * @brief Uses the SPI polled API for small data transfers. + * @details Polled transfers usually improve performance because it + * saves two context switches and interrupt servicing. Note + * that this option has no effect on large transfers which + * are always performed using DMAs/IRQs. + */ +#if !defined(MMC_USE_SPI_POLLING) || defined(__DOXYGEN__) +#define MMC_USE_SPI_POLLING TRUE +#endif + +/*===========================================================================*/ +/* SDC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intervals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + +/*===========================================================================*/ +/* SERIAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SERIAL_DEFAULT_BITRATE 38400 +#endif + +/** + * @brief Serial buffers size. + * @details Configuration parameter, you can change the depth of the queue + * buffers depending on the requirements of your application. + * @note The default is 64 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_BUFFERS_SIZE 16 +#endif + +/*===========================================================================*/ +/* SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) +#define SPI_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define SPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +#endif /* _HALCONF_H_ */ + +/** @} */ diff --git a/boards/base/Win32/example/readme.txt b/boards/base/Win32/example/readme.txt new file mode 100644 index 00000000..78b8552b --- /dev/null +++ b/boards/base/Win32/example/readme.txt @@ -0,0 +1,9 @@ +Copy these files into your own project directory and alter them to suite. + +Notes: + +1/ This makefile uses the MINGW compiler tool chain and was run using the cygwin make. +2/ At the top of the Makefile is the define USE_CHIBIOS. Win32 can build uGFX for either + native Win32 (the default) or for the ChibiOS simulator. +3/ The files chconf.h and halconf.h are only needed if compiling for the ChibiOS simulator. +4/ Look at the MYFILES definition and the MYCSRC definition. diff --git a/boards/base/Win32/readme.txt b/boards/base/Win32/readme.txt new file mode 100644 index 00000000..031a7c6e --- /dev/null +++ b/boards/base/Win32/readme.txt @@ -0,0 +1,9 @@ +This directory contains the interface for Win32 +running either native Win32 or under the ChibiOS simulator. + +On this board uGFX currently supports: + - GDISP via the Win32 driver + - GINPUT-touch via the Win32 driver + - GINPUT-toggles via the Win32 driver + +There is an example Makefile and project in the examples directory. From 0399c33aebeae0f60c31f87a6649371ff2a78242 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 29 Oct 2013 21:14:02 +1000 Subject: [PATCH 146/160] Linux board defintions --- boards/base/Linux/board.mk | 4 + boards/base/Linux/example/Makefile | 153 +++++++++++++++++++++++++++ boards/base/Linux/example/readme.txt | 5 + boards/base/Linux/readme.txt | 8 ++ 4 files changed, 170 insertions(+) create mode 100644 boards/base/Linux/board.mk create mode 100644 boards/base/Linux/example/Makefile create mode 100644 boards/base/Linux/example/readme.txt create mode 100644 boards/base/Linux/readme.txt diff --git a/boards/base/Linux/board.mk b/boards/base/Linux/board.mk new file mode 100644 index 00000000..f022947f --- /dev/null +++ b/boards/base/Linux/board.mk @@ -0,0 +1,4 @@ +GFXINC += $(GFXLIB)/boards/base/Linux +GFXSRC += +GFXDEFS += -DGFX_USE_OS_LINUX=TRUE +include $(GFXLIB)/drivers/multiple/X/gdisp_lld.mk diff --git a/boards/base/Linux/example/Makefile b/boards/base/Linux/example/Makefile new file mode 100644 index 00000000..1d59fe43 --- /dev/null +++ b/boards/base/Linux/example/Makefile @@ -0,0 +1,153 @@ +# +# !!!! Do NOT edit this makefile with an editor which replace tabs by spaces !!!! +# +############################################################################################## +# +# On command line: +# +# make all = Create project +# +# make clean = Clean project files. +# +# To rebuild project do "make clean" and "make all". +# + +############################################################################################## +# Start of default section +# + +TRGT = +CC = $(TRGT)gcc +AS = $(TRGT)gcc -x assembler-with-cpp + +# List all default C defines here, like -D_DEBUG=1 +DDEFS = + +# List all default ASM defines here, like -D_DEBUG=1 +DADEFS = + +# List all default directories to look for include files here +DINCDIR = + +# List the default directory to look for the libraries here +DLIBDIR = + +# List all default libraries here +DLIBS = -lX11 -pthread -lrt + +# +# End of default section +############################################################################################## + +############################################################################################## +# Start of user section +# + +# Define project name here +PROJECT = ugfx + +# Imported source files and paths for uGFX +GFXLIB = ../ugfx +include ${GFXLIB}/gfx.mk +include ${GFXLIB}/boards/base/Linux/board.mk + +# Where is our source code - alter these for your project. +MYFILES = $(GFXLIB)/demos/modules/gdisp/basics +MYCSRC = $(MYFILES)/main.c +MYDEFS = + +# List all user C define here, like -D_DEBUG=1 +UDEFS = $(MYDEFS) $(GFXDEFS) + +# Define ASM defines here +UADEFS = + +# List C source files here +SRC = $(GFXSRC) \ + $(MYCSRC) + +# List ASM source files here +ASRC = + +# List all user directories here +UINCDIR = $(MYFILES) $(GFXINC) + +# List the user directory to look for the libraries here +ULIBDIR = + +# List all user libraries here +ULIBS = + +# Define optimisation level here +OPT = -ggdb -O0 -fomit-frame-pointer + +# +# End of user defines +############################################################################################## + +INCDIR = $(patsubst %,-I%,$(DINCDIR) $(UINCDIR)) +LIBDIR = $(patsubst %,-L%,$(DLIBDIR) $(ULIBDIR)) +DEFS = $(DDEFS) $(UDEFS) +ADEFS = $(DADEFS) $(UADEFS) +OBJS = $(ASRC:.s=.o) $(SRC:.c=.o) +LIBS = $(DLIBS) $(ULIBS) + +ASFLAGS = -Wa,-amhls=$(<:.s=.lst) $(ADEFS) +CPFLAGS = $(OPT) -Wall -Wextra -Wstrict-prototypes -fverbose-asm $(DEFS) + +ifeq ($(HOST_OSX),yes) + ifeq ($(OSX_SDK),) + OSX_SDK = /Developer/SDKs/MacOSX10.7.sdk + endif + ifeq ($(OSX_ARCH),) + OSX_ARCH = -mmacosx-version-min=10.3 -arch i386 + endif + + CPFLAGS += -isysroot $(OSX_SDK) $(OSX_ARCH) + LDFLAGS = -Wl -Map=$(PROJECT).map,-syslibroot,$(OSX_SDK),$(LIBDIR) + LIBS += $(OSX_ARCH) +else + # Linux, or other + CPFLAGS += -m32 -Wa,-alms=$(<:.c=.lst) + LDFLAGS = -m32 -Wl,-Map=$(PROJECT).map,--cref,--no-warn-mismatch $(LIBDIR) +endif + +# Generate dependency information +CPFLAGS += -MD -MP -MF .dep/$(@F).d + +# +# makefile rules +# + +all: $(OBJS) $(PROJECT) + +%.o : %.c + $(CC) -c $(CPFLAGS) -I . $(INCDIR) $< -o $@ + +%.o : %.s + $(AS) -c $(ASFLAGS) $< -o $@ + +$(PROJECT): $(OBJS) + $(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@ + +gcov: + -mkdir gcov + $(COV) -u $(subst /,\,$(SRC)) + -mv *.gcov ./gcov + +clean: + -rm -f $(OBJS) + -rm -f $(PROJECT) + -rm -f $(PROJECT).map + -rm -f $(SRC:.c=.c.bak) + -rm -f $(SRC:.c=.lst) + -rm -f $(ASRC:.s=.s.bak) + -rm -f $(ASRC:.s=.lst) + -rm -fR .dep + +# +# Include the dependency files, should be the last of the makefile +# +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + +# *** EOF *** diff --git a/boards/base/Linux/example/readme.txt b/boards/base/Linux/example/readme.txt new file mode 100644 index 00000000..aff58bb1 --- /dev/null +++ b/boards/base/Linux/example/readme.txt @@ -0,0 +1,5 @@ +Copy these files into your own project directory and alter them to suite. + +Notes: + +1/ Look at the MYFILES definition and the MYCSRC definition. diff --git a/boards/base/Linux/readme.txt b/boards/base/Linux/readme.txt new file mode 100644 index 00000000..491c91f5 --- /dev/null +++ b/boards/base/Linux/readme.txt @@ -0,0 +1,8 @@ +This directory contains the interface for Linux +running either native Linux. + +On this board uGFX currently supports: + - GDISP via the X driver + - GINPUT-touch via the X driver + +There is an example Makefile and project in the examples directory. From ece5bcd6ab566dc3bef092e6a0b5260ba771bc85 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 5 Nov 2013 00:36:54 +1000 Subject: [PATCH 147/160] Auto-generate pixel formats using macro's. Prepare for (but not yet complete) supporting a different high level GDISP pixel format to the low level driver format. This will be useful in multiple display scenario's where displays have different pixel formats. --- drivers/gdisp/ED060SC4/gdisp_lld_config.h | 2 +- drivers/gdisp/HX8347D/gdisp_lld_config.h | 2 +- drivers/gdisp/ILI9320/gdisp_lld_config.h | 2 +- drivers/gdisp/ILI9325/gdisp_lld_config.h | 2 +- drivers/gdisp/ILI9341/gdisp_lld_config.h | 2 +- drivers/gdisp/ILI9481/gdisp_lld_config.h | 2 +- .../gdisp/Nokia6610GE12/gdisp_lld_config.h | 2 +- drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h | 2 +- drivers/gdisp/RA8875/gdisp_lld_config.h | 2 +- drivers/gdisp/S6D1121/gdisp_lld_config.h | 2 +- drivers/gdisp/SSD1289/gdisp_lld_config.h | 2 +- drivers/gdisp/SSD1306/gdisp_lld_config.h | 2 +- drivers/gdisp/SSD1963/gdisp_lld_config.h | 2 +- drivers/gdisp/SSD2119/gdisp_lld_config.h | 2 +- drivers/gdisp/ST7565/gdisp_lld_config.h | 2 +- drivers/gdisp/TestStub/gdisp_lld_config.h | 2 +- drivers/multiple/Win32/gdisp_lld_config.h | 6 +- drivers/multiple/X/gdisp_lld_config.h | 2 +- include/gdisp/colors.h | 353 ++++++++++++++++++ include/gdisp/gdisp.h | 181 +-------- 20 files changed, 385 insertions(+), 189 deletions(-) create mode 100644 include/gdisp/colors.h diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_config.h b/drivers/gdisp/ED060SC4/gdisp_lld_config.h index d7e836c9..47e84779 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld_config.h +++ b/drivers/gdisp/ED060SC4/gdisp_lld_config.h @@ -17,7 +17,7 @@ #define GDISP_HARDWARE_CLEARS TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_MONO +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO #endif diff --git a/drivers/gdisp/HX8347D/gdisp_lld_config.h b/drivers/gdisp/HX8347D/gdisp_lld_config.h index 48801f55..ab4c8639 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld_config.h +++ b/drivers/gdisp/HX8347D/gdisp_lld_config.h @@ -25,7 +25,7 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/ILI9320/gdisp_lld_config.h b/drivers/gdisp/ILI9320/gdisp_lld_config.h index 1a1f139f..5709de50 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_config.h @@ -27,7 +27,7 @@ //#define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/ILI9325/gdisp_lld_config.h b/drivers/gdisp/ILI9325/gdisp_lld_config.h index 8c586c78..c40bd2b7 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9325/gdisp_lld_config.h @@ -27,7 +27,7 @@ #define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/ILI9341/gdisp_lld_config.h b/drivers/gdisp/ILI9341/gdisp_lld_config.h index ba9c05bc..668a06c9 100644 --- a/drivers/gdisp/ILI9341/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9341/gdisp_lld_config.h @@ -27,7 +27,7 @@ //#define GDISP_HARDWARE_STREAM_READ TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/ILI9481/gdisp_lld_config.h b/drivers/gdisp/ILI9481/gdisp_lld_config.h index 4a33d110..3f3a4834 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld_config.h +++ b/drivers/gdisp/ILI9481/gdisp_lld_config.h @@ -27,7 +27,7 @@ #define GDISP_HARDWARE_STREAM_READ TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h b/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h index 73f505be..19a455d8 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld_config.h @@ -25,7 +25,7 @@ #define GDISP_HARDWARE_CONTROL TRUE #define GDISP_HARDWARE_STREAM_WRITE TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h index 70a57d12..1476dbcf 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_config.h @@ -41,7 +41,7 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE #endif -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB444 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/RA8875/gdisp_lld_config.h b/drivers/gdisp/RA8875/gdisp_lld_config.h index ae290245..55a07839 100644 --- a/drivers/gdisp/RA8875/gdisp_lld_config.h +++ b/drivers/gdisp/RA8875/gdisp_lld_config.h @@ -27,7 +27,7 @@ #define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/S6D1121/gdisp_lld_config.h b/drivers/gdisp/S6D1121/gdisp_lld_config.h index 839bbf9d..79e859bc 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld_config.h +++ b/drivers/gdisp/S6D1121/gdisp_lld_config.h @@ -27,7 +27,7 @@ #define GDISP_HARDWARE_STREAM_POS TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/SSD1289/gdisp_lld_config.h b/drivers/gdisp/SSD1289/gdisp_lld_config.h index 84e518d2..4cf5fa5c 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_config.h @@ -32,7 +32,7 @@ #define GDISP_HARDWARE_BITFILLS TRUE #endif -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/SSD1306/gdisp_lld_config.h b/drivers/gdisp/SSD1306/gdisp_lld_config.h index 8580f933..627de17b 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1306/gdisp_lld_config.h @@ -19,7 +19,7 @@ #define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_MONO +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO // This controller supports a special gdispControl() to inverse the display. // Pass a parameter of 1 for inverse and 0 for normal. diff --git a/drivers/gdisp/SSD1963/gdisp_lld_config.h b/drivers/gdisp/SSD1963/gdisp_lld_config.h index 054d72b8..8ad94738 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1963/gdisp_lld_config.h @@ -25,7 +25,7 @@ #define GDISP_HARDWARE_STREAM_WRITE TRUE //#define GDISP_HARDWARE_CONTROL TRUE // Not Yet. -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/SSD2119/gdisp_lld_config.h b/drivers/gdisp/SSD2119/gdisp_lld_config.h index 5d81057c..a974c623 100644 --- a/drivers/gdisp/SSD2119/gdisp_lld_config.h +++ b/drivers/gdisp/SSD2119/gdisp_lld_config.h @@ -32,7 +32,7 @@ #define GDISP_HARDWARE_BITFILLS TRUE #endif -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/ST7565/gdisp_lld_config.h b/drivers/gdisp/ST7565/gdisp_lld_config.h index 632dc431..f774e8fa 100644 --- a/drivers/gdisp/ST7565/gdisp_lld_config.h +++ b/drivers/gdisp/ST7565/gdisp_lld_config.h @@ -19,7 +19,7 @@ #define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_HARDWARE_CONTROL TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_MONO +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_MONO #endif /* GFX_USE_GDISP */ diff --git a/drivers/gdisp/TestStub/gdisp_lld_config.h b/drivers/gdisp/TestStub/gdisp_lld_config.h index adb6c8b4..63471c6c 100644 --- a/drivers/gdisp/TestStub/gdisp_lld_config.h +++ b/drivers/gdisp/TestStub/gdisp_lld_config.h @@ -25,7 +25,7 @@ #define GDISP_HARDWARE_DRAWPIXEL TRUE #define GDISP_HARDWARE_PIXELREAD TRUE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 #endif /* GFX_USE_GDISP */ diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h index e2fc3de4..4985bc43 100644 --- a/drivers/multiple/Win32/gdisp_lld_config.h +++ b/drivers/multiple/Win32/gdisp_lld_config.h @@ -21,10 +21,10 @@ /*===========================================================================*/ /* Driver hardware support. */ /*===========================================================================*/ - + // Calling gdispGFlush() is optional for this driver but can be used by the // application to force a display update. eg after streaming. - + #define GDISP_HARDWARE_FLUSH TRUE #define GDISP_HARDWARE_CONTROL TRUE @@ -45,7 +45,7 @@ #define GDISP_HARDWARE_SCROLL TRUE #endif -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 #endif /* GFX_USE_GDISP */ diff --git a/drivers/multiple/X/gdisp_lld_config.h b/drivers/multiple/X/gdisp_lld_config.h index b58a3d54..631ecf46 100644 --- a/drivers/multiple/X/gdisp_lld_config.h +++ b/drivers/multiple/X/gdisp_lld_config.h @@ -29,7 +29,7 @@ #define GDISP_HARDWARE_PIXELREAD TRUE #define GDISP_HARDWARE_CONTROL FALSE -#define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 #endif /* GFX_USE_GDISP */ diff --git a/include/gdisp/colors.h b/include/gdisp/colors.h new file mode 100644 index 00000000..975934d0 --- /dev/null +++ b/include/gdisp/colors.h @@ -0,0 +1,353 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file include/gdisp/colors.h + * @brief GDISP color definitions header file. + * + * @defgroup Colors Colors + * @ingroup GDISP + * @{ + */ + +#ifndef _GDISP_COLORS_H +#define _GDISP_COLORS_H + +#include "gfx.h" + +#if GFX_USE_GDISP || defined(__DOXYGEN__) + +/** + * For pixel formats we do some assignment of codes to enable + * format auto-calculation. (Undocumented). + * 0x2RGB TRUECOLOR RGB format, R = red bits, G = green bits, B = blue bits + * 0x3RGB TRUECOLOR BGR format, R = red bits, G = green bits, B = blue bits + * 0x40XX GRAYSCALE XX = bits + * 0x60XX PALLETTE XX = bits + * 0x8XXX CUSTOM format. + */ +#define GDISP_COLORSYSTEM_MASK 0xF000 +#define GDISP_COLORSYSTEM_RGB 0x2000 +#define GDISP_COLORSYSTEM_BGR 0x3000 + +/** + * @brief Color Type Constants + * @{ + */ +#define GDISP_COLORSYSTEM_TRUECOLOR 0x2000 +#define GDISP_COLORSYSTEM_GRAYSCALE 0x4000 +#define GDISP_COLORSYSTEM_PALETTE 0x6000 +/** @} */ + +/** + * @brief Pixel Format Constants + * @{ + */ +#define GDISP_PIXELFORMAT_MONO (GDISP_COLORSYSTEM_GRAYSCALE|0x0001) +#define GDISP_PIXELFORMAT_RGB565 (GDISP_COLORSYSTEM_RGB|0x0565) +#define GDISP_PIXELFORMAT_BGR565 (GDISP_COLORSYSTEM_BGR|0x0565) +#define GDISP_PIXELFORMAT_RGB888 (GDISP_COLORSYSTEM_RGB|0x0888) +#define GDISP_PIXELFORMAT_BGR888 (GDISP_COLORSYSTEM_BGR|0x0888) +#define GDISP_PIXELFORMAT_RGB444 (GDISP_COLORSYSTEM_RGB|0x0444) +#define GDISP_PIXELFORMAT_BGR444 (GDISP_COLORSYSTEM_BGR|0x0444) +#define GDISP_PIXELFORMAT_RGB332 (GDISP_COLORSYSTEM_RGB|0x0332) +#define GDISP_PIXELFORMAT_BGR332 (GDISP_COLORSYSTEM_BGR|0x0332) +#define GDISP_PIXELFORMAT_RGB666 (GDISP_COLORSYSTEM_RGB|0x0666) +#define GDISP_PIXELFORMAT_BGR666 (GDISP_COLORSYSTEM_BGR|0x0666) +#define GDISP_PIXELFORMAT_ERROR 0x0000 +/** @} */ + +/** + * @name Some basic colors + * @{ + */ +#define White HTML2COLOR(0xFFFFFF) +#define Black HTML2COLOR(0x000000) +#define Gray HTML2COLOR(0x808080) +#define Grey Gray +#define Blue HTML2COLOR(0x0000FF) +#define Red HTML2COLOR(0xFF0000) +#define Fuchsia HTML2COLOR(0xFF00FF) +#define Magenta Fuchsia +#define Green HTML2COLOR(0x008000) +#define Yellow HTML2COLOR(0xFFFF00) +#define Aqua HTML2COLOR(0x00FFFF) +#define Cyan Aqua +#define Lime HTML2COLOR(0x00FF00) +#define Maroon HTML2COLOR(0x800000) +#define Navy HTML2COLOR(0x000080) +#define Olive HTML2COLOR(0x808000) +#define Purple HTML2COLOR(0x800080) +#define Silver HTML2COLOR(0xC0C0C0) +#define Teal HTML2COLOR(0x008080) +#define Orange HTML2COLOR(0xFFA500) +#define Pink HTML2COLOR(0xFFC0CB) +#define SkyBlue HTML2COLOR(0x87CEEB) +/** @} */ + +#if defined(__DOXYGEN__) + /** + * @brief The color system (grayscale, palette or truecolor) + */ + #define COLOR_SYSTEM GDISP_COLORSYSTEM_TRUECOLOR + /** + * @brief The number of bits in a color value + */ + #define COLOR_BITS 16 + /** + * @brief The number of bits for each of red, green and blue + * @{ + */ + #define COLOR_BITS_R 5 + #define COLOR_BITS_G 6 + #define COLOR_BITS_B 5 + /** @} */ + /** + * @brief The number of bits to shift each of red, green and blue to put it in the correct place in the color + * @{ + */ + #define COLOR_SHIFT_R 11 + #define COLOR_SHIFT_G 5 + #define COLOR_SHIFT_B 0 + /** @} */ + /** + * @brief Does the color need masking to remove invalid bits + */ + #define COLOR_NEEDS_MASK FALSE + /** + * @brief If the color need masking to remove invalid bits, this is the mask + */ + #define COLOR_MASK 0xFFFF + /** + * @brief The color type + * @{ + */ + #define COLOR_TYPE uint16_t + /** @} */ + /** + * @brief The number of bits in the color type (not necessarily the same as COLOR_BITS). + */ + #define COLOR_TYPE_BITS 16 + /** + * @brief Convert red, green, blue (each 0 to 255) into a color value. + */ + #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xF8)<<8) | (((g) & 0xFC)<<3) | (((b) & 0xF8)>>3))) + /** + * @brief Convert a 6 digit HTML code (hex) into a color value. + */ + #define HTML2COLOR(h) ((color_t)((((h) & 0xF80000)>>8) | (((h) & 0x00FC00)>>5) | (((h) & 0x0000F8)>>3))) + /** + * @brief Extract the red/green/blue component (0 to 255) of a color value. + * @note This uses quick and dirty bit shifting. If you want more exact colors + * use @p EXACT_RED_OF() etc which uses multiplies and divides. For constant + * colors using @p EXACT_REF_OF() is no more expensive because the compiler + * evaluates the arithmetic. + * @note A 5 bit maximum value (0x1F) converts to 0xF8 (slightly off-color) + * @{ + */ + #define RED_OF(c) (((c) & 0xF800)>>8) + #define GREEN_OF(c) (((c)&0x007E)>>3) + #define BLUE_OF(c) (((c)&0x001F)<<3) + /** @} */ + /** + * @brief Extract the exact red/green/blue component (0 to 255) of a color value. + * @note This uses multiplies and divides rather than bit shifting. + * This gives exact equivalent colors at the expense of more cpu intensive + * operations. Note for constants this is no more expensive than @p REF_OF() + * because the compiler evaluates the arithmetic. + * @note A 5 bit maximum value (0x1F) converts to 0xFF ( the true equivalent color) + * @{ + */ + #define EXACT_RED_OF(c) (((((c)>>11)&0x1F)*255)/31) + #define EXACT_GREEN_OF(c) (((((c)>>5)&0x3F)*255)/63) + #define EXACT_BLUE_OF(c) (((((c)>>0)&0x1F)*255)/31) + /** @} */ +#endif + +/* + * We use this big mess of macros to calculate all the components + * to prevent user errors in the color definitions. It greatly simplifies + * the above definitions and ensures a consistent implementation. + */ + +//------------------------- +// True-Color color system +//------------------------- +#if GDISP_PIXELFORMAT & GDISP_COLORSYSTEM_TRUECOLOR + #define COLOR_SYSTEM GDISP_COLORSYSTEM_TRUECOLOR + + // Calculate the number of bits + #define COLOR_BITS_R ((GDISP_PIXELFORMAT>>8) & 0x0F) + #define COLOR_BITS_G ((GDISP_PIXELFORMAT>>4) & 0x0F) + #define COLOR_BITS_B ((GDISP_PIXELFORMAT>>0) & 0x0F) + #define COLOR_BITS (COLOR_BITS_R + COLOR_BITS_G + COLOR_BITS_B) + + // From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking + #if COLOR_BITS <= 8 + #define COLOR_TYPE uint8_t + #define COLOR_TYPE_BITS 8 + #elif COLOR_BITS <= 16 + #define COLOR_TYPE uint16_t + #define COLOR_TYPE_BITS 16 + #elif COLOR_BITS <= 32 + #define COLOR_TYPE uint32_t + #define COLOR_TYPE_BITS 32 + #else + #error "GDISP: Cannot define color types with more than 32 bits" + #endif + #if COLOR_TYPE_BITS == COLOR_BITS + #define COLOR_NEEDS_MASK FALSE + #else + #define COLOR_NEEDS_MASK TRUE + #endif + #define COLOR_MASK() ((1 << COLOR_BITS)-1) + + // Calculate the component bit shifts + #if (GDISP_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_RGB + #define COLOR_SHIFT_R (COLOR_BITS_B+COLOR_BITS_G) + #define COLOR_SHIFT_G COLOR_BITS_B + #define COLOR_SHIFT_B 0 + #else + #define COLOR_SHIFT_B (COLOR_BITS_R+COLOR_BITS_G) + #define COLOR_SHIFT_G COLOR_BITS_R + #define COLOR_SHIFT_R 0 + #endif + + // Calculate RED_OF, GREEN_OF, BLUE_OF and RGB2COLOR + #if COLOR_BITS_R + COLOR_SHIFT_R == 8 + #define RED_OF(val) ((val) & (((1< 8 + #define RED_OF(val) (((val) & (((1<> (COLOR_BITS_R+COLOR_SHIFT_R-8)) + #define RGB2COLOR_R(val) (((COLOR_TYPE)((val) & (0xFF & ~((1<<(8-COLOR_BITS_R))-1)))) << (COLOR_BITS_R+COLOR_SHIFT_R-8)) + #else // COLOR_BITS_R + COLOR_SHIFT_R < 8 + #define RED_OF(val) (((val) & (((1<> (8-(COLOR_BITS_R+COLOR_SHIFT_R))) + #endif + #if COLOR_BITS_G + COLOR_SHIFT_G == 8 + #define GREEN_OF(val) ((val) & (((1< 8 + #define GREEN_OF(val) (((val) & (((1<> (COLOR_BITS_G+COLOR_SHIFT_G-8)) + #define RGB2COLOR_G(val) (((COLOR_TYPE)((val) & (0xFF & ~((1<<(8-COLOR_BITS_G))-1)))) << (COLOR_BITS_G+COLOR_SHIFT_G-8)) + #else // COLOR_BITS_G + COLOR_SHIFT_G < 8 + #define GREEN_OF(val) (((val) & (((1<> (8-(COLOR_BITS_G+COLOR_SHIFT_G))) + #endif + #if COLOR_BITS_B + COLOR_SHIFT_B == 8 + #define BLUE_OF(val) ((val) & (((1< 8 + #define BLUE_OF(val) (((val) & (((1<> (COLOR_BITS_B+COLOR_SHIFT_B-8)) + #define RGB2COLOR_B(val) (((COLOR_TYPE)((val) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1)))) << (COLOR_BITS_B+COLOR_SHIFT_B-8)) + #else // COLOR_BITS_B + COLOR_SHIFT_B < 8 + #define BLUE_OF(val) (((val) & (((1<> (8-(COLOR_BITS_B+COLOR_SHIFT_B))) + #endif + #define EXACT_RED_OF(val) (((((val)>>COLOR_SHIFT_R)&((1<>COLOR_SHIFT_G)&((1<>COLOR_SHIFT_B)&((1< 24 + #define HTML2COLOR_R(val) (((val) & ((0xFF & ~((1<<(8-COLOR_BITS_R))-1))<<16)) << (COLOR_BITS_R+COLOR_SHIFT_R-24)) + #else // COLOR_BITS_R + COLOR_SHIFT_R < 24 + #define HTML2COLOR_R(val) (((val) & ((0xFF & ~((1<<(8-COLOR_BITS_R))-1))<<16)) >> (24-(COLOR_BITS_R+COLOR_SHIFT_R))) + #endif + #if COLOR_BITS_G + COLOR_SHIFT_G == 16 + #define HTML2COLOR_G(val) ((val) & ((0xFF & ~((1<<(8-COLOR_BITS_G))-1))<<8)) + #elif COLOR_BITS_G + COLOR_SHIFT_G > 16 + #define HTML2COLOR_G(val) (((val) & ((0xFF & ~((1<<(8-COLOR_BITS_G))-1))<<8)) << (COLOR_BITS_G+COLOR_SHIFT_G-16)) + #else // COLOR_BITS_G + COLOR_SHIFT_G < 16 + #define HTML2COLOR_G(val) (((val) & ((0xFF & ~((1<<(8-COLOR_BITS_G))-1))<<8)) >> (16-(COLOR_BITS_G+COLOR_SHIFT_G))) + #endif + #if COLOR_BITS_B + COLOR_SHIFT_B == 8 + #define HTML2COLOR_B(val) ((val) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1))) + #elif COLOR_BITS_B + COLOR_SHIFT_B > 8 + #define HTML2COLOR_B(val) (((val) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1))) << (COLOR_BITS_B+COLOR_SHIFT_B-8)) + #else // COLOR_BITS_B + COLOR_SHIFT_B < 8 + #define HTML2COLOR_B(val) (((val) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1))) >> (8-(COLOR_BITS_B+COLOR_SHIFT_B))) + #endif + #define HTML2COLOR(h) ((COLOR_TYPE)(HTML2COLOR_R(h) | HTML2COLOR_G(h) | HTML2COLOR_B(h))) + +//------------------------- +// Gray-scale color system +//------------------------- +#elif (GDISP_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_GRAYSCALE + #define COLOR_SYSTEM GDISP_COLORSYSTEM_GRAYSCALE + + // Calculate the number of bits and shifts + #define COLOR_BITS (GDISP_PIXELFORMAT & 0xFF) + #define COLOR_BITS_R COLOR_BITS + #define COLOR_BITS_G COLOR_BITS + #define COLOR_BITS_B COLOR_BITS + #define COLOR_SHIFT_R 0 + #define COLOR_SHIFT_G 0 + #define COLOR_SHIFT_B 0 + + // From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking + #if COLOR_BITS <= 8 + #define COLOR_TYPE uint8_t + #define COLOR_TYPE_BITS 8 + #else + #error "GDISP: Cannot define gray-scale color types with more than 8 bits" + #endif + #if COLOR_TYPE_BITS == COLOR_BITS + #define COLOR_NEEDS_MASK FALSE + #else + #define COLOR_NEEDS_MASK TRUE + #endif + #define COLOR_MASK() ((1 << COLOR_BITS)-1) + + #if COLOR_BITS == 1 + #define RGB2COLOR(r,g,b) (((r)|(g)|(b)) ? 1 : 0) + #define HTML2COLOR(h) ((h) ? 1 : 0) + #define RED_OF(c) ((c) ? 255 : 0) + #define GREEN_OF(c) RED_OF(c) + #define BLUE_OF(c) RED_OF(c) + #define EXACT_RED_OF(val) RED_OF(c) + #define EXACT_GREEN_OF(val) RED_OF(c) + #define EXACT_BLUE_OF(val) RED_OF(c) + #else + // They eye is more sensitive to green + #define RGB2COLOR(r,g,b) ((COLOR_TYPE)(((uint16_t)(r)+(g)+(g)+(b)) >> (10-COLOR_BITS))) + #define HTML2COLOR(h) ((COLOR_TYPE)(((((h)&0xFF0000)>>16)+(((h)&0x00FF00)>>7)+((h)&0x0000FF)) >> (10-COLOR_BITS))) + #define RED_OF(val) (((val) & ((1< 1, this should - * also be explicitly defined to ensure the best match + * @note When GDISP_TOTAL_CONTROLLERS > 1, this must + * be explicitly defined and should ensure the best match * with your hardware across all devices. - * @note Should be set to one of the following: - * GDISP_PIXELFORMAT_RGB565 - * GDISP_PIXELFORMAT_BGR565 - * GDISP_PIXELFORMAT_RGB888 - * GDISP_PIXELFORMAT_RGB444 - * GDISP_PIXELFORMAT_RGB332 - * GDISP_PIXELFORMAT_RGB666 - * GDISP_PIXELFORMAT_CUSTOM - * @note If you set GDISP_PIXELFORMAT_CUSTOM you need to also define - * color_t, RGB2COLOR(r,g,b), HTML2COLOR(h), - * RED_OF(c), GREEN_OF(c), BLUE_OF(c), - * COLOR(c) and MASKCOLOR. */ #ifndef GDISP_PIXELFORMAT #define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_ERROR #endif /** * @brief Do pixels require packing for a blit - * @note Is only valid for a pixel format that doesn't fill it's datatype. ie formats: + * @note Is only valid for a pixel format that doesn't fill it's datatype. eg formats: * GDISP_PIXELFORMAT_RGB888 * GDISP_PIXELFORMAT_RGB444 * GDISP_PIXELFORMAT_RGB666 * GDISP_PIXELFORMAT_CUSTOM - * @note If you use GDISP_PIXELFORMAT_CUSTOM and packed bit fills - * you need to also define @p gdispPackPixels(buf,cx,x,y,c) - * @note If you are using GDISP_HARDWARE_BITFILLS = FALSE then the pixel - * format must not be a packed format as the software blit does - * not support packed pixels * @note Very few cases should actually require packed pixels as the low * level driver can also pack on the fly as it is sending it * to the graphics device. + * @note Packed pixels are not really supported at this point. */ #ifndef GDISP_PACKED_PIXELS #define GDISP_PACKED_PIXELS FALSE @@ -233,114 +182,8 @@ extern GDisplay *GDISP; /* Defines related to the pixel format */ /*===========================================================================*/ -#if defined(__DOXYGEN__) - /** - * @brief The color of a pixel. - */ - typedef uint16_t color_t; - /** - * @brief Convert a number (of any type) to a color_t. - * @details Masks any invalid bits in the color - */ - #define COLOR(c) ((color_t)(c)) - /** - * @brief Does the color_t type contain invalid bits that need masking. - */ - #define MASKCOLOR FALSE - /** - * @brief Convert red, green, blue (each 0 to 255) into a color value. - */ - #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xF8)<<8) | (((g) & 0xFC)<<3) | (((b) & 0xF8)>>3))) - /** - * @brief Convert a 6 digit HTML code (hex) into a color value. - */ - #define HTML2COLOR(h) ((color_t)((((h) & 0xF80000)>>8) | (((h) & 0x00FC00)>>5) | (((h) & 0x0000F8)>>3))) - /** - * @brief Extract the red component (0 to 255) of a color value. - */ - #define RED_OF(c) (((c) & 0xF800)>>8) - /** - * @brief Extract the green component (0 to 255) of a color value. - */ - #define GREEN_OF(c) (((c)&0x007E)>>3) - /** - * @brief Extract the blue component (0 to 255) of a color value. - */ - #define BLUE_OF(c) (((c)&0x001F)<<3) - -#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_MONO - typedef uint8_t color_t; - #define COLOR(c) ((color_t)(c)) - #define MASKCOLOR TRUE - #define RGB2COLOR(r,g,b) ((r|g|b) ? 1 : 0) - #define HTML2COLOR(h) (h ? 1 : 0) - #define RED_OF(c) (c ? 255 : 0) - #define GREEN_OF(c) (c ? 255 : 0) - #define BLUE_OF(c) (c ? 255 : 0) - -#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565 - typedef uint16_t color_t; - #define COLOR(c) ((color_t)(c)) - #define MASKCOLOR FALSE - #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xF8)<<8) | (((g) & 0xFC)<<3) | (((b) & 0xF8)>>3))) - #define HTML2COLOR(h) ((color_t)((((h) & 0xF80000)>>8) | (((h) & 0x00FC00)>>5) | (((h) & 0x0000F8)>>3))) - #define RED_OF(c) (((c)&0xF800)>>8) - #define GREEN_OF(c) (((c)&0x07E0)>>3) - #define BLUE_OF(c) (((c)&0x001F)<<3) - -#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_BGR565 - typedef uint16_t color_t; - #define COLOR(c) ((color_t)(c)) - #define MASKCOLOR FALSE - #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xF8)>>3) | (((g) & 0xFC)<<3) | (((b) & 0xF8)<<8))) - #define HTML2COLOR(h) ((color_t)((((h) & 0x0000F8)>>3) | (((h) & 0x00FC00)>>5) | (((h) & 0xF80000)>>8))) - #define RED_OF(c) (((c)&0x001F)<<3) - #define GREEN_OF(c) (((c)&0x07E0)>>3) - #define BLUE_OF(c) (((c)& 0xF800)>>8) - -#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888 - typedef uint32_t color_t; - #define COLOR(c) ((color_t)(((c) & 0xFFFFFF))) - #define MASKCOLOR TRUE - #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xFF)<<16) | (((g) & 0xFF) << 8) | ((b) & 0xFF))) - #define HTML2COLOR(h) ((color_t)(h)) - #define RED_OF(c) (((c) & 0xFF0000)>>16) - #define GREEN_OF(c) (((c)&0x00FF00)>>8) - #define BLUE_OF(c) ((c)&0x0000FF) - -#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB444 - typedef uint16_t color_t; - #define COLOR(c) ((color_t)(((c) & 0x0FFF))) - #define MASKCOLOR TRUE - #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xF0)<<4) | ((g) & 0xF0) | (((b) & 0xF0)>>4))) - #define HTML2COLOR(h) ((color_t)((((h) & 0xF00000)>>12) | (((h) & 0x00F000)>>8) | (((h) & 0x0000F0)>>4))) - #define RED_OF(c) (((c) & 0x0F00)>>4) - #define GREEN_OF(c) ((c)&0x00F0) - #define BLUE_OF(c) (((c)&0x000F)<<4) - -#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB332 - typedef uint8_t color_t; - #define COLOR(c) ((color_t)(c)) - #define MASKCOLOR FALSE - #define RGB2COLOR(r,g,b) ((color_t)(((r) & 0xE0) | (((g) & 0xE0)>>3) | (((b) & 0xC0)>>6))) - #define HTML2COLOR(h) ((color_t)((((h) & 0xE00000)>>16) | (((h) & 0x00E000)>>11) | (((h) & 0x0000C0)>>6))) - #define RED_OF(c) ((c) & 0xE0) - #define GREEN_OF(c) (((c)&0x1C)<<3) - #define BLUE_OF(c) (((c)&0x03)<<6) - -#elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB666 - typedef uint32_t color_t; - #define COLOR(c) ((color_t)(((c) & 0x03FFFF))) - #define MASKCOLOR TRUE - #define RGB2COLOR(r,g,b) ((color_t)((((r) & 0xFC)<<10) | (((g) & 0xFC)<<4) | (((b) & 0xFC)>>2))) - #define HTML2COLOR(h) ((color_t)((((h) & 0xFC0000)>>6) | (((h) & 0x00FC00)>>4) | (((h) & 0x0000FC)>>2))) - #define RED_OF(c) (((c) & 0x03F000)>>12) - #define GREEN_OF(c) (((c)&0x00FC00)>>8) - #define BLUE_OF(c) (((c)&0x00003F)<<2) - -#elif GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_CUSTOM - #error "GDISP: No supported pixel format has been specified." -#endif +/* Load our color definitions and pixel formats */ +#include "colors.h" /** * @brief The type of a pixel. From e35b76388cdc32e275962a19932c64a2ce0ee52d Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 5 Nov 2013 13:43:28 +1000 Subject: [PATCH 148/160] Fix to streaming read pixel for Win32 driver in emulation mode. --- drivers/multiple/Win32/gdisp_lld_Win32.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/multiple/Win32/gdisp_lld_Win32.c b/drivers/multiple/Win32/gdisp_lld_Win32.c index 65baf903..6cbf9cd4 100644 --- a/drivers/multiple/Win32/gdisp_lld_Win32.c +++ b/drivers/multiple/Win32/gdisp_lld_Win32.c @@ -641,20 +641,20 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_NEED_CONTROL switch(g->g.Orientation) { case GDISP_ROTATE_0: - color = GetPixel(priv->dcBuffer, g->p.x, g->p.y); + color = GetPixel(priv->dcBuffer, priv->x, priv->y); break; case GDISP_ROTATE_90: - color = GetPixel(priv->dcBuffer, g->p.y, g->g.Width - 1 - g->p.x); + color = GetPixel(priv->dcBuffer, priv->y, g->g.Width - 1 - priv->x); break; case GDISP_ROTATE_180: - color = GetPixel(priv->dcBuffer, g->g.Width - 1 - g->p.x, g->g.Height - 1 - g->p.y); + color = GetPixel(priv->dcBuffer, g->g.Width - 1 - priv->x, g->g.Height - 1 - priv->y); break; case GDISP_ROTATE_270: - color = GetPixel(priv->dcBuffer, g->g.Height - 1 - g->p.y, g->p.x); + color = GetPixel(priv->dcBuffer, g->g.Height - 1 - priv->y, priv->x); break; } #else - color = GetPixel(priv->dcBuffer, g->p.x, g->p.y); + color = GetPixel(priv->dcBuffer, priv->x, priv->y); #endif ReleaseMutex(drawMutex); From 009d9f1f60d6d77f6ed75e8c5fc93e5e979e9db0 Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 5 Nov 2013 13:44:12 +1000 Subject: [PATCH 149/160] English grammer correction --- include/gdisp/colors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/gdisp/colors.h b/include/gdisp/colors.h index 975934d0..486424b7 100644 --- a/include/gdisp/colors.h +++ b/include/gdisp/colors.h @@ -119,7 +119,7 @@ */ #define COLOR_NEEDS_MASK FALSE /** - * @brief If the color need masking to remove invalid bits, this is the mask + * @brief If the color needs masking to remove invalid bits, this is the mask */ #define COLOR_MASK 0xFFFF /** From 250adaf028848c0aa0dfa2029b722274cb7a6d6a Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 5 Nov 2013 13:45:19 +1000 Subject: [PATCH 150/160] Fixes to gdisp vertical scrolling. Also added improved optimisation for drivers without blit but with a fill routine. --- src/gdisp/gdisp.c | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 263e882d..b08fe627 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -1041,7 +1041,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c if (!g->vmt->setclip) #endif { - // This is a different cliping to fillarea(g) as it needs to take into account srcx,srcy + // This is a different clipping to fillarea(g) as it needs to take into account srcx,srcy if (x < g->clipx0) { cx -= g->clipx0 - x; srcx += g->clipx0 - x; x = g->clipx0; } if (y < g->clipy0) { cy -= g->clipy0 - y; srcy += g->clipy0 - x; y = g->clipy0; } if (x+cx > g->clipx1) cx = g->clipx1 - x; @@ -2130,7 +2130,7 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c #if GDISP_NEED_SCROLL void gdispGVerticalScroll(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, int lines, color_t bgcolor) { coord_t abslines; - #if !GDISP_HARDWARE_SCROLL + #if GDISP_HARDWARE_SCROLL != TRUE coord_t fy, dy, ix, fx, i, j; #endif @@ -2232,9 +2232,11 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c } } #if GDISP_HARDWARE_PIXELREAD == HARDWARE_AUTODETECT - else + else { // Worst is "not possible" + MUTEX_EXIT(g); return; + } #endif #endif @@ -2291,8 +2293,40 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c #endif #endif + // Next best line write is drawing pixels in combination with filling + #if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS && GDISP_HARDWARE_DRAWPIXEL + // We don't need to test for auto-detect on drawpixel as we know we have it because we don't have streaming. + #if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT + if (g->vmt->fill) + #endif + { + g->p.y = fy; + g->p.cy = 1; + g->p.x = x+ix; + g->p.cx = 1; + for(j = 0; j < fx; ) { + g->p.color = g->linebuf[j]; + if (j + g->p.cx < fx && g->linebuf[j] == g->linebuf[j + g->p.cx]) + g->p.cx++; + else if (g->p.cx == 1) { + gdisp_lld_draw_pixel(g); + j++; + g->p.x++; + } else { + gdisp_lld_fill_area(g); + j += g->p.cx; + g->p.x += g->p.cx; + g->p.cx = 1; + } + } + } + #if GDISP_HARDWARE_FILLS == HARDWARE_AUTODETECT + else + #endif + #endif + // Worst line write is drawing pixels - #if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_DRAWPIXEL + #if GDISP_HARDWARE_BITFILLS != TRUE && GDISP_HARDWARE_STREAM_WRITE != TRUE && GDISP_HARDWARE_FILLS != TRUE && GDISP_HARDWARE_DRAWPIXEL // The following test is unneeded because we are guaranteed to have draw pixel if we don't have streaming //#if GDISP_HARDWARE_DRAWPIXEL == HARDWARE_AUTODETECT // if (g->vmt->pixel) From a8e860678df38fdb44f94cacae52e8d54f4374ff Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 5 Nov 2013 19:34:12 +1000 Subject: [PATCH 151/160] New GDISP now supports multiple controllers with different pixel formats. You can now have a main color display and a secondary monochrome display. You can now optionally set GDISP_PIXELFORMAT to any color or grayscale format for your application and the driver will internally convert to the display hardware format. --- drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c | 2 +- drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c | 2 +- drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c | 7 +- drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c | 7 +- drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c | 7 +- drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c | 7 +- .../Nokia6610GE12/gdisp_lld_Nokia6610GE12.c | 13 +- .../Nokia6610GE8/gdisp_lld_Nokia6610GE8.c | 39 ++- drivers/gdisp/RA8875/gdisp_lld_RA8875.c | 2 +- drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c | 7 +- drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c | 16 +- drivers/gdisp/SSD1289/gdisp_lld_config.h | 7 +- drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c | 2 +- drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c | 2 +- drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c | 16 +- drivers/gdisp/SSD2119/gdisp_lld_config.h | 5 +- drivers/gdisp/ST7565/gdisp_lld_ST7565.c | 2 +- drivers/multiple/Win32/gdisp_lld_Win32.c | 29 +- drivers/multiple/Win32/gdisp_lld_config.h | 12 +- include/gdisp/colors.h | 118 +++++---- include/gdisp/lld/gdisp_lld.h | 248 ++++++++++++++++++ 21 files changed, 442 insertions(+), 108 deletions(-) diff --git a/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c b/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c index 14e7f88a..3ab1de79 100644 --- a/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c +++ b/drivers/gdisp/ED060SC4/gdisp_lld_ED060SC4.c @@ -524,7 +524,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { bitpos = (6 - 2 * (dx % EINK_PPB)); byte = block->data[dy][dx / EINK_PPB]; byte &= ~(PIXELMASK << bitpos); - if (g->p.color != Black) + if (COLOR2NATIVE(g->p.color) != Black) byte |= PIXEL_WHITE << bitpos; else byte |= PIXEL_BLACK << bitpos; diff --git a/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c b/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c index fecf115c..4514b495 100644 --- a/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c +++ b/drivers/gdisp/HX8347D/gdisp_lld_HX8347D.c @@ -167,7 +167,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { busmode16(g); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_ram16(g, g->p.color); + write_ram16(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { busmode8(g); diff --git a/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c b/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c index a18c2d82..e65e0a77 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c +++ b/drivers/gdisp/ILI9320/gdisp_lld_ILI9320.c @@ -204,7 +204,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #endif } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_data(g, g->p.color); + write_data(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); @@ -225,7 +225,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { dummy_read(g); } LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { - return read_data(g); + uint16_t data; + + data = read_data(g); + return NATIVE2COLOR(data); } LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { setwritemode(g); diff --git a/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c b/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c index 75b4cd13..ffd67cf7 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c +++ b/drivers/gdisp/ILI9325/gdisp_lld_ILI9325.c @@ -200,7 +200,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { set_viewport(g); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_data(g, g->p.color); + write_data(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); @@ -219,7 +219,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { dummy_read(g); } LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { - return read_data(g); + uint16_t data; + + data = read_data(g); + return NATIVE2COLOR(data); } LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { setwritemode(g); diff --git a/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c b/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c index 33ca68d4..2513c48d 100644 --- a/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c +++ b/drivers/gdisp/ILI9341/gdisp_lld_ILI9341.c @@ -246,7 +246,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { write_index(g, 0x2C); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_data16(g, g->p.color); + write_data16(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); @@ -262,7 +262,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { dummy_read(g); } LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { - return read_data(g); + uint16_t data; + + data = read_data(g); + return NATIVE2COLOR(data); } LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { setwritemode(g); diff --git a/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c b/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c index 49e28b23..2b2f0917 100644 --- a/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c +++ b/drivers/gdisp/ILI9481/gdisp_lld_ILI9481.c @@ -211,7 +211,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { set_viewport(g); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_data(g, g->p.color); + write_data(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); @@ -226,7 +226,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { dummy_read(g); } LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { - return read_data(g); + uint16_t data; + + data = read_data(g); + return NATIVE2COLOR(data); } LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { setwritemode(g); diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c index d1086c46..28a2fceb 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld_Nokia6610GE12.c @@ -70,8 +70,8 @@ /*===========================================================================*/ // Use the priv pointer itself to save our color. This save allocating ram for it -// and works provided sizeof(color_t) <= sizeof(void *) -#define savecolor(g) (*(color_t *)&g->priv) +// and works provided sizeof(uint16_t) <= sizeof(void *) +#define savecolor(g) (*(uint16_t *)&g->priv) #define GDISP_FLG_ODDBYTE (GDISP_FLG_DRIVER<<0) @@ -143,14 +143,17 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { g->flags &= ~GDISP_FLG_ODDBYTE; } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + uint16_t c; + + c = COLOR2NATIVE(g->p.color); if ((g->flags & GDISP_FLG_ODDBYTE)) { // Write the pair of pixels to the display write_data3(g, ((savecolor(g) >> 4) & 0xFF), - (((savecolor(g) << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), - (g->p.color & 0xFF)); + (((savecolor(g) << 4) & 0xF0)|((c >> 8) & 0x0F)), + (c & 0xFF)); g->flags &= ~GDISP_FLG_ODDBYTE; } else { - savecolor(g) = g->p.color; + savecolor(g) = c; g->flags |= GDISP_FLG_ODDBYTE; } } diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c index e0cfb997..f6ce4278 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld_Nokia6610GE8.c @@ -111,9 +111,9 @@ #if GDISP_HARDWARE_STREAM_WRITE typedef struct dvrPriv { - color_t savecolor; + uint16_t savecolor; #if GDISP_GE8_BROKEN_CONTROLLER - color_t firstcolor; + uint16_t firstcolor; #endif } dvrPriv; #define PRIV ((dvrPriv *)g->priv) @@ -231,20 +231,23 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { g->flags &= ~(GDISP_FLG_ODDBYTE|GDISP_FLG_RUNBYTE); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { + uint16_t c; + + c = COLOR2NATIVE(g->p.color); #if GDISP_GE8_BROKEN_CONTROLLER if (!(g->flags & GDISP_FLG_RUNBYTE)) { - PRIV->firstcolor = g->p.color; + PRIV->firstcolor = c; g->flags |= GDISP_FLG_RUNBYTE; } #endif if ((g->flags & GDISP_FLG_ODDBYTE)) { // Write the pair of pixels to the display write_data3(g, ((PRIV->savecolor >> 4) & 0xFF), - (((PRIV->savecolor << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), - (g->p.color & 0xFF)); + (((PRIV->savecolor << 4) & 0xF0)|((c >> 8) & 0x0F)), + (c & 0xFF)); g->flags &= ~GDISP_FLG_ODDBYTE; } else { - PRIV->savecolor = g->p.color; + PRIV->savecolor = c; g->flags |= GDISP_FLG_ODDBYTE; } } @@ -284,9 +287,12 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_HARDWARE_DRAWPIXEL LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) { + uint16_t c; + + c = COLOR2NATIVE(g->p.color); acquire_bus(g); set_viewport(g); - write_data3(g, 0, (g->p.color>>8) & 0x0F, g->p.color & 0xFF); + write_data3(g, 0, (c>>8) & 0x0F, c & 0xFF); release_bus(g); } #endif @@ -295,15 +301,17 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_HARDWARE_FILLS LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { - unsigned tuples; + unsigned tuples; + uint16_t c; tuples = (g->p.cx*g->p.cy+1)>>1; // With an odd sized area we over-print by one pixel. // This extra pixel overwrites the first pixel (harmless as it is the same colour) + c = COLOR2NATIVE(g->p.color); acquire_bus(g); set_viewport(g); while(tuples--) - write_data3(g, ((g->p.color >> 4) & 0xFF), (((g->p.color << 4) & 0xF0)|((g->p.color >> 8) & 0x0F)), (g->p.color & 0xFF)); + write_data3(g, ((c >> 4) & 0xFF), (((c << 4) & 0xF0)|((c >> 8) & 0x0F)), (c & 0xFF)); release_bus(g); } #endif @@ -311,7 +319,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_HARDWARE_BITFILLS LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { coord_t lg, x, y; - color_t c1, c2; + uint16_t c1, c2; unsigned tuples; const pixel_t *buffer; #if GDISP_PACKED_PIXELS @@ -328,7 +336,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { acquire_bus(g); set_viewport(g); - /* to surpress compiler warnings */ + /* to suppress compiler warnings */ x = 0; y = 0; @@ -356,7 +364,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { while(tuples--) { /* Get a pixel */ - c1 = *p++; + c1 = COLOR2NATIVE(*p++); /* Check for line or buffer wrapping */ if (++x >= g->p.cx) { @@ -369,7 +377,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { } /* Get the next pixel */ - c2 = *p++; + c2 = COLOR2NATIVE(*p++); /* Check for line or buffer wrapping */ if (++x >= g->p.cx) { @@ -385,7 +393,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { write_data3(g, ((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF)); } - #else + #elif GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT // Although this controller uses packed pixels, we may have to feed it into // the controller with different packing to the source bitmap @@ -440,6 +448,9 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { /* Write the pair of pixels to the display */ write_data3(g, ((c1 >> 4) & 0xFF), (((c1 << 4) & 0xF0)|((c2 >> 8) & 0x0F)), (c2 & 0xFF)); } + + #else + #error "Packed pixels is broken if you are not running native pixel format" #endif /* All done */ diff --git a/drivers/gdisp/RA8875/gdisp_lld_RA8875.c b/drivers/gdisp/RA8875/gdisp_lld_RA8875.c index fb81c43a..d28670c6 100644 --- a/drivers/gdisp/RA8875/gdisp_lld_RA8875.c +++ b/drivers/gdisp/RA8875/gdisp_lld_RA8875.c @@ -184,7 +184,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { set_viewport(g); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_data(g, g->p.color); + write_data(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); diff --git a/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c b/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c index cbaa7199..cca9d67e 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c +++ b/drivers/gdisp/S6D1121/gdisp_lld_S6D1121.c @@ -221,7 +221,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { set_viewport(g); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_data(g, g->p.color); + write_data(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); @@ -240,7 +240,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { dummy_read(g); } LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { - return read_data(g); + uint16_t data; + + data = read_data(g); + return NATIVE2COLOR(data); } LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { setwritemode(g); diff --git a/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c b/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c index 6692e7d7..a33b6564 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c +++ b/drivers/gdisp/SSD1289/gdisp_lld_SSD1289.c @@ -200,7 +200,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #endif } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_data(g, g->p.color); + write_data(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); @@ -221,7 +221,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { dummy_read(g); } LLDSPEC color_t gdisp_lld_read_color(GDisplay *g) { - return read_data(g); + uint16_t data; + + data = read_data(g); + return NATIVE2COLOR(data); } LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { setwritemode(g); @@ -231,15 +234,22 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #if GDISP_HARDWARE_FILLS && defined(GDISP_USE_DMA) LLDSPEC void gdisp_lld_fill_area(GDisplay *g) { + uint16_t c; + + c = COLOR2NATIVE(g->p.color); acquire_bus(g); set_viewport(g); set_cursor(g); - dma_with_noinc(g, &color, g->p.cx*g->p.cy) + dma_with_noinc(g, &c, g->p.cx*g->p.cy) release_bus(g); } #endif #if GDISP_HARDWARE_BITFILLS && defined(GDISP_USE_DMA) + #if GDISP_PIXELFORMAT != GDISP_LLD_PIXELFORMAT + #error "GDISP: SSD1289: BitBlit is only available in RGB565 pixel format" + #endif + LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { pixel_t *buffer; coord_t ycnt; diff --git a/drivers/gdisp/SSD1289/gdisp_lld_config.h b/drivers/gdisp/SSD1289/gdisp_lld_config.h index 4cf5fa5c..a9166553 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld_config.h +++ b/drivers/gdisp/SSD1289/gdisp_lld_config.h @@ -28,8 +28,11 @@ #define GDISP_HARDWARE_CONTROL TRUE #if defined(GDISP_USE_DMA) - #define GDISP_HARDWARE_FILLS TRUE - #define GDISP_HARDWARE_BITFILLS TRUE + #define GDISP_HARDWARE_FILLS TRUE + #if !defined(GDISP_PIXELFORMAT) || GDISP_PIXELFORMAT == 0x2565 + // Hardware BitBlts are only supported in native pixel format on this controller + #define GDISP_HARDWARE_BITFILLS TRUE + #endif #endif #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 diff --git a/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c b/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c index bd3e386d..b72ba781 100644 --- a/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c +++ b/drivers/gdisp/SSD1306/gdisp_lld_SSD1306.c @@ -176,7 +176,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { x = g->p.x; break; } - if (g->p.color != Black) + if (COLOR2NATIVE(g->p.color) != Black) RAM(g)[xyaddr(x, y)] |= xybit(y); else RAM(g)[xyaddr(x, y)] &= ~xybit(y); diff --git a/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c b/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c index b94c1a40..eb1b9b15 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c +++ b/drivers/gdisp/SSD1963/gdisp_lld_SSD1963.c @@ -188,7 +188,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { set_viewport(g); } LLDSPEC void gdisp_lld_write_color(GDisplay *g) { - write_data(g, g->p.color); + write_data(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay *g) { release_bus(g); diff --git a/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c b/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c index df05fc2c..9594ff95 100644 --- a/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c +++ b/drivers/gdisp/SSD2119/gdisp_lld_SSD2119.c @@ -238,7 +238,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { set_viewport(g); } LLDSPEC void gdisp_lld_write_color(GDisplay* g) { - write_data(g, g->p.color); + write_data(g, COLOR2NATIVE(g->p.color)); } LLDSPEC void gdisp_lld_write_stop(GDisplay* g) { release_bus(g); @@ -257,7 +257,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { dummy_read(g); } LLDSPEC color_t gdisp_lld_read_color(GDisplay* g) { - return read_data(g); + uint16_t data; + + data = read_data(g); + return NATIVE2COLOR(data); } LLDSPEC void gdisp_lld_read_stop(GDisplay* g) { setwritemode(g); @@ -267,15 +270,22 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay* g) { #if GDISP_HARDWARE_FILLS && defined(GDISP_USE_DMA) LLDSPEC void gdisp_lld_fill_area(GDisplay* g) { + uint16_t c; + + c = COLOR2NATIVE(g->p.color); acquire_bus(g); set_viewport(g); set_cursor(g); - dma_with_noinc(g, &g->p.color, g->p.cx * g->p.cy); + dma_with_noinc(g, &c, g->p.cx * g->p.cy); release_bus(g); } #endif #if GDISP_HARDWARE_BITFILLS && defined(GDISP_USE_DMA) + #if GDISP_PIXELFORMAT != GDISP_LLD_PIXELFORMAT + #error "GDISP: SSD2119: BitBlit is only available in RGB565 pixel format" + #endif + LLDSPEC void gdisp_lld_blit_area(GDisplay* g) { pixel_t* buffer; coord_t ynct; diff --git a/drivers/gdisp/SSD2119/gdisp_lld_config.h b/drivers/gdisp/SSD2119/gdisp_lld_config.h index a974c623..ec034bef 100644 --- a/drivers/gdisp/SSD2119/gdisp_lld_config.h +++ b/drivers/gdisp/SSD2119/gdisp_lld_config.h @@ -29,7 +29,10 @@ #if defined(GDISP_USE_DMA) #define GDISP_HARDWARE_FILLS TRUE - #define GDISP_HARDWARE_BITFILLS TRUE + #if !defined(GDISP_PIXELFORMAT) || GDISP_PIXELFORMAT == 0x2565 + // Hardware BitBlts are only supported in native pixel format on this controller + #define GDISP_HARDWARE_BITFILLS TRUE + #endif #endif #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565 diff --git a/drivers/gdisp/ST7565/gdisp_lld_ST7565.c b/drivers/gdisp/ST7565/gdisp_lld_ST7565.c index bd8c7b74..2bb5406f 100644 --- a/drivers/gdisp/ST7565/gdisp_lld_ST7565.c +++ b/drivers/gdisp/ST7565/gdisp_lld_ST7565.c @@ -167,7 +167,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { y = g->p.x; break; } - if (g->p.color != Black) + if (COLOR2NATIVE(g->p.color) != Black) RAM(g)[xyaddr(x, y)] |= xybit(y); else RAM(g)[xyaddr(x, y)] &= ~xybit(y); diff --git a/drivers/multiple/Win32/gdisp_lld_Win32.c b/drivers/multiple/Win32/gdisp_lld_Win32.c index 6cbf9cd4..9484c823 100644 --- a/drivers/multiple/Win32/gdisp_lld_Win32.c +++ b/drivers/multiple/Win32/gdisp_lld_Win32.c @@ -23,9 +23,7 @@ #ifndef GDISP_SCREEN_HEIGHT #define GDISP_SCREEN_HEIGHT 480 #endif -#if GDISP_PIXELFORMAT != GDISP_PIXELFORMAT_RGB888 - #error "GDISP Win32: This driver currently only supports the RGB888 pixel format." -#endif + // Setting this to TRUE delays updating the screen // to the windows paint routine. Due to the // drawing lock this does not add as much speed @@ -89,9 +87,6 @@ static HANDLE drawMutex; #define APP_NAME "uGFX" -#define COLOR2BGR(c) ((((c) & 0xFF)<<16)|((c) & 0xFF00)|(((c)>>16) & 0xFF)) -#define BGR2COLOR(c) COLOR2BGR(c) - typedef struct winPriv { HWND hwnd; HDC dcBuffer; @@ -291,9 +286,9 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) // Paint the toggle area #if GINPUT_NEED_TOGGLE if (ps.rcPaint.bottom >= GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASTOGGLE)) { - pen = CreatePen(PS_SOLID, 1, COLOR2BGR(Black)); - hbrOn = CreateSolidBrush(COLOR2BGR(Blue)); - hbrOff = CreateSolidBrush(COLOR2BGR(Gray)); + pen = CreatePen(PS_SOLID, 1, COLOR2NATIVE(Black)); + hbrOn = CreateSolidBrush(COLOR2NATIVE(Blue)); + hbrOff = CreateSolidBrush(COLOR2NATIVE(Gray)); old = SelectObject(dc, pen); MoveToEx(dc, 0, GDISP_SCREEN_HEIGHT, &p); LineTo(dc, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT); @@ -519,7 +514,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { COLORREF color; priv = g->priv; - color = COLOR2BGR(g->p.color); + color = COLOR2NATIVE(g->p.color); if (!(g->flags & GDISP_FLG_WSTREAM)) BAD_PARAMETER("write_color: not in streaming mode"); @@ -667,7 +662,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { } } - return BGR2COLOR(color); + return NATIVE2COLOR(color); } LLDSPEC void gdisp_lld_read_stop(GDisplay *g) { if (!(g->flags & GDISP_FLG_WSTREAM)) @@ -683,7 +678,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { COLORREF color; priv = g->priv; - color = COLOR2BGR(g->p.color); + color = COLOR2NATIVE(g->p.color); #if GDISP_NEED_CONTROL switch(g->g.Orientation) { @@ -742,7 +737,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { COLORREF color; priv = g->priv; - color = COLOR2BGR(g->p.color); + color = COLOR2NATIVE(g->p.color); hbr = CreateSolidBrush(color); #if GDISP_NEED_CONTROL @@ -841,6 +836,10 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #endif #if GDISP_HARDWARE_BITFILLS + #if COLOR_SYSTEM != GDISP_COLORSYSTEM_TRUECOLOR || COLOR_TYPE_BITS <= 8 + #error "GDISP Win32: This driver's bitblit currently only supports true-color with bit depths > 8 bits." + #endif + LLDSPEC void gdisp_lld_blit_area(GDisplay *g) { winPriv * priv; pixel_t * buffer; @@ -855,7 +854,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { memset(&bmpInfo, 0, sizeof(bmpInfo)); bmpInfo.bV4Size = sizeof(bmpInfo); bmpInfo.bV4Planes = 1; - bmpInfo.bV4BitCount = sizeof(pixel_t)*8; + bmpInfo.bV4BitCount = COLOR_TYPE_BITS; bmpInfo.bV4AlphaMask = 0; bmpInfo.bV4RedMask = RGB2COLOR(255,0,0); bmpInfo.bV4GreenMask = RGB2COLOR(0,255,0); @@ -969,7 +968,7 @@ LLDSPEC bool_t gdisp_lld_init(GDisplay *g) { #endif ReleaseMutex(drawMutex); - return BGR2COLOR(color); + return NATIVE2COLOR(color); } #endif diff --git a/drivers/multiple/Win32/gdisp_lld_config.h b/drivers/multiple/Win32/gdisp_lld_config.h index 4985bc43..1554161b 100644 --- a/drivers/multiple/Win32/gdisp_lld_config.h +++ b/drivers/multiple/Win32/gdisp_lld_config.h @@ -41,11 +41,19 @@ #define GDISP_HARDWARE_DRAWPIXEL TRUE #define GDISP_HARDWARE_FILLS TRUE #define GDISP_HARDWARE_PIXELREAD TRUE - #define GDISP_HARDWARE_BITFILLS TRUE #define GDISP_HARDWARE_SCROLL TRUE + + // Bit-blits on Win32 are currently only supported for True-Color bit-depths greater than 8 bits + // Note: At the time this file is included we have not calculated all our color + // definitions so we need to do this by hand. + #if !defined(GDISP_PIXELFORMAT) + #define GDISP_HARDWARE_BITFILLS TRUE + #elif (GDISP_PIXELFORMAT & 0x2000) && (((GDISP_PIXELFORMAT & 0x0F00)>>8)+((GDISP_PIXELFORMAT & 0x00F0)>>4)+((GDISP_PIXELFORMAT & 0x000F))) > 8 + #define GDISP_HARDWARE_BITFILLS TRUE + #endif #endif -#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB888 +#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_BGR888 #endif /* GFX_USE_GDISP */ diff --git a/include/gdisp/colors.h b/include/gdisp/colors.h index 486424b7..efd7076c 100644 --- a/include/gdisp/colors.h +++ b/include/gdisp/colors.h @@ -48,6 +48,9 @@ * @{ */ #define GDISP_PIXELFORMAT_MONO (GDISP_COLORSYSTEM_GRAYSCALE|0x0001) +#define GDISP_PIXELFORMAT_GRAY4 (GDISP_COLORSYSTEM_GRAYSCALE|0x0002) +#define GDISP_PIXELFORMAT_GRAY16 (GDISP_COLORSYSTEM_GRAYSCALE|0x0004) +#define GDISP_PIXELFORMAT_GRAY256 (GDISP_COLORSYSTEM_GRAYSCALE|0x0008) #define GDISP_PIXELFORMAT_RGB565 (GDISP_COLORSYSTEM_RGB|0x0565) #define GDISP_PIXELFORMAT_BGR565 (GDISP_COLORSYSTEM_BGR|0x0565) #define GDISP_PIXELFORMAT_RGB888 (GDISP_COLORSYSTEM_RGB|0x0888) @@ -132,6 +135,15 @@ * @brief The number of bits in the color type (not necessarily the same as COLOR_BITS). */ #define COLOR_TYPE_BITS 16 + /** + * @brief Convert a luminance (0 to 255) into a color value. + * @note The word "Luma" is used instead of grey or gray due to the spelling ambiguities of the word grey + * @note This is not a weighted luminance conversion in the color tv style. + * @note @p LUMA2COLOR() uses a linear conversion (0.33R + 0.33G + 0.33B). Note this is different to color + * tv luminance (0.26126R + 0.7152G + 0.0722B), digital tv luminance of (0.299R + 0.587G + 0.114B), or + * @p LUMA_OF() which uses (0.25R + 0.5G + 0.25B). + */ + #define LUMA2COLOR(l) ((color_t)((((l) & 0xF8)<<8) | (((l) & 0xFC)<<3) | (((l) & 0xF8)>>3))) /** * @brief Convert red, green, blue (each 0 to 255) into a color value. */ @@ -141,27 +153,35 @@ */ #define HTML2COLOR(h) ((color_t)((((h) & 0xF80000)>>8) | (((h) & 0x00FC00)>>5) | (((h) & 0x0000F8)>>3))) /** - * @brief Extract the red/green/blue component (0 to 255) of a color value. + * @brief Extract the luma/red/green/blue component (0 to 255) of a color value. * @note This uses quick and dirty bit shifting. If you want more exact colors * use @p EXACT_RED_OF() etc which uses multiplies and divides. For constant - * colors using @p EXACT_REF_OF() is no more expensive because the compiler + * colors using @p EXACT_RED_OF() is no more expensive because the compiler * evaluates the arithmetic. - * @note A 5 bit maximum value (0x1F) converts to 0xF8 (slightly off-color) + * @note @p LUMA_OF() returns a roughly weighted luminance (0.25R + 0.5G + 0.25B). Note this is + * different to @p LUMA2COLOR() which uses a linear conversion (0.33R + 0.33G + 0.33B) and + * color tv luminance of (0.26126R + 0.7152G + 0.0722B) and digital tv luminance of (0.299R + 0.587G + 0.114B). + * @note A 5 bit color component maximum value (0x1F) converts to 0xF8 (slightly off-color) * @{ */ + #define LUMA_OF(c) ((RED_OF(c)+((uint16_t)GREEN_OF(c)<<1)+BLUE_OF(c))>>2) #define RED_OF(c) (((c) & 0xF800)>>8) #define GREEN_OF(c) (((c)&0x007E)>>3) #define BLUE_OF(c) (((c)&0x001F)<<3) /** @} */ /** - * @brief Extract the exact red/green/blue component (0 to 255) of a color value. + * @brief Extract the exact luma/red/green/blue component (0 to 255) of a color value. * @note This uses multiplies and divides rather than bit shifting. * This gives exact equivalent colors at the expense of more cpu intensive * operations. Note for constants this is no more expensive than @p REF_OF() * because the compiler evaluates the arithmetic. - * @note A 5 bit maximum value (0x1F) converts to 0xFF ( the true equivalent color) + * @note @p EXACT_LUMA_OF() returns a roughly weighted luminance (0.25R + 0.5G + 0.25B). Note this is + * different to @p LUMA2COLOR() which uses a linear conversion (0.33R + 0.33G + 0.33B) and + * color tv luminance of (0.26126R + 0.7152G + 0.0722B) and digital tv luminance of (0.299R + 0.587G + 0.114B). + * @note A 5 bit color component maximum value (0x1F) converts to 0xFF (the true equivalent color) * @{ */ + #define EXACT_LUMA_OF(c) ((EXACT_RED_OF(c)+((uint16_t)EXACT_GREEN_OF(c)<<1)+EXACT_BLUE_OF(c))>>2) #define EXACT_RED_OF(c) (((((c)>>11)&0x1F)*255)/31) #define EXACT_GREEN_OF(c) (((((c)>>5)&0x3F)*255)/63) #define EXACT_BLUE_OF(c) (((((c)>>0)&0x1F)*255)/31) @@ -219,61 +239,64 @@ // Calculate RED_OF, GREEN_OF, BLUE_OF and RGB2COLOR #if COLOR_BITS_R + COLOR_SHIFT_R == 8 - #define RED_OF(val) ((val) & (((1< 8 - #define RED_OF(val) (((val) & (((1<> (COLOR_BITS_R+COLOR_SHIFT_R-8)) - #define RGB2COLOR_R(val) (((COLOR_TYPE)((val) & (0xFF & ~((1<<(8-COLOR_BITS_R))-1)))) << (COLOR_BITS_R+COLOR_SHIFT_R-8)) + #define RED_OF(c) (((c) & (((1<> (COLOR_BITS_R+COLOR_SHIFT_R-8)) + #define RGB2COLOR_R(r) (((COLOR_TYPE)((r) & (0xFF & ~((1<<(8-COLOR_BITS_R))-1)))) << (COLOR_BITS_R+COLOR_SHIFT_R-8)) #else // COLOR_BITS_R + COLOR_SHIFT_R < 8 - #define RED_OF(val) (((val) & (((1<> (8-(COLOR_BITS_R+COLOR_SHIFT_R))) + #define RED_OF(c) (((c) & (((1<> (8-(COLOR_BITS_R+COLOR_SHIFT_R))) #endif #if COLOR_BITS_G + COLOR_SHIFT_G == 8 - #define GREEN_OF(val) ((val) & (((1< 8 - #define GREEN_OF(val) (((val) & (((1<> (COLOR_BITS_G+COLOR_SHIFT_G-8)) - #define RGB2COLOR_G(val) (((COLOR_TYPE)((val) & (0xFF & ~((1<<(8-COLOR_BITS_G))-1)))) << (COLOR_BITS_G+COLOR_SHIFT_G-8)) + #define GREEN_OF(c) (((c) & (((1<> (COLOR_BITS_G+COLOR_SHIFT_G-8)) + #define RGB2COLOR_G(g) (((COLOR_TYPE)((g) & (0xFF & ~((1<<(8-COLOR_BITS_G))-1)))) << (COLOR_BITS_G+COLOR_SHIFT_G-8)) #else // COLOR_BITS_G + COLOR_SHIFT_G < 8 - #define GREEN_OF(val) (((val) & (((1<> (8-(COLOR_BITS_G+COLOR_SHIFT_G))) + #define GREEN_OF(c) (((c) & (((1<> (8-(COLOR_BITS_G+COLOR_SHIFT_G))) #endif #if COLOR_BITS_B + COLOR_SHIFT_B == 8 - #define BLUE_OF(val) ((val) & (((1< 8 - #define BLUE_OF(val) (((val) & (((1<> (COLOR_BITS_B+COLOR_SHIFT_B-8)) - #define RGB2COLOR_B(val) (((COLOR_TYPE)((val) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1)))) << (COLOR_BITS_B+COLOR_SHIFT_B-8)) + #define BLUE_OF(c) (((c) & (((1<> (COLOR_BITS_B+COLOR_SHIFT_B-8)) + #define RGB2COLOR_B(b) (((COLOR_TYPE)((b) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1)))) << (COLOR_BITS_B+COLOR_SHIFT_B-8)) #else // COLOR_BITS_B + COLOR_SHIFT_B < 8 - #define BLUE_OF(val) (((val) & (((1<> (8-(COLOR_BITS_B+COLOR_SHIFT_B))) + #define BLUE_OF(c) (((c) & (((1<> (8-(COLOR_BITS_B+COLOR_SHIFT_B))) #endif - #define EXACT_RED_OF(val) (((((val)>>COLOR_SHIFT_R)&((1<>COLOR_SHIFT_G)&((1<>COLOR_SHIFT_B)&((1<>2) + #define EXACT_RED_OF(c) (((uint16_t)(((c)>>COLOR_SHIFT_R)&((1<>COLOR_SHIFT_G)&((1<>COLOR_SHIFT_B)&((1<>2) + #define LUMA2COLOR(l) (RGB2COLOR_R(l) | RGB2COLOR_G(l) | RGB2COLOR_B(l)) #define RGB2COLOR(r,g,b) (RGB2COLOR_R(r) | RGB2COLOR_G(g) | RGB2COLOR_B(b)) // Calculate HTML2COLOR #if COLOR_BITS_R + COLOR_SHIFT_R == 24 - #define HTML2COLOR_R(val) ((val) & ((0xFF & ~((1<<(8-COLOR_BITS_R))-1))<<16)) + #define HTML2COLOR_R(h) ((h) & ((0xFF & ~((1<<(8-COLOR_BITS_R))-1))<<16)) #elif COLOR_BITS_R + COLOR_SHIFT_R > 24 - #define HTML2COLOR_R(val) (((val) & ((0xFF & ~((1<<(8-COLOR_BITS_R))-1))<<16)) << (COLOR_BITS_R+COLOR_SHIFT_R-24)) + #define HTML2COLOR_R(h) (((h) & ((0xFF & ~((1<<(8-COLOR_BITS_R))-1))<<16)) << (COLOR_BITS_R+COLOR_SHIFT_R-24)) #else // COLOR_BITS_R + COLOR_SHIFT_R < 24 - #define HTML2COLOR_R(val) (((val) & ((0xFF & ~((1<<(8-COLOR_BITS_R))-1))<<16)) >> (24-(COLOR_BITS_R+COLOR_SHIFT_R))) + #define HTML2COLOR_R(h) (((h) & ((0xFF & ~((1<<(8-COLOR_BITS_R))-1))<<16)) >> (24-(COLOR_BITS_R+COLOR_SHIFT_R))) #endif #if COLOR_BITS_G + COLOR_SHIFT_G == 16 - #define HTML2COLOR_G(val) ((val) & ((0xFF & ~((1<<(8-COLOR_BITS_G))-1))<<8)) + #define HTML2COLOR_G(h) ((h) & ((0xFF & ~((1<<(8-COLOR_BITS_G))-1))<<8)) #elif COLOR_BITS_G + COLOR_SHIFT_G > 16 - #define HTML2COLOR_G(val) (((val) & ((0xFF & ~((1<<(8-COLOR_BITS_G))-1))<<8)) << (COLOR_BITS_G+COLOR_SHIFT_G-16)) + #define HTML2COLOR_G(h) (((h) & ((0xFF & ~((1<<(8-COLOR_BITS_G))-1))<<8)) << (COLOR_BITS_G+COLOR_SHIFT_G-16)) #else // COLOR_BITS_G + COLOR_SHIFT_G < 16 - #define HTML2COLOR_G(val) (((val) & ((0xFF & ~((1<<(8-COLOR_BITS_G))-1))<<8)) >> (16-(COLOR_BITS_G+COLOR_SHIFT_G))) + #define HTML2COLOR_G(h) (((h) & ((0xFF & ~((1<<(8-COLOR_BITS_G))-1))<<8)) >> (16-(COLOR_BITS_G+COLOR_SHIFT_G))) #endif #if COLOR_BITS_B + COLOR_SHIFT_B == 8 - #define HTML2COLOR_B(val) ((val) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1))) + #define HTML2COLOR_B(h) ((h) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1))) #elif COLOR_BITS_B + COLOR_SHIFT_B > 8 - #define HTML2COLOR_B(val) (((val) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1))) << (COLOR_BITS_B+COLOR_SHIFT_B-8)) + #define HTML2COLOR_B(h) (((h) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1))) << (COLOR_BITS_B+COLOR_SHIFT_B-8)) #else // COLOR_BITS_B + COLOR_SHIFT_B < 8 - #define HTML2COLOR_B(val) (((val) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1))) >> (8-(COLOR_BITS_B+COLOR_SHIFT_B))) + #define HTML2COLOR_B(h) (((h) & (0xFF & ~((1<<(8-COLOR_BITS_B))-1))) >> (8-(COLOR_BITS_B+COLOR_SHIFT_B))) #endif #define HTML2COLOR(h) ((COLOR_TYPE)(HTML2COLOR_R(h) | HTML2COLOR_G(h) | HTML2COLOR_B(h))) @@ -308,25 +331,26 @@ #if COLOR_BITS == 1 #define RGB2COLOR(r,g,b) (((r)|(g)|(b)) ? 1 : 0) + #define LUMA2COLOR(l) ((l) ? 1 : 0) #define HTML2COLOR(h) ((h) ? 1 : 0) - #define RED_OF(c) ((c) ? 255 : 0) - #define GREEN_OF(c) RED_OF(c) - #define BLUE_OF(c) RED_OF(c) - #define EXACT_RED_OF(val) RED_OF(c) - #define EXACT_GREEN_OF(val) RED_OF(c) - #define EXACT_BLUE_OF(val) RED_OF(c) + #define LUMA_OF(c) ((c) ? 255 : 0) + #define EXACT_LUMA_OF(c) LUMA_OF(c) #else // They eye is more sensitive to green #define RGB2COLOR(r,g,b) ((COLOR_TYPE)(((uint16_t)(r)+(g)+(g)+(b)) >> (10-COLOR_BITS))) + #define LUMA2COLOR(l) ((COLOR_TYPE)((l)>>(8-COLOR_BITS))) #define HTML2COLOR(h) ((COLOR_TYPE)(((((h)&0xFF0000)>>16)+(((h)&0x00FF00)>>7)+((h)&0x0000FF)) >> (10-COLOR_BITS))) - #define RED_OF(val) (((val) & ((1<>8) & 0x0F) + #define LLDCOLOR_BITS_G ((GDISP_LLD_PIXELFORMAT>>4) & 0x0F) + #define LLDCOLOR_BITS_B ((GDISP_LLD_PIXELFORMAT>>0) & 0x0F) + #define LLDCOLOR_BITS (LLDCOLOR_BITS_R + LLDCOLOR_BITS_G + LLDCOLOR_BITS_B) + + // From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking + #if LLDCOLOR_BITS <= 8 + #define LLDCOLOR_TYPE uint8_t + #define LLDCOLOR_TYPE_BITS 8 + #elif LLDCOLOR_BITS <= 16 + #define LLDCOLOR_TYPE uint16_t + #define LLDCOLOR_TYPE_BITS 16 + #elif LLDCOLOR_BITS <= 32 + #define LLDCOLOR_TYPE uint32_t + #define LLDCOLOR_TYPE_BITS 32 + #else + #error "GDISP: Cannot define low level driver color types with more than 32 bits" + #endif + #if LLDCOLOR_TYPE_BITS == LLDCOLOR_BITS + #define LLDCOLOR_NEEDS_MASK FALSE + #else + #define LLDCOLOR_NEEDS_MASK TRUE + #endif + #define LLDCOLOR_MASK() ((1 << LLDCOLOR_BITS)-1) + + // Calculate the component bit shifts + #if (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_RGB + #define LLDCOLOR_SHIFT_R (LLDCOLOR_BITS_B+LLDCOLOR_BITS_G) + #define LLDCOLOR_SHIFT_G LLDCOLOR_BITS_B + #define LLDCOLOR_SHIFT_B 0 + #else + #define LLDCOLOR_SHIFT_B (LLDCOLOR_BITS_R+LLDCOLOR_BITS_G) + #define LLDCOLOR_SHIFT_G LLDCOLOR_BITS_R + #define LLDCOLOR_SHIFT_R 0 + #endif + + // Calculate LLDRED_OF, LLDGREEN_OF, LLDBLUE_OF and LLDRGB2COLOR + #if LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R == 8 + #define LLDRED_OF(c) ((c) & (((1< 8 + #define LLDRED_OF(c) (((c) & (((1<> (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-8)) + #define LLDRGB2COLOR_R(r) (((LLDCOLOR_TYPE)((r) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1)))) << (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-8)) + #else // LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R < 8 + #define LLDRED_OF(c) (((c) & (((1<> (8-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R))) + #endif + #if LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G == 8 + #define LLDGREEN_OF(c) ((c) & (((1< 8 + #define LLDGREEN_OF(c) (((c) & (((1<> (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-8)) + #define LLDRGB2COLOR_G(g) (((LLDCOLOR_TYPE)((g) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1)))) << (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-8)) + #else // LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G < 8 + #define LLDGREEN_OF(c) (((c) & (((1<> (8-(LLDCOLOR_BITS_LLDG+COLOR_SHIFT_G))) + #endif + #if LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B == 8 + #define LLDBLUE_OF(c) ((c) & (((1< 8 + #define LLDBLUE_OF(c) (((c) & (((1<> (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8)) + #define LLDRGB2COLOR_B(b) (((LLDCOLOR_TYPE)((b) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1)))) << (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8)) + #else // LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B < 8 + #define LLDBLUE_OF(c) (((c) & (((1<> (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B))) + #endif + #define LLDLUMA_OF(c) ((LLDRED_OF(c)+((uint16_t)LLDGREEN_OF(c)<<1)+LLDBLUE_OF(c))>>2) + #define LLDEXACT_RED_OF(c) (((uint16_t)(((c)>>LLDCOLOR_SHIFT_R)&((1<>LLDCOLOR_SHIFT_G)&((1<>LLDCOLOR_SHIFT_B)&((1<>2) + #define LLDLUMA2COLOR(l) (LLDRGB2COLOR_R(l) | LLDRGB2COLOR_G(l) | LLDRGB2COLOR_B(l)) + #define LLDRGB2COLOR(r,g,b) (LLDRGB2COLOR_R(r) | LLDRGB2COLOR_G(g) | LLDRGB2COLOR_B(b)) + + // Calculate LLDHTML2COLOR + #if LLDCOLOR_BITS_R + LLDCOLOR_SHIFT_R == 24 + #define LLDHTML2COLOR_R(h) ((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16)) + #elif COLOR_BITS_R + COLOR_SHIFT_R > 24 + #define LLDHTML2COLOR_R(h) (((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16)) << (LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R-24)) + #else // COLOR_BITS_R + COLOR_SHIFT_R < 24 + #define LLDHTML2COLOR_R(h) (((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_R))-1))<<16)) >> (24-(LLDCOLOR_BITS_R+LLDCOLOR_SHIFT_R))) + #endif + #if LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G == 16 + #define LLDHTML2COLOR_G(h) ((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8)) + #elif LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G > 16 + #define LLDHTML2COLOR_G(h) (((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8)) << (LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G-16)) + #else // LLDCOLOR_BITS_G + LLDCOLOR_SHIFT_G < 16 + #define LLDHTML2COLOR_G(h) (((h) & ((0xFF & ~((1<<(8-LLDCOLOR_BITS_G))-1))<<8)) >> (16-(LLDCOLOR_BITS_G+LLDCOLOR_SHIFT_G))) + #endif + #if LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B == 8 + #define LLDHTML2COLOR_B(h) ((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))) + #elif LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B > 8 + #define LLDHTML2COLOR_B(h) (((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))) << (LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B-8)) + #else // LLDCOLOR_BITS_B + LLDCOLOR_SHIFT_B < 8 + #define LLDHTML2COLOR_B(h) (((h) & (0xFF & ~((1<<(8-LLDCOLOR_BITS_B))-1))) >> (8-(LLDCOLOR_BITS_B+LLDCOLOR_SHIFT_B))) + #endif + #define LLDHTML2COLOR(h) ((LLDCOLOR_TYPE)(LLDHTML2COLOR_R(h) | LLDHTML2COLOR_G(h) | LLDHTML2COLOR_B(h))) + +//------------------------- +// Gray-scale color system +//------------------------- +#elif (GDISP_LLD_PIXELFORMAT & GDISP_COLORSYSTEM_MASK) == GDISP_COLORSYSTEM_GRAYSCALE + #define LLDCOLOR_SYSTEM GDISP_COLORSYSTEM_GRAYSCALE + + // Calculate the number of bits and shifts + #define LLDCOLOR_BITS (GDISP_LLD_PIXELFORMAT & 0xFF) + #define LLDCOLOR_BITS_R LLDCOLOR_BITS + #define LLDCOLOR_BITS_G LLDCOLOR_BITS + #define LLDCOLOR_BITS_B LLDCOLOR_BITS + #define LLDCOLOR_SHIFT_R 0 + #define LLDCOLOR_SHIFT_G 0 + #define LLDCOLOR_SHIFT_B 0 + + // From the number of bits determine COLOR_TYPE, COLOR_TYPE_BITS and masking + #if LLDCOLOR_BITS <= 8 + #define LLDCOLOR_TYPE uint8_t + #define LLDCOLOR_TYPE_BITS 8 + #else + #error "GDISP: Cannot define gray-scale low level driver color types with more than 8 bits" + #endif + #if LLDCOLOR_TYPE_BITS == LLDCOLOR_BITS + #define LLDCOLOR_NEEDS_MASK FALSE + #else + #define LLDCOLOR_NEEDS_MASK TRUE + #endif + #define LLDCOLOR_MASK() ((1 << LLDCOLOR_BITS)-1) + + #if COLOR_BITS == 1 + #define LLDRGB2COLOR(r,g,b) (((r)|(g)|(b)) ? 1 : 0) + #define LLDLUMA2COLOR(l) ((l) ? 1 : 0) + #define LLDHTML2COLOR(h) ((h) ? 1 : 0) + #define LLDLUMA_OF(c) ((c) ? 255 : 0) + #define LLDEXACT_LUMA_OF(c) LLDLUMA_OF(c) + #else + // They eye is more sensitive to green + #define LLDRGB2COLOR(r,g,b) ((LLDCOLOR_TYPE)(((uint16_t)(r)+(g)+(g)+(b)) >> (10-LLDCOLOR_BITS))) + #define LLDLUMA2COLOR(l) ((LLDCOLOR_TYPE)((l)>>(8-LLDCOLOR_BITS))) + #define LLDHTML2COLOR(h) ((LLDCOLOR_TYPE)(((((h)&0xFF0000)>>16)+(((h)&0x00FF00)>>7)+((h)&0x0000FF)) >> (10-LLDCOLOR_BITS))) + #define LLDLUMA_OF(c) (((c) & ((1< LLDCOLOR_BITS + #define LARGER_COLOR_BITS COLOR_BITS + #define LARGER_COLOR_TYPE COLOR_TYPE +#else + #define LARGER_COLOR_BITS LLDCOLOR_BITS + #define LARGER_COLOR_TYPE LLDCOLOR_TYPE +#endif + +/** + * @brief Controls color conversion accuracy for a low level driver + * @details Should higher precision be used when converting colors. + * @note Color conversion is only necessary if GDISP_PIXELFORMAT != GDISP_LLD_PIXELFORMAT + * @note It only makes sense to turn this on if you have a high bit depth display but + * are running the application in low bit depths. + * @note To achieve higher color accuracy bit shifting is replaced with multiplies and divides. + */ +#ifndef GDISP_HARDWARE_USE_EXACT_COLOR + #if LLDCOLOR_BITS_R - COLOR_BITS_R >= LLDCOLOR_BITS_R/2 || LLDCOLOR_BITS_G - COLOR_BITS_G >= LLDCOLOR_BITS_G/2 || LLDCOLOR_BITS_B - COLOR_BITS_B >= LLDCOLOR_BITS_B/2 + #define GDISP_HARDWARE_USE_EXACT_COLOR TRUE + #else + #define GDISP_HARDWARE_USE_EXACT_COLOR FALSE + #endif +#endif + +/* Low level driver pixel format conversion functions */ +#if GDISP_PIXELFORMAT == GDISP_LLD_PIXELFORMAT || defined(__DOXYGEN__) + /** + * @brief Convert from a standard color format to the low level driver pixel format + * @note For use only by low level drivers + */ + #define COLOR2NATIVE(c) (c) + /** + * @brief Convert from a low level driver pixel format to the standard color format + * @note For use only by low level drivers + */ + #define NATIVE2COLOR(c) (c) + +#else + #if COLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE || LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_GRAYSCALE + #if GDISP_HARDWARE_USE_EXACT_COLOR + #define COLOR2NATIVE(c) LLDLUMA2COLOR(EXACT_LUMA_OF(c)) + #define NATIVE2COLOR(c) LUMA2COLOR(LLDEXACT_LUMA_OF(c)) + #else + #define COLOR2NATIVE(c) LLDLUMA2COLOR(LUMA_OF(c)) + #define NATIVE2COLOR(c) LUMA2COLOR(LLDLUMA_OF(c)) + #endif + #elif COLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR && LLDCOLOR_SYSTEM == GDISP_COLORSYSTEM_TRUECOLOR + #if GDISP_HARDWARE_USE_EXACT_COLOR + #define COLOR2NATIVE(c) LLDRGB2COLOR(EXACT_RED_OF(c), EXACT_GREEN_OF(c), EXACT_BLUE_OF(c)) + #define NATIVE2COLOR(c) RGB2COLOR(LLDEXACT_RED_OF(c), LLDEXACT_GREEN_OF(c), LLDEXACT_BLUE_OF(c)) + #else + #define COLOR2NATIVE(c) LLDRGB2COLOR(RED_OF(c), GREEN_OF(c), BLUE_OF(c)) + #define NATIVE2COLOR(c) RGB2COLOR(LLDRED_OF(c), LLDGREEN_OF(c), LLDBLUE_OF(c)) + #endif + + /* + #elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB888 && GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_BGR888 + #define COLOR2NATIVE(c) ((LLDCOLOR_TYPE)(((c)&0xFF0000)>>16)|((c)&0x00FF00)|(((c)&0x0000FF)<<16)) + #define NATIVE2COLOR(c) ((COLOR_TYPE)(((c)&0xFF0000)>>16)|((c)&0x00FF00)|(((c)&0x0000FF)<<16)) + #elif GDISP_PIXELFORMAT == GDISP_PIXELFORMAT_RGB565 && GDISP_LLD_PIXELFORMAT == GDISP_PIXELFORMAT_BGR888 + #define COLOR2NATIVE(c) ((LLDCOLOR_TYPE)( \ + ((LARGER_COLOR_TYPE)((c)&(((1<>(COLOR_BITS_R+COLOR_SHIFT_R-8))| \ + ((LARGER_COLOR_TYPE)((c)&(((1<>(16-(COLOR_BITS_G+COLOR_SHIFT_G)))| \ + ((LARGER_COLOR_TYPE)((c)&0xF80000)>>(24-(COLOR_BITS_B+COLOR_SHIFT_B))))) + */ + #else + #error "GDISP: This pixel format conversion is not supported yet" + #endif +#endif + #endif /* GFX_USE_GDISP */ #endif /* _GDISP_LLD_H */ From 5d2d6e79621a40d1a4ec4047e5c5ff8b9c7d1657 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 6 Nov 2013 17:21:58 +1000 Subject: [PATCH 152/160] Fix compiler warning --- boards/addons/gdisp/board_SSD1306_spi.h | 1 + 1 file changed, 1 insertion(+) diff --git a/boards/addons/gdisp/board_SSD1306_spi.h b/boards/addons/gdisp/board_SSD1306_spi.h index 5b481630..21bf095f 100644 --- a/boards/addons/gdisp/board_SSD1306_spi.h +++ b/boards/addons/gdisp/board_SSD1306_spi.h @@ -106,6 +106,7 @@ static inline void release_bus(GDisplay *g) { static inline void write_cmd(GDisplay *g, uint8_t cmd) { uint8_t command[2]; + (void) g; command[0] = 0x00; // Co = 0, D/C = 0 command[1] = cmd; From d00b5438310e23f0f2115ee660d066a1bfc1b23c Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 9 Nov 2013 14:23:13 +1000 Subject: [PATCH 153/160] Updated Makefile and new openocd config file for the Olimex SAM7EX256 board. Makefiles modifications required for updated gcc v4.7.2 --- .../Olimex-SAM7EX256-GE8/example/Makefile | 8 +- .../Olimex-SAM7EX256-GE8/example/openocd.cfg | 75 +++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 boards/base/Olimex-SAM7EX256-GE8/example/openocd.cfg diff --git a/boards/base/Olimex-SAM7EX256-GE8/example/Makefile b/boards/base/Olimex-SAM7EX256-GE8/example/Makefile index cff4e7ad..d6161d5e 100644 --- a/boards/base/Olimex-SAM7EX256-GE8/example/Makefile +++ b/boards/base/Olimex-SAM7EX256-GE8/example/Makefile @@ -5,8 +5,9 @@ # Compiler options here. ifeq ($(USE_OPT),) -# USE_OPT = -O2 -ggdb -gstabs+ -fomit-frame-pointer -mabi=apcs-gnu - USE_OPT = -O0 -ggdb -gstabs+ -fomit-frame-pointer -mabi=apcs-gnu + # If you are using gcc V4.5.1 or older then replace -g with -ggdb -gstabs+ + # For debugging you probably want -O0 rather than -O2 + USE_OPT = -O0 -g -fomit-frame-pointer -mabi=apcs-gnu endif # C specific options here (added to USE_OPT). @@ -126,7 +127,8 @@ CPPC = $(TRGT)g++ # Enable loading with g++ only if you need C++ runtime support. # NOTE: You can use C++ even without C++ support if you are careful. C++ # runtime support makes code size explode. -LD = $(TRGT)gcc -ggdb -gstabs+ +# If you are using gcc V4.5.1 or older then add -ggdb -gstabs+ to the LD line +LD = $(TRGT)gcc #LD = $(TRGT)g++ CP = $(TRGT)objcopy AS = $(TRGT)gcc -x assembler-with-cpp diff --git a/boards/base/Olimex-SAM7EX256-GE8/example/openocd.cfg b/boards/base/Olimex-SAM7EX256-GE8/example/openocd.cfg new file mode 100644 index 00000000..8c58e6f0 --- /dev/null +++ b/boards/base/Olimex-SAM7EX256-GE8/example/openocd.cfg @@ -0,0 +1,75 @@ +# This is a script file for OpenOCD 0.7.0 +# +# It is set up for the Olimex SAM7EX256 board using the Olimex Tiny-H JTAG adaptor. +# +# Assuming the current directory is your project directory containing this openocd.cfg file... +# +# To program your device: +# +# openocd -f openocd.cfg -c "Burn yourfile.bin" -c shutdown +# +# To debug your device: +# +# openocd +# (This will run openocd in gdb server debug mode. Leave it running in the background) +# +# gdb yourfile.elf +# (To start gdb. Then run the following commands in gdb...) +# +# target remote 127.0.0.1:3333 +# monitor Debug +# stepi +# (This last stepi resynchronizes gdb). +# +# If you want to reprogram from within gdb: +# +# monitor Burn yourfile.bin +# + +echo "" +echo "##### Loading debugger..." +source [find interface/olimex-arm-usb-tiny-h.cfg] +#source [find interface/ftdi/olimex-arm-usb-tiny-h.cfg] + +echo "" +echo "##### Loading CPU..." +source [find target/at91sam7x256.cfg] + +echo "" +echo "##### Configuring..." +jtag_rclk 3000 +arm7_9 dcc_downloads enable +arm7_9 fast_memory_access enable +# flash protect 0 0 1 off +#gdb_breakpoint_override hard +arm7_9 dbgrq enable + +proc Debug { } { + echo "" + echo "##### Debug Session Connected..." + soft_reset_halt + reg pc 0x00100000 + echo "Ready..." +} + +proc Burn {file} { + echo "" + echo "##### Burning $file to device..." + halt + flash write_image erase unlock $file 0x00100000 + reset + echo "Burning Complete!" +} + +echo "" +echo "##### Leaving Configuration Mode..." +init +soft_reset_halt +$_TARGETNAME invoke-event reset-init +flash probe 0 +flash banks + +echo "" +echo "##### Waiting for debug connections..." + + From 190113b91c7692d13fa72c8b515208e9a648c6d2 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 9 Nov 2013 19:08:18 +1000 Subject: [PATCH 154/160] OpenOCD config file for Mikromedia-STM-M4 board and updates to the makefile. --- .../example/Makefile | 3 +- .../example/openocd.cfg | 81 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 boards/base/Mikromedia-STM32-M4-ILI9341/example/openocd.cfg diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/example/Makefile b/boards/base/Mikromedia-STM32-M4-ILI9341/example/Makefile index 28292535..6fca731e 100644 --- a/boards/base/Mikromedia-STM32-M4-ILI9341/example/Makefile +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/example/Makefile @@ -5,7 +5,8 @@ # Compiler options here. ifeq ($(USE_OPT),) - USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16 + # Replace -O0 with -O2 for a production build. -O2 just messes with the debugger. + USE_OPT = -O0 -g -fomit-frame-pointer -falign-functions=16 endif # C specific options here (added to USE_OPT). diff --git a/boards/base/Mikromedia-STM32-M4-ILI9341/example/openocd.cfg b/boards/base/Mikromedia-STM32-M4-ILI9341/example/openocd.cfg new file mode 100644 index 00000000..f8b6a6f5 --- /dev/null +++ b/boards/base/Mikromedia-STM32-M4-ILI9341/example/openocd.cfg @@ -0,0 +1,81 @@ +# This is a script file for OpenOCD 0.7.0 +# +# It is set up for the Mikromedia-STM32M4 board using the ST-Link JTAG adaptor. +# +# Assuming the current directory is your project directory containing this openocd.cfg file... +# +# To program your device: +# +# openocd -f openocd.cfg -c "Burn yourfile.bin" -c shutdown +# +# To debug your device: +# +# openocd +# (This will run openocd in gdb server debug mode. Leave it running in the background) +# +# gdb yourfile.elf +# (To start gdb. Then run the following commands in gdb...) +# +# target remote 127.0.0.1:3333 +# monitor Debug +# stepi +# (This last stepi resynchronizes gdb). +# +# If you want to reprogram from within gdb: +# +# monitor Burn yourfile.bin +# + +echo "" +echo "##### Loading debugger..." +source [find interface/stlink-v2.cfg] + +echo "" +echo "##### Loading CPU..." +source [find target/stm32f4x_stlink.cfg] + +echo "" +echo "##### Configuring..." +reset_config srst_only srst_nogate +#cortex_m maskisr (auto|on|off) +#cortex_m vector_catch [all|none|list] +#cortex_m reset_config (srst|sysresetreq|vectreset) +#gdb_breakpoint_override hard + +proc Debug { } { + echo "" + echo "##### Debug Session Connected..." + reset init + echo "Ready..." +} + +proc Burn {file} { + echo "" + echo "##### Burning $file to device..." + halt + # Due to an issue with the combination of the ST-Link adapters and OpenOCD + # applying the stm32f2x unlock 0 command actaully applies read protection - VERY BAD! + # If this happens to you - use the ST-Link utility to set the option byte back to normal. + # If you are using a different debugger eg a FT2232 based adapter you can uncomment the line below. + #stm32f2x unlock 0 + flash protect 0 0 last off + reset init + flash write_image erase $file 0x08000000 + verify_image $file 0x0 + #flash protect 0 0 last on + reset + echo "Burning Complete!" +} + +echo "" +echo "##### Leaving Configuration Mode..." +init +reset init +flash probe 0 +flash banks +#flash info 0 + +echo "" +echo "##### Waiting for debug connections..." + + From 53408e2cb3d0705f261e9756bcf6f3f6c90c3fe9 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 9 Nov 2013 19:13:01 +1000 Subject: [PATCH 155/160] Fix incorrect naming of GMISC_INVSQRT_... macros. --- demos/modules/gdisp/streaming/gfxconf.h | 4 ++-- demos/modules/gdisp/streaming/main.c | 4 ++-- gfxconf.example.h | 4 ++-- include/gmisc/options.h | 12 ++++++------ src/gmisc/trig.c | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/demos/modules/gdisp/streaming/gfxconf.h b/demos/modules/gdisp/streaming/gfxconf.h index 4038a3fd..82843184 100644 --- a/demos/modules/gdisp/streaming/gfxconf.h +++ b/demos/modules/gdisp/streaming/gfxconf.h @@ -25,7 +25,7 @@ #define GFX_USE_GMISC TRUE #define GMISC_NEED_INVSQRT TRUE -//#define GDISP_INVSQRT_MIXED_ENDIAN TRUE -//#define GDISP_INVSQRT_REAL_SLOW TRUE +//#define GMISC_INVSQRT_MIXED_ENDIAN TRUE +//#define GMISC_INVSQRT_REAL_SLOW TRUE #endif /* _GFXCONF_H */ diff --git a/demos/modules/gdisp/streaming/main.c b/demos/modules/gdisp/streaming/main.c index 5b857eeb..4ad48b6c 100644 --- a/demos/modules/gdisp/streaming/main.c +++ b/demos/modules/gdisp/streaming/main.c @@ -42,11 +42,11 @@ * your processor. * * You can modify the implementation of invsqrt() by firstly defining - * #define GDISP_INVSQRT_MIXED_ENDIAN TRUE + * #define GMISC_INVSQRT_MIXED_ENDIAN TRUE * in your gfxconf.h file. * * If it still doesn't work then instead define - * #define GDISP_INVSQRT_REAL_SLOW TRUE + * #define GMISC_INVSQRT_REAL_SLOW TRUE * in your gfxconf.h file. This should always work although it will probably be slow. */ #define BALLCOLOR1 Red diff --git a/gfxconf.example.h b/gfxconf.example.h index 74d7f768..260d8bf6 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -181,8 +181,8 @@ #define GWIN_CONSOLE_USE_BASESTREAM FALSE #define GWIN_CONSOLE_USE_FLOAT FALSE #define GWIN_NEED_IMAGE_ANIMATION FALSE - #define GDISP_INVSQRT_MIXED_ENDIAN FALSE - #define GDISP_INVSQRT_REAL_SLOW FALSE + #define GMISC_INVSQRT_MIXED_ENDIAN FALSE + #define GMISC_INVSQRT_REAL_SLOW FALSE */ /* Optional Low Level Driver Definitions */ diff --git a/include/gmisc/options.h b/include/gmisc/options.h index 9c309487..06f689ec 100644 --- a/include/gmisc/options.h +++ b/include/gmisc/options.h @@ -53,15 +53,15 @@ * the same endianness. Unfortunately there are some strange * processors that don't eg. some very early ARM devices. * For those where the endianness doesn't match you can fix it by - * defining GDISP_INVSQRT_MIXED_ENDIAN. + * defining GMISC_INVSQRT_MIXED_ENDIAN. * @note This still assumes the processor is using an ieee floating point format. * * If you have a software floating point that uses a non-standard * floating point format (or very strange hardware) then define - * GDISP_INVSQRT_REAL_SLOW and it will do it the hard way. + * GMISC_INVSQRT_REAL_SLOW and it will do it the hard way. */ - #ifndef GDISP_INVSQRT_MIXED_ENDIAN - #define GDISP_INVSQRT_MIXED_ENDIAN FALSE + #ifndef GMISC_INVSQRT_MIXED_ENDIAN + #define GMISC_INVSQRT_MIXED_ENDIAN FALSE #endif /** * @brief Modifies the @p invsqrt() function to do things the long slow way. @@ -69,8 +69,8 @@ * processor floating point format. * @note This makes the @p invsqrt() function very slow. */ - #ifndef GDISP_INVSQRT_REAL_SLOW - #define GDISP_INVSQRT_REAL_SLOW FALSE + #ifndef GMISC_INVSQRT_REAL_SLOW + #define GMISC_INVSQRT_REAL_SLOW FALSE #endif /** @} */ diff --git a/src/gmisc/trig.c b/src/gmisc/trig.c index 2485da85..3c6dd461 100644 --- a/src/gmisc/trig.c +++ b/src/gmisc/trig.c @@ -144,7 +144,7 @@ #if GMISC_NEED_INVSQRT // Algorithm based on Quake code. - #if GDISP_INVSQRT_REAL_SLOW + #if GMISC_INVSQRT_REAL_SLOW #include float invsqrt(float n) { return 1.0/sqrt(n); @@ -157,7 +157,7 @@ x2 = n * 0.5F; // Convert into an int32 (no binary format conversion) - #if GDISP_INVSQRT_MIXED_ENDIAN + #if GMISC_INVSQRT_MIXED_ENDIAN ((char *)&i)[0] = ((char *)&n)[3]; ((char *)&i)[1] = ((char *)&n)[2]; ((char *)&i)[2] = ((char *)&n)[1]; @@ -170,7 +170,7 @@ i = 0x5F375A86 - (i >> 1); // The quake code used 0x5F3759DF but this is better. // Convert back to a float (no binary format conversion) - #if GDISP_INVSQRT_MIXED_ENDIAN + #if GMISC_INVSQRT_MIXED_ENDIAN ((char *)&n)[0] = ((char *)&i)[3]; ((char *)&n)[1] = ((char *)&i)[2]; ((char *)&n)[2] = ((char *)&i)[1]; From daa4e8bbd78ebe4a84234de266006d1a23697657 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 9 Nov 2013 19:17:22 +1000 Subject: [PATCH 156/160] Add support for a portrait and landscape orientation modes. --- include/gdisp/gdisp.h | 4 +++- src/gdisp/gdisp.c | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index 3d617e50..51415805 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -62,8 +62,10 @@ typedef enum fontmetric { fontHeight, fontDescendersHeight, fontLineSpacing, fon typedef const struct mf_font_s* font_t; /** * @brief Type for the screen orientation. + * @note GDISP_ROTATE_LANDSCAPE and GDISP_ROTATE_PORTRAIT are internally converted to the + * most appropriate other orientation. */ -typedef enum orientation { GDISP_ROTATE_0=0, GDISP_ROTATE_90=90, GDISP_ROTATE_180=180, GDISP_ROTATE_270=270 } orientation_t; +typedef enum orientation { GDISP_ROTATE_0=0, GDISP_ROTATE_90=90, GDISP_ROTATE_180=180, GDISP_ROTATE_270=270, GDISP_ROTATE_PORTRAIT=1000, GDISP_ROTATE_LANDSCAPE=1001 } orientation_t; /** * @brief Type for the available power modes for the screen. */ diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index b08fe627..7eade99c 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -2367,6 +2367,16 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c MUTEX_ENTER(g); g->p.x = what; g->p.ptr = value; + if (what == GDISP_CONTROL_ORIENTATION) { + switch ((orientation_t) value) { + case GDISP_ROTATE_LANDSCAPE: + g->p.ptr = g->g.Width >= g->g.Height ? GDISP_ROTATE_0 : GDISP_ROTATE_90; + break; + case GDISP_ROTATE_PORTRAIT: + g->p.ptr = g->g.Width >= g->g.Height ? GDISP_ROTATE_90 : GDISP_ROTATE_0; + break; + } + } gdisp_lld_control(g); #if GDISP_NEED_CLIP || GDISP_NEED_VALIDATION if (what == GDISP_CONTROL_ORIENTATION) { From 1f99d5c9fac79e3e9aa4ebff97b296b6dcb9c9a7 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 9 Nov 2013 19:18:59 +1000 Subject: [PATCH 157/160] Add support for a default application orientation. Also remove old unneeded GDISP_USE_CUSTOM_BOARD macro --- demos/3rdparty/tdisp_f4_discovery/gfxconf.h | 1 - demos/modules/gwin/widgets/gfxconf.h | 3 ++- gfxconf.example.h | 1 + include/gdisp/options.h | 14 +++++--------- src/gdisp/gdisp.c | 9 +++++++++ 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/demos/3rdparty/tdisp_f4_discovery/gfxconf.h b/demos/3rdparty/tdisp_f4_discovery/gfxconf.h index 42399ef5..c00e3941 100644 --- a/demos/3rdparty/tdisp_f4_discovery/gfxconf.h +++ b/demos/3rdparty/tdisp_f4_discovery/gfxconf.h @@ -136,7 +136,6 @@ /* Optional Low Level Driver Definitions */ /* - #define GDISP_USE_CUSTOM_BOARD FALSE #define GDISP_SCREEN_WIDTH 320 #define GDISP_SCREEN_HEIGHT 240 #define GDISP_USE_FSMC diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index 7899bfb8..111979e3 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -50,10 +50,11 @@ #define GDISP_NEED_TEXT TRUE #define GDISP_NEED_IMAGE TRUE #define GDISP_NEED_CONVEX_POLYGON TRUE +#define GDISP_NEED_CONTROL TRUE +#define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE /* The following are optional depending on your hardware */ //#define GDISP_NEED_SCROLL TRUE -//#define GDISP_NEED_CONTROL TRUE /* GDISP fonts to include */ #define GDISP_INCLUDE_FONT_UI2 TRUE diff --git a/gfxconf.example.h b/gfxconf.example.h index 260d8bf6..6a7b0c68 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -171,6 +171,7 @@ /* Optional Parameters for various subsystems */ /* + #define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE #define GDISP_LINEBUF_SIZE 128 #define GEVENT_MAXIMUM_SIZE 32 #define GEVENT_MAX_SOURCE_LISTENERS 32 diff --git a/include/gdisp/options.h b/include/gdisp/options.h index 7796144c..650e81c5 100644 --- a/include/gdisp/options.h +++ b/include/gdisp/options.h @@ -346,14 +346,10 @@ * @{ */ /** - * @brief Use a custom board definition even if a board definition exists. - * @details Defaults to FALSE - * @details If TRUE, add gdisp_lld_board.h to your project directory and customise it. - * @note Not all GDISP low level drivers currently use board definition files. + * @brief Define the default orientation for all displays in the system. + * @note GDISP_NEED_CONTROL must also be set (and the hardware must support it) */ - #ifndef GDISP_USE_CUSTOM_BOARD - #define GDISP_USE_CUSTOM_BOARD FALSE - #endif + // #define GDISP_DEFAULT_ORIENTATION GDISP_ROTATE_LANDSCAPE /** * @brief Set the screen height and width. * @note Ignored by some low level GDISP drivers, optional for others. @@ -368,8 +364,8 @@ * @details Only required by the SSD1963 driver. * @note This will be replaced eventually by board definition files */ - /* #define GDISP_USE_FSMC */ - /* #define GDISP_USE_GPIO */ + // #define GDISP_USE_FSMC + // #define GDISP_USE_GPIO /** @} */ #endif /* _GDISP_OPTIONS_H */ diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 7eade99c..6964bfff 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -587,6 +587,15 @@ void _gdispInit(void) { g->flags = 0; gdisp_lld_init(g); + #if defined(GDISP_DEFAULT_ORIENTATION) && GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL + g->p.x = GDISP_CONTROL_ORIENTATION; + g->p.ptr = GDISP_DEFAULT_ORIENTATION; + #if GDISP_HARDWARE_CONTROL == HARDWARE_AUTODETECT + if (g->vmt->control) + #endif + gdisp_lld_control(g); + #endif + // Set the initial clipping region #if GDISP_NEED_VALIDATION || GDISP_NEED_CLIP From 5cc1c5d67b339dc3cc623a6f3d10b9137d0929c8 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sun, 10 Nov 2013 21:33:28 +1000 Subject: [PATCH 158/160] Fix some compiler warnings. --- src/gdisp/gdisp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index 6964bfff..2af30f15 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -589,7 +589,7 @@ void _gdispInit(void) { #if defined(GDISP_DEFAULT_ORIENTATION) && GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL g->p.x = GDISP_CONTROL_ORIENTATION; - g->p.ptr = GDISP_DEFAULT_ORIENTATION; + g->p.ptr = (void *)GDISP_DEFAULT_ORIENTATION; #if GDISP_HARDWARE_CONTROL == HARDWARE_AUTODETECT if (g->vmt->control) #endif @@ -2379,10 +2379,12 @@ void gdispGBlitArea(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, c if (what == GDISP_CONTROL_ORIENTATION) { switch ((orientation_t) value) { case GDISP_ROTATE_LANDSCAPE: - g->p.ptr = g->g.Width >= g->g.Height ? GDISP_ROTATE_0 : GDISP_ROTATE_90; + g->p.ptr = g->g.Width >= g->g.Height ? (void *)GDISP_ROTATE_0 : (void *)GDISP_ROTATE_90; break; case GDISP_ROTATE_PORTRAIT: - g->p.ptr = g->g.Width >= g->g.Height ? GDISP_ROTATE_90 : GDISP_ROTATE_0; + g->p.ptr = g->g.Width >= g->g.Height ? (void *)GDISP_ROTATE_90 : (void *)GDISP_ROTATE_0; + break; + default: break; } } From 1646f9da1a5052bbc6d7fbb1db0c1b411bff46bd Mon Sep 17 00:00:00 2001 From: inmarket Date: Sun, 10 Nov 2013 21:34:49 +1000 Subject: [PATCH 159/160] Allow full range of values to be returned from the mouse driver when it is in RAW mode --- src/ginput/mouse.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ginput/mouse.c b/src/ginput/mouse.c index 99ef04f6..80a4ed20 100644 --- a/src/ginput/mouse.c +++ b/src/ginput/mouse.c @@ -65,6 +65,7 @@ static struct MouseConfig_t { #define FLG_CAL_OK 0x0020 #define FLG_CAL_SAVED 0x0040 #define FLG_CAL_FREE 0x0080 + #define FLG_CAL_RAW 0x0100 #if GINPUT_MOUSE_NEED_CALIBRATION GMouseCalibrationSaveRoutine fnsavecal; GMouseCalibrationLoadRoutine fnloadcal; @@ -200,14 +201,18 @@ static void get_calibrated_reading(MouseReading *pt) { pt->x = t; } break; + default: + break; } #endif #if GINPUT_MOUSE_NEED_CALIBRATION + if (!(MouseConfig.flags & FLG_CAL_RAW)) { if (pt->x < 0) pt->x = 0; else if (pt->x >= w) pt->x = w-1; if (pt->y < 0) pt->y = 0; else if (pt->y >= h) pt->y = h-1; + } #endif } @@ -350,7 +355,7 @@ GSourceHandle ginputGetMouse(uint16_t instance) { MouseConfig.caldata.ay = 0; MouseConfig.caldata.by = 1; MouseConfig.caldata.cy = 0; - MouseConfig.flags |= (FLG_CAL_OK|FLG_CAL_SAVED); + MouseConfig.flags |= (FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW); } else ginputCalibrateMouse(instance); #endif @@ -437,7 +442,7 @@ bool_t ginputCalibrateMouse(uint16_t instance) { MouseConfig.flags |= FLG_IN_CAL; gtimerStop(&MouseTimer); - MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED); + MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW); #if GDISP_NEED_CONTROL gdispGSetOrientation(MouseConfig.display, GDISP_ROTATE_0); From a8ce005e2621b0108863297948cea0fa52c8bf2a Mon Sep 17 00:00:00 2001 From: inmarket Date: Sun, 10 Nov 2013 21:35:23 +1000 Subject: [PATCH 160/160] Update changes list --- releases.txt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/releases.txt b/releases.txt index 32a838e9..d3a274b7 100644 --- a/releases.txt +++ b/releases.txt @@ -5,12 +5,29 @@ current release: 2.0 *** changes after 1.9 *** -FEATURE: GDISP Streaming +FEATURE: GDISP Streaming API and demos. +DEPRECATE: GDISP_NEED_ASYNC is now deprecated. +DEPRECATE: 3rd party boing demo is now deprecated (replaced by GDISP Streaming demo) +FIX: Remove GOS definitions from demo conf files so that it can be supplied by a makefile. +FEATURE: Repair GDISP low level driver interfaces so they can now be included in the doxygen documentation. FEATURE: New driver interface for GDISP FEATURE: Multiple display support FEATURE: Multiple controller support +FEATURE: Application pixel format no longer has to match the low level driver pixel format. +FEATURE: Many more pixel formats are now supported. +FEATURE: Many performance optimisations +FEATURE: Vertical scrolling is now supported if the low level driver supports read_pixel. FEATURE: Add gdispFlush() for those controllers that need it FEATURE: Add GDISP_NEED_AUTOFLUSH and GDISP_NEED_TIMERFLUSH to automatically flush when required. +FEATURE: Add support for generic portrait and landscape orientation modes +FEATURE: Add macro GDISP_DEFAULT_ORIENTATION so an application can specify a default orientation. +FEATURE: Driver files renamed to allow compiles when all object files go in the same directory +FEATURE: New directory structure for board files. Predefined boards have all the hardware definitions predefined. +FEATURE: Board defintions, example projects and makefiles for Win32. +FEATURE: Board defintions, example projects and makefiles for X. +FEATURE: Board defintions, example projects and makefiles for Olimex SAM7-EX256 board. +FEATURE: Board defintions, example projects and makefiles for Mikromedia STM32-M4 board. +FEATURE: New invsqrt() routine added to GMISC *** changes after 1.8 *** FEATURE: GWIN list boxes.