]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/utils/lcd_draw.c
Add SAMA5D2 Xplained IAR demo.
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D2x_Xplained_IAR / AtmelFiles / utils / lcd_draw.c
diff --git a/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/utils/lcd_draw.c b/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/utils/lcd_draw.c
new file mode 100644 (file)
index 0000000..1441a6a
--- /dev/null
@@ -0,0 +1,828 @@
+/* ----------------------------------------------------------------------------\r
+ *         SAM Software Package License\r
+ * ----------------------------------------------------------------------------\r
+ * Copyright (c) 2015, Atmel Corporation\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the disclaimer below.\r
+ *\r
+ * Atmel's name may not be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ *\r
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * ----------------------------------------------------------------------------\r
+ */\r
+\r
+/** \addtogroup lcdd_draw\r
+ *\r
+ * Implementation of draw function on LCD, Include draw text, image\r
+ * and basic shapes (line, rectangle, circle).\r
+ *\r
+ */\r
+\r
+/** \file */\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Headers\r
+ *----------------------------------------------------------------------------*/\r
+\r
+#include "board.h"\r
+\r
+#include "video/lcdd.h"\r
+\r
+#include "lcd_draw.h"\r
+#include "lcd_font.h"\r
+#include "font.h"\r
+\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <assert.h>\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Local variable\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/** Front color cache */\r
+static uint32_t front_color;\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Local functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * Hide canvas layer\r
+ */\r
+static void _hide_canvas(void)\r
+{\r
+       //lcdd_enable_layer(lcdd_get_canvas()->layer_id, false);\r
+}\r
+\r
+/**\r
+ * Update canvas\r
+ */\r
+static void _show_canvas(void)\r
+{\r
+       //lcdd_enable_layer(lcdd_get_canvas()->layer_id, true);\r
+}\r
+\r
+/**\r
+ * Set front color\r
+ * \param color Pixel color.\r
+ */\r
+static void _set_front_color(uint32_t color)\r
+{\r
+       front_color = color;\r
+}\r
+\r
+/**\r
+ * \brief Draw a pixel on LCD of front color.\r
+ *\r
+ * \param dwX       X-coordinate of pixel.\r
+ * \param dwY       Y-coordinate of pixel.\r
+ */\r
+static void _draw_pixel(uint32_t dwX, uint32_t dwY)\r
+{\r
+       struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+       uint8_t *buffer = pDisp->buffer;\r
+       uint16_t w = pDisp->width;\r
+       //uint16_t h = pDisp->height;\r
+       uint16_t cw = pDisp->bpp / 8;   /* color width */\r
+       uint32_t rw = w * cw;   /* row width in bytes */\r
+       //uint8_t  r, g, b;\r
+       uint8_t *pPix;\r
+\r
+       if (buffer == NULL)\r
+               return;\r
+\r
+       if (rw & 0x3)\r
+               rw = (rw | 0x3) + 1;    /* 4-byte aligned rows */\r
+       pPix = &buffer[dwY * rw + cw * dwX];\r
+\r
+       switch (pDisp->bpp) {\r
+       case 16:                /* TRGB 1555 */\r
+               pPix[0] = (front_color) & 0xFF;\r
+               pPix[1] = (front_color >> 8) & 0xFF;\r
+               break;\r
+       case 24:                /*  RGB  888 */\r
+               pPix[0] = (front_color) & 0xFF;\r
+               pPix[1] = (front_color >> 8) & 0xFF;\r
+               pPix[2] = (front_color >> 16) & 0xFF;\r
+               break;\r
+       case 32:                /* ARGB 8888 */\r
+               pPix[0] = (front_color) & 0xFF;\r
+               pPix[1] = (front_color >> 8) & 0xFF;\r
+               pPix[2] = (front_color >> 16) & 0xFF;\r
+               pPix[3] = (front_color >> 24) & 0xFF;\r
+               break;\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Fill rectangle with front color.\r
+ * \param dwX1  X-coordinate of top left.\r
+ * \param dwY1  Y-coordinate of top left.\r
+ * \param dwX2  X-coordinate of bottom right.\r
+ * \param dwY1  Y-coordinate of bottom right.\r
+ */\r
+static void _fill_rect(uint32_t dwX1, uint32_t dwY1, uint32_t dwX2, uint32_t dwY2)\r
+{\r
+       struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+       uint16_t w = pDisp->width;\r
+       uint16_t cw = pDisp->bpp / 8;   /* color width */\r
+       uint32_t rw = w * cw;   /* row width in bytes */\r
+       uint8_t *base = pDisp->buffer;\r
+       uint8_t *buffer = pDisp->buffer;\r
+       uint32_t fillStart, fillEnd;\r
+       uint32_t i;\r
+       if (buffer == NULL)\r
+               return;\r
+\r
+       /* 4-byte aligned rows */\r
+       if (rw & 0x3)\r
+               rw = (rw | 0x3) + 1;\r
+       /* Buffer address for the starting row */\r
+       base = &buffer[dwY1 * rw];\r
+\r
+       fillStart = dwX1 * cw;\r
+       fillEnd = dwX2 * cw;\r
+\r
+#if 1                          /* Memcopy pixel */\r
+       buffer = base;\r
+       for (; dwY1 <= dwY2; dwY1++) {\r
+               for (i = fillStart; i <= fillEnd; i += cw) {\r
+                       memcpy(&buffer[i], &front_color, cw);\r
+               }\r
+               buffer = &buffer[rw];\r
+       }\r
+#endif\r
+\r
+#if 0                          /* Pixel by pixel */\r
+       for (; dwY1 <= dwY2; dwY1++) {\r
+               for (i = dwX1; i <= dwX2; i++) {\r
+                       _draw_pixel(i, dwY1);\r
+               }\r
+       }\r
+#endif\r
+\r
+#if 0                          /* Optimized */\r
+       /* First row */\r
+       for (i = fillStart; i <= fillEnd; i += cw) {\r
+               memcpy(&base[i], &front_color, cw);\r
+       }\r
+       /* Next rows, copy first */\r
+       buffer = &base[rw + fillStart];\r
+       for (i = dwY1 + 1; i <= dwY2; i++) {\r
+               memcpy(buffer, &base[fillStart], fillEnd - fillStart + cw);\r
+               buffer = &buffer[rw];\r
+       }\r
+#endif\r
+}\r
+\r
+/**\r
+ * \brief Draw a line on LCD, which is not horizontal or vertical.\r
+ *\r
+ * \param dwX1       X-coordinate of line start.\r
+ * \param dwY1       Y-coordinate of line start.\r
+ * \param dwX2       X-coordinate of line end.\r
+ * \param dwY2       Y-coordinate of line end.\r
+ */\r
+\r
+/*\r
+static uint32_t _draw_line_bresenham (uint32_t dwX1, uint32_t dwY1, uint32_t dwX2, uint32_t dwY2)\r
+{\r
+       int dx, dy;\r
+       int i;\r
+       int xinc, yinc, cumul;\r
+       int x, y;\r
+\r
+       x = dwX1;\r
+       y = dwY1;\r
+       dx = dwX2 - dwX1;\r
+       dy = dwY2 - dwY1;\r
+\r
+       xinc = (dx > 0) ? 1 : -1;\r
+       yinc = (dy > 0) ? 1 : -1;\r
+       dx = (dx > 0) ? dx : -dx;\r
+       dy = (dy > 0) ? dy : -dy;\r
+\r
+       _draw_pixel(x, y);\r
+\r
+       if (dx > dy) {\r
+               cumul = dx / 2;\r
+               for (i = 1; i <= dx; i++) {\r
+                       x += xinc;\r
+                       cumul += dy;\r
+\r
+                       if (cumul >= dx) {\r
+                               cumul -= dx;\r
+                               y += yinc;\r
+                       }\r
+                       _draw_pixel(x, y);\r
+               }\r
+       } else {\r
+               cumul = dy / 2;\r
+               for (i = 1; i <= dy; i++) {\r
+                       y += yinc;\r
+                       cumul += dx;\r
+\r
+                       if (cumul >= dy) {\r
+                               cumul -= dy;\r
+                               x += xinc;\r
+                       }\r
+\r
+                       _draw_pixel(x, y);\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+*/\r
+\r
+static uint32_t _draw_line_bresenham (uint32_t dwX1, uint32_t dwY1, uint32_t dwX2, uint32_t dwY2)\r
+{\r
+    int dx = abs(dwX2 - dwX1);\r
+    int dy = abs(dwY2 - dwY1);\r
+    int sx = (dwX1 < dwX2) ? 1 : -1;\r
+    int sy = (dwY1 < dwY2) ? 1 : -1;\r
+    int err = dx - dy;\r
+    int e2 ;\r
+\r
+    while (1) {\r
+      _draw_pixel(dwX1, dwY1);\r
+      if ((dwX1 == dwX2) && (dwY1 == dwY2))\r
+        break;\r
+      e2 = 2 * err;\r
+         if (e2 > -dy) {\r
+                 err -= dy; dwX1 += sx;\r
+         }\r
+      if (e2 < dx) {\r
+                 err += dx; dwY1 += sy;\r
+         }\r
+    }\r
+       return 0;\r
+}\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Exported functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * \brief Fills the given LCD buffer with a particular color.\r
+ *\r
+ * \param color  Fill color.\r
+ */\r
+void lcdd_fill(uint32_t color)\r
+{\r
+       struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+       _set_front_color(color);\r
+       _hide_canvas();\r
+       _fill_rect(0, 0, pDisp->width, pDisp->height);\r
+       _show_canvas();\r
+}\r
+\r
+void lcdd_fill_white(void)\r
+{\r
+       struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+       _hide_canvas();\r
+       _set_front_color(0x0000FF);\r
+       _fill_rect(0, 0, pDisp->width / 3, pDisp->height);\r
+       _set_front_color(0xFFFFFF);\r
+       _fill_rect(pDisp->width/3, 0, pDisp->width/3+pDisp->width/3, pDisp->height);\r
+       _set_front_color(0xFF0000);\r
+       _fill_rect(pDisp->width/3+pDisp->width/3, 0, pDisp->width-1, pDisp->height);\r
+       _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draw a pixel on LCD of given color.\r
+ *\r
+ * \param x  X-coordinate of pixel.\r
+ * \param y  Y-coordinate of pixel.\r
+ * \param color  Pixel color.\r
+ */\r
+void lcdd_draw_pixel(uint32_t x, uint32_t y, uint32_t color)\r
+{\r
+       _set_front_color(color);\r
+       _hide_canvas();\r
+       _draw_pixel(x, y);\r
+       _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Read a pixel from LCD.\r
+ *\r
+ * \param x  X-coordinate of pixel.\r
+ * \param y  Y-coordinate of pixel.\r
+ *\r
+ * \return color  Readed pixel color.\r
+ */\r
+extern uint32_t lcdd_read_pixel(uint32_t x, uint32_t y)\r
+{\r
+       struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+       uint8_t *buffer = pDisp->buffer;\r
+       uint16_t w = pDisp->width;\r
+       //uint16_t h = pDisp->height;\r
+       uint16_t cw = pDisp->bpp / 8;   /* color width */\r
+       uint32_t rw = w * cw;   /* row width in bytes */\r
+       uint8_t *pPix;\r
+       uint32_t color = 0;\r
+\r
+       if (buffer == NULL)\r
+               return 0;\r
+\r
+       if (rw & 0x3)\r
+               rw = (rw | 0x3) + 1;    /* 4-byte aligned rows */\r
+       pPix = &buffer[x * rw + cw * y];\r
+\r
+       switch (pDisp->bpp) {\r
+       case 16:                /* TRGB 1555 */\r
+               color = pPix[0] | (pPix[1] << 8);\r
+               break;\r
+       case 24:                /*  RGB  888 */\r
+               color = pPix[0] | (pPix[1] << 8) | (pPix[2] << 16);\r
+               break;\r
+       case 32:                /* ARGB 8888 */\r
+               color =\r
+                       pPix[0] | (pPix[1] << 8) | (pPix[2] << 16) | (pPix[3] <<\r
+                                                                     24);\r
+               break;\r
+       }\r
+       return color;\r
+}\r
+\r
+/**\r
+ * \brief Draw a line on LCD, horizontal and vertical line are supported.\r
+ *\r
+ * \param x1        X-coordinate of line start.\r
+ * \param y1        Y-coordinate of line start.\r
+ * \param x2        X-coordinate of line end.\r
+ * \param y2        Y-coordinate of line end.\r
+ * \param color     Pixel color.\r
+ */\r
+void lcdd_draw_line(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2,\r
+                   uint32_t color)\r
+{\r
+       _set_front_color(color);\r
+\r
+       if ((x1 == x2) && (y1 > y2)) {\r
+               SWAP(y1, y2);\r
+       }\r
+       if ((x1 > x2) & (y1 == y2)) {\r
+               SWAP(x1, x2);\r
+       }\r
+\r
+       if ((x1 == x2) || (y1 == y2)) {\r
+               lcdd_draw_filled_rectangle(x1, y1, x2, y2, color);\r
+       } else {\r
+               _hide_canvas();\r
+               _draw_line_bresenham(x1, y1, x2, y2);\r
+               _show_canvas();\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Draws a rectangle on LCD, at the given coordinates.\r
+ *\r
+ * \param x      X-coordinate of upper-left rectangle corner.\r
+ * \param y      Y-coordinate of upper-left rectangle corner.\r
+ * \param width  Rectangle width in pixels.\r
+ * \param height  Rectangle height in pixels.\r
+ * \param color  Rectangle color.\r
+ */\r
+void lcdd_draw_rectangle(uint32_t x, uint32_t y, uint32_t width, uint32_t height,\r
+                        uint32_t color)\r
+{\r
+       uint32_t x1 = x + width - 1;\r
+       uint32_t y1 = y + height - 1;\r
+\r
+       _set_front_color(color);\r
+       _hide_canvas();\r
+       _fill_rect(x, y, x1, y);\r
+       _fill_rect(x1, y, x1, y1);\r
+       _fill_rect(x, y, x, y1);\r
+       _fill_rect(x, y1, x1, y1);\r
+       _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draws a rectangle with fill inside on LCD, at the given coordinates.\r
+ *\r
+ * \param dwX1   X-coordinate of upper-left rectangle corner.\r
+ * \param dwY1   Y-coordinate of upper-left rectangle corner.\r
+ * \param dwX2   X-coordinate of down-right rectangle corner.\r
+ * \param dwY2   Y-coordinate of down-right rectangle corner.\r
+ * \param color Rectangle color.\r
+ */\r
+void lcdd_draw_filled_rectangle(uint32_t dwX1, uint32_t dwY1,\r
+                               uint32_t dwX2, uint32_t dwY2, uint32_t color)\r
+{\r
+       _set_front_color(color);\r
+       _hide_canvas();\r
+       _fill_rect(dwX1, dwY1, dwX2, dwY2);\r
+       _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draws a circle on LCD, at the given coordinates.\r
+ *\r
+ * \param dwX     X-coordinate of circle center.\r
+ * \param dwY     Y-coordinate of circle center.\r
+ * \param dwR     circle radius.\r
+ * \param color circle color.\r
+ */\r
+void lcdd_draw_circle(uint32_t dwX, uint32_t dwY, uint32_t dwR, uint32_t color)\r
+{\r
+       int32_t d;              /* Decision Variable */\r
+       uint32_t curX;          /* Current X Value */\r
+       uint32_t curY;          /* Current Y Value */\r
+\r
+       if (dwR == 0)\r
+               return;\r
+       _set_front_color(color);\r
+\r
+       d = 3 - (dwR << 1);\r
+       curX = 0;\r
+       curY = dwR;\r
+\r
+       _hide_canvas();\r
+       while (curX <= curY) {\r
+               _draw_pixel(dwX + curX, dwY + curY);\r
+               _draw_pixel(dwX + curX, dwY - curY);\r
+               _draw_pixel(dwX - curX, dwY + curY);\r
+               _draw_pixel(dwX - curX, dwY - curY);\r
+               _draw_pixel(dwX + curY, dwY + curX);\r
+               _draw_pixel(dwX + curY, dwY - curX);\r
+               _draw_pixel(dwX - curY, dwY + curX);\r
+               _draw_pixel(dwX - curY, dwY - curX);\r
+\r
+               if (d < 0) {\r
+                       d += (curX << 2) + 6;\r
+               } else {\r
+                       d += ((curX - curY) << 2) + 10;\r
+                       curY--;\r
+               }\r
+               curX++;\r
+       }\r
+       _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draws a filled circle on LCD, at the given coordinates.\r
+ *\r
+ * \param dwX     X-coordinate of circle center.\r
+ * \param dwY     Y-coordinate of circle center.\r
+ * \param dwR     circle radius.\r
+ * \param color circle color.\r
+ */\r
+void lcdd_draw_filled_circle(uint32_t dwX, uint32_t dwY, uint32_t dwR,\r
+                            uint32_t color)\r
+{\r
+       signed int d;           // Decision Variable\r
+       uint32_t dwCurX;        // Current X Value\r
+       uint32_t dwCurY;        // Current Y Value\r
+       uint32_t dwXmin, dwYmin;\r
+\r
+       if (dwR == 0)\r
+               return;\r
+       _set_front_color(color);\r
+\r
+       d = 3 - (dwR << 1);\r
+       dwCurX = 0;\r
+       dwCurY = dwR;\r
+\r
+       _hide_canvas();\r
+       while (dwCurX <= dwCurY) {\r
+               dwXmin = (dwCurX > dwX) ? 0 : dwX - dwCurX;\r
+               dwYmin = (dwCurY > dwY) ? 0 : dwY - dwCurY;\r
+               _fill_rect(dwXmin, dwYmin, dwX + dwCurX, dwYmin);\r
+               _fill_rect(dwXmin, dwY + dwCurY, dwX + dwCurX, dwY + dwCurY);\r
+               dwXmin = (dwCurY > dwX) ? 0 : dwX - dwCurY;\r
+               dwYmin = (dwCurX > dwY) ? 0 : dwY - dwCurX;\r
+               _fill_rect(dwXmin, dwYmin, dwX + dwCurY, dwYmin);\r
+               _fill_rect(dwXmin, dwY + dwCurX, dwX + dwCurY, dwY + dwCurX);\r
+\r
+               if (d < 0) {\r
+                       d += (dwCurX << 2) + 6;\r
+               } else {\r
+                       d += ((dwCurX - dwCurY) << 2) + 10;\r
+                       dwCurY--;\r
+               }\r
+\r
+               dwCurX++;\r
+       }\r
+       _show_canvas();\r
+}\r
+\r
+/**\r
+ * \brief Draws a string inside a LCD buffer, at the given coordinates. Line breaks\r
+ * will be honored.\r
+ *\r
+ * \param x        X-coordinate of string top-left corner.\r
+ * \param y        Y-coordinate of string top-left corner.\r
+ * \param p_string  String to display.\r
+ * \param color    String color.\r
+ */\r
+void lcdd_draw_string(uint32_t x, uint32_t y, const char *p_string, uint32_t color)\r
+{\r
+       uint32_t xorg = x;\r
+       uint8_t font_sel = lcdd_get_selected_font();\r
+       uint8_t width = font_param[font_sel].width ;\r
+       uint8_t height = font_param[font_sel].height;\r
+       uint8_t char_space = font_param[font_sel].char_space;\r
+\r
+       /* Font 10*8 reverse height and width */\r
+       if (font_sel == FONT10x8) {\r
+               width = font_param[font_sel].height ;\r
+               height = font_param[font_sel].width;\r
+       }\r
+\r
+       while (*p_string) {\r
+               if (*p_string == '\n') {\r
+                       y += height + char_space;\r
+                       x = xorg;\r
+               } else {\r
+                       lcdd_draw_char(x, y, *p_string, color);\r
+                       x += width + char_space;\r
+               }\r
+               p_string++;\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Draws a string inside a LCD buffer, at the given coordinates\r
+ * with given background color. Line breaks will be honored.\r
+ *\r
+ * \param x         X-coordinate of string top-left corner.\r
+ * \param y         Y-coordinate of string top-left corner.\r
+ * \param p_string  String to display.\r
+ * \param fontColor String color.\r
+ * \param bgColor   Background color.\r
+ */\r
+void lcdd_draw_string_with_bgcolor(uint32_t x, uint32_t y,\r
+                                                                  const char *p_string,\r
+                                                                  uint32_t fontColor,\r
+                                                                  uint32_t bgColor)\r
+{\r
+       uint32_t xorg = x;\r
+       uint8_t font_sel = lcdd_get_selected_font();\r
+       uint8_t width = font_param[font_sel].width ;\r
+       uint8_t height = font_param[font_sel].height;\r
+       uint8_t char_space = font_param[font_sel].char_space;\r
+\r
+       /* Font 10*8 reverse height and width */\r
+       if (font_sel == FONT10x8) {\r
+               width = font_param[font_sel].height ;\r
+               height = font_param[font_sel].width;\r
+       }\r
+\r
+       while (*p_string) {\r
+               if (*p_string == '\n') {\r
+                       y += height + char_space;;\r
+                       x = xorg;\r
+               } else {\r
+                       lcdd_draw_char_with_bgcolor(x, y, *p_string, fontColor, bgColor);\r
+                       x += width + char_space;;\r
+               }\r
+               p_string++;\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Returns the width & height in pixels that a string will occupy on the screen\r
+ * if drawn using lcdd_draw_string.\r
+ *\r
+ * \param p_string  String.\r
+ * \param p_width   Pointer for storing the string width (optional).\r
+ * \param p_height  Pointer for storing the string height (optional).\r
+ *\r
+ * \return String width in pixels.\r
+ */\r
+void lcdd_get_string_size(const char *p_string, uint32_t * p_width, uint32_t * p_height)\r
+{\r
+       uint8_t font_sel = lcdd_get_selected_font();\r
+       uint8_t width = font_param[font_sel].width;\r
+       uint8_t height = font_param[font_sel].height;\r
+       uint8_t char_space = font_param[font_sel].char_space;\r
+       uint32_t str_width = 0;\r
+\r
+       /* Font 10*8 reverse height and width */\r
+       if (font_sel == FONT10x8) {\r
+               width = font_param[font_sel].height ;\r
+               height = font_param[font_sel].width;\r
+       }\r
+\r
+       while (*p_string) {\r
+               if (*p_string == '\n')\r
+                       height += height + char_space;\r
+               else\r
+                       str_width += width + char_space;\r
+               p_string++;\r
+       }\r
+       if (width > 0)\r
+               str_width -= char_space;\r
+\r
+       if (p_width != NULL)\r
+               *p_width = str_width;\r
+       if (p_height != NULL)\r
+               *p_height = height;\r
+}\r
+\r
+/**\r
+ * \brief Draw a raw image at given position on LCD.\r
+ *\r
+ * \param dwX       X-coordinate of image start.\r
+ * \param dwY       Y-coordinate of image start.\r
+ * \param pImage    Image buffer.\r
+ * \param width     Image width.\r
+ * \param height    Image height.\r
+ */\r
+void lcdd_draw_image(uint32_t dwX, uint32_t dwY, const uint8_t * pImage,\r
+                    uint32_t width, uint32_t height)\r
+{\r
+       struct _lcdd_layer *pDisp = lcdd_get_canvas();\r
+       uint16_t cw = pDisp->bpp / 8;   /* color width */\r
+       uint32_t rw = pDisp->width * cw;        /* Row width in bytes */\r
+       uint32_t rws = width * cw;      /* Source Row Width */\r
+       uint32_t rl = (rw & 0x3) ? ((rw | 0x3) + 1) : rw;       /* Aligned length */\r
+       uint32_t rls = (rws & 0x3) ? ((rws | 0x3) + 1) : rws;   /* Aligned length */\r
+       uint8_t *pSrc, *pDst;\r
+       uint32_t i;\r
+\r
+       pSrc = (uint8_t *) pImage;\r
+       pDst = pDisp->buffer;\r
+       pDst = &pDst[dwX * cw + dwY * rl];\r
+\r
+       for (i = 0; i < height; i++) {\r
+               memcpy(pDst, pSrc, rws);\r
+               pSrc = &pSrc[rls];\r
+               pDst = &pDst[rl];\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Clear a window with an color.\r
+ *\r
+ * \param dwX         X-coordinate of the window.\r
+ * \param dwY         Y-coordinate of the window.\r
+ * \param width     window width.\r
+ * \param height    window height.\r
+ * \param color     background color\r
+ */\r
+void lcdd_clear_window(uint32_t dwX, uint32_t dwY, uint32_t width,\r
+                      uint32_t height, uint32_t color)\r
+{\r
+       _set_front_color(color);\r
+       _hide_canvas();\r
+       _fill_rect(0, 0, dwX + width - 1, dwY + height - 1);\r
+       _show_canvas();\r
+}\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Local functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * Draw fast vertical line\r
+ */\r
+void lcdd_draw_fast_vline (uint32_t x, uint32_t y, uint32_t h, uint32_t color)\r
+{\r
+       lcdd_draw_line(x, y, x, y+h-1, color);\r
+}\r
+/**\r
+ * Draw fast horizontal line\r
+ */\r
+void lcdd_draw_fast_hline (uint32_t x, uint32_t y, uint32_t w, uint32_t color)\r
+{\r
+       lcdd_draw_line(x, y, x+w-1, y, color);\r
+}\r
+/**\r
+ * Fill rectangle with color\r
+ */\r
+static void _lcdd_fill_rectangle (uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color)\r
+{\r
+       uint32_t i;\r
+       for (i=x; i<x+w; i++) lcdd_draw_fast_vline(i, y, h, color);\r
+}\r
+/**\r
+ * Draw a circle\r
+ */\r
+static void _lcdd_draw_circle (uint32_t x0, uint32_t y0, uint32_t r, uint8_t corner, uint32_t color)\r
+{\r
+       int32_t f = 1 - r;\r
+       int32_t ddF_x = 1;\r
+       int32_t ddF_y = -2 * (int32_t)r;\r
+       int32_t x = 0;\r
+       int32_t y = r;\r
+\r
+       while (x<y) {\r
+               if (f >= 0)\r
+               {\r
+                       y--;\r
+                       ddF_y += 2;\r
+                       f     += ddF_y;\r
+               }\r
+               x++;\r
+               ddF_x += 2;\r
+               f     += ddF_x;\r
+               if (corner & 0x4) {\r
+                       _draw_pixel(x0 + x, y0 + y);\r
+                       _draw_pixel(x0 + y, y0 + x);\r
+               }\r
+               if (corner & 0x2) {\r
+                       _draw_pixel(x0 + x, y0 - y);\r
+                       _draw_pixel(x0 + y, y0 - x);\r
+               }\r
+               if (corner & 0x8) {\r
+                       _draw_pixel(x0 - y, y0 + x);\r
+                       _draw_pixel(x0 - x, y0 + y);\r
+               }\r
+               if (corner & 0x1) {\r
+                       _draw_pixel(x0 - y, y0 - x);\r
+                       _draw_pixel(x0 - x, y0 - y);\r
+               }\r
+       }\r
+}\r
+/**\r
+ * Fill a circle\r
+ */\r
+static void _lcdd_fill_circle (uint32_t x0, uint32_t y0, uint32_t r, uint8_t corner, uint32_t delta, uint32_t color)\r
+{\r
+       int32_t f = 1 - r;\r
+       int32_t ddF_x = 1;\r
+       int32_t ddF_y = -2 * (int32_t)r;\r
+       int32_t x = 0;\r
+       int32_t y = r;\r
+\r
+       while (x<y) {\r
+               if (f >= 0) {\r
+                       y--;\r
+                       ddF_y += 2;\r
+                       f += ddF_y;\r
+               }\r
+               x++;\r
+               ddF_x += 2;\r
+               f += ddF_x;\r
+\r
+               if (corner & 0x1) {\r
+                       lcdd_draw_fast_vline(x0+x, y0-y, 2*y+1+delta, color);\r
+                       lcdd_draw_fast_vline(x0+y, y0-x, 2*x+1+delta, color);\r
+               }\r
+               if (corner & 0x2) {\r
+                       lcdd_draw_fast_vline(x0-x, y0-y, 2*y+1+delta, color);\r
+                       lcdd_draw_fast_vline(x0-y, y0-x, 2*x+1+delta, color);\r
+               }\r
+       }\r
+}\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Global functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/**\r
+ * Draw a rectangle with rounded corners\r
+ */\r
+void lcdd_draw_rounded_rect (uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t r, uint32_t color)\r
+{\r
+       _set_front_color(color);\r
+       _hide_canvas();\r
+       // smarter version\r
+       lcdd_draw_fast_hline(x+r, y, w-2*r, color); // Top\r
+       lcdd_draw_fast_hline(x+r, y+h-1, w-2*r, color); // Bottom\r
+       lcdd_draw_fast_vline(x, y+r, h-2*r, color); // Left\r
+       lcdd_draw_fast_vline(x+w-1, y+r, h-2*r, color); // Right\r
+       // draw four corners\r
+       _lcdd_draw_circle(x+r, y+r, r, 1, color);\r
+       _lcdd_draw_circle(x+w-r-1, y+r, r, 2, color);\r
+       _lcdd_draw_circle(x+w-r-1, y+h-r-1, r, 4, color);\r
+       _lcdd_draw_circle(x+r, y+h-r-1, r, 8, color);\r
+       _show_canvas();\r
+}\r
+/**\r
+ * Fill a rectangle with rounded corners\r
+ */\r
+void lcdd_fill_rounded_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t r, uint32_t color)\r
+{\r
+       _set_front_color(color);\r
+       _hide_canvas();\r
+       if (w>(2*r)) {\r
+               _lcdd_fill_rectangle(x+r, y, w-(2*r), h, color);\r
+               // draw four corners\r
+               _lcdd_fill_circle(x+w-r-1, y+r, r, 1, h-2*r-1, color);\r
+               _lcdd_fill_circle(x+r, y+r, r, 2, h-2*r-1, color);\r
+       }\r
+       _show_canvas();\r
+}\r