From 34075031de2dd0695e0e239c1dad0429fcc3e2f1 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Mon, 6 Aug 2012 11:30:02 +1000 Subject: Backport GDISP low level drivers to GLCD see GLCD/readme.txt --- glcd/glcd.c | 1045 ++++++++++++++++++++++++----------------------------------- 1 file changed, 431 insertions(+), 614 deletions(-) (limited to 'glcd/glcd.c') diff --git a/glcd/glcd.c b/glcd/glcd.c index 5ae7c097..9d4db9cf 100644 --- a/glcd/glcd.c +++ b/glcd/glcd.c @@ -1,614 +1,431 @@ -/* - ChibiOS/RT - Copyright (C) 2012 - Joel Bodenmann aka Tectu - - This file is part of ChibiOS-LCD-Driver. - - ChibiOS-LCD-Driver 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-LCD-Driver 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 . -*/ - -#include "glcd.h" -#include "glcdWorker.h" - -#define EMSG(a) const struct a *emsg = (const struct a*)msg - -uint16_t lcd_width, lcd_height; -static Thread *workerThread = NULL; - -/* internal functions; don't include in header */ -inline glcd_result_t _lcdFillArea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color); -inline glcd_result_t _lcdWriteArea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t *buffer, size_t n); -glcd_result_t _lcdDrawChar(struct glcd_msg_draw_char *m); - -static WORKING_AREA(waGLCDWorkerThread, GLCD_WORKER_SIZE); -static msg_t ThreadGLCDWorker(void *arg) { - (void)arg; - Thread *p; - - chRegSetThreadName("GLCDWorker"); - - while(TRUE) { - /* Wait for msg with work to do. */ - p = chMsgWait(); - struct glcd_msg_base *msg = (struct glcd_msg_base*)chMsgGet(p); - glcd_result_t result = GLCD_PROGRESS; - - /* do work here */ - switch(msg->action) { - case GLCD_SET_POWERMODE: { - EMSG(glcd_msg_powermode); - lld_lcdSetPowerMode(emsg->powermode); - result = GLCD_DONE; - break; - } - - case GLCD_SET_ORIENTATION: { - EMSG(glcd_msg_orientation); - lld_lcdSetOrientation(emsg->newOrientation); - result = GLCD_DONE; - break; - } - - case GLCD_SET_WINDOW: { - EMSG(glcd_msg_set_window); - lld_lcdSetWindow(emsg->x0, emsg->y0, emsg->x1, emsg->y1); - result = GLCD_DONE; - break; - } - - case GLCD_FILL_AREA: { - EMSG(glcd_msg_fill_area); - result = _lcdFillArea(emsg->x0, emsg->y0, emsg->x1, emsg->y1, emsg->color); - break; - } - - case GLCD_WRITE_AREA: { - EMSG(glcd_msg_write_area); - result = _lcdWriteArea(emsg->x0, emsg->y0, emsg->x1, emsg->y1, emsg->buffer, emsg->size); - break; - } - - case GLCD_CLEAR: { - EMSG(glcd_msg_clear); - lld_lcdClear(emsg->color); - result = GLCD_DONE; - break; - } - - case GLCD_GET_PIXEL_COLOR: { - EMSG(glcd_msg_get_pixel_color); - ((struct glcd_msg_get_pixel_color *)emsg)->color = - lld_lcdGetPixelColor(emsg->x, emsg->y); - result = GLCD_DONE; - break; - } - - case GLCD_DRAW_PIXEL: { - EMSG(glcd_msg_draw_pixel); - lld_lcdDrawPixel(emsg->x, emsg->y, emsg->color); - result = GLCD_DONE; - break; - } - - case GLCD_WRITE_STREAM_START: { - lld_lcdWriteStreamStart(); - result = GLCD_DONE; - break; - } - - case GLCD_WRITE_STREAM_STOP: { - lld_lcdWriteStreamStop(); - result = GLCD_DONE; - break; - } - - case GLCD_WRITE_STREAM: { - EMSG(glcd_msg_write_stream); - lld_lcdWriteStream(emsg->buffer, emsg->size); - result = GLCD_DONE; - break; - } - - case GLCD_VERTICAL_SCROLL: { - EMSG(glcd_msg_vertical_scroll); - lld_lcdVerticalScroll(emsg->x0, emsg->y0, emsg->x1, emsg->y1, emsg->lines); - result = GLCD_DONE; - break; - } - - case GLCD_DRAW_CHAR: { - EMSG(glcd_msg_draw_char); - result = _lcdDrawChar(emsg); - break; - } - - default: { - result = GLCD_FAILED; - break; - } - } - - /* Done, release msg again. */ - chMsgRelease(p, (msg_t)result); - - } - - return 0; -} - -void lcdInit(GLCDDriver *glcdp) { - workerThread = chThdCreateStatic(waGLCDWorkerThread, sizeof(waGLCDWorkerThread), NORMALPRIO, ThreadGLCDWorker, NULL); - - lld_lcdInit(); - lcd_width = lcdGetWidth(); - lcd_height = lcdGetHeight(); - - lcdSetPowerMode(powerOn); - lcdSetOrientation(portrait); -} - -uint16_t lcdGetHeight(void) { - return lld_lcdGetHeight(); -} - -uint16_t lcdGetWidth(void) { - return lld_lcdGetWidth(); -} - -uint16_t lcdGetOrientation(void) { - return lld_lcdGetOrientation(); -} - -glcd_result_t lcdSetPowerMode(uint8_t powerMode) { - struct glcd_msg_powermode msg; - - msg.action = GLCD_SET_POWERMODE; - msg.powermode = powerMode; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -glcd_result_t lcdSetOrientation(uint8_t newOrientation) { - struct glcd_msg_orientation msg; - - msg.action = GLCD_SET_ORIENTATION; - msg.newOrientation = newOrientation; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -glcd_result_t lcdSetWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { - struct glcd_msg_set_window msg; - - msg.action = GLCD_SET_WINDOW; - msg.x0 = x0; - msg.y0 = y0; - msg.x1 = x1; - msg.y1 = y1; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -glcd_result_t lcdFillArea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { - struct glcd_msg_fill_area msg; - - msg.action = GLCD_FILL_AREA; - msg.x0 = x0; - msg.y0 = y0; - msg.x1 = x1; - msg.y1 = y1; - msg.color = color; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -inline glcd_result_t _lcdFillArea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { - lld_lcdFillArea(x0, y0, x1, y1, color); - - return GLCD_DONE; -} - -glcd_result_t lcdWriteArea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t *buffer, size_t n) { - struct glcd_msg_write_area msg; - - msg.action = GLCD_WRITE_AREA; - msg.x0 = x0; - msg.y0 = y0; - msg.x1 = x1; - msg.y1 = y1; - msg.buffer = buffer; - msg.size = n; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -inline glcd_result_t _lcdWriteArea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t *buffer, size_t n) { - lld_lcdSetWindow(x0, y0, x1, y1); - lld_lcdWriteStreamStart(); - lld_lcdWriteStream(buffer, n); - lld_lcdWriteStreamStop(); - - return GLCD_DONE; -} - -glcd_result_t lcdClear(uint16_t color) { - struct glcd_msg_clear msg; - - msg.action = GLCD_CLEAR; - msg.color = color; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -uint16_t lcdGetPixelColor(uint16_t x, uint16_t y) { - struct glcd_msg_get_pixel_color msg; - - msg.action = GLCD_GET_PIXEL_COLOR; - msg.x = x; - msg.y = y; - - chMsgSend(workerThread, (msg_t)&msg); - - return msg.color; -} - -glcd_result_t lcdDrawPixel(uint16_t x, uint16_t y, uint16_t color) { - struct glcd_msg_draw_pixel msg; - - msg.action = GLCD_DRAW_PIXEL; - msg.x = x; - msg.y = y; - msg.color = color; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -glcd_result_t lcdWriteStreamStart(void) { - struct glcd_msg_write_stream_start msg; - - msg.action = GLCD_WRITE_STREAM_START; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -glcd_result_t lcdWriteStreamStop(void) { - struct glcd_msg_write_stream_stop msg; - - msg.action = GLCD_WRITE_STREAM_STOP; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -glcd_result_t lcdWriteStream(uint16_t *buffer, uint16_t size) { - struct glcd_msg_write_stream msg; - - msg.action = GLCD_WRITE_STREAM; - msg.buffer = buffer; - msg.size = size; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -glcd_result_t lcdVerticalScroll(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, int16_t lines) { - struct glcd_msg_vertical_scroll msg; - - msg.action = GLCD_VERTICAL_SCROLL; - msg.x0 = x0; - msg.y0 = y0; - msg.x1 = x1; - msg.y1 = y1; - msg.lines = lines; - - return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); -} - -void lcdDrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { - // speed improvement if vertical or horizontal - if(x0 == x1) { - lcdFillArea(x0, y0, x0+1, y1, color); - } else if (y0 == y1) { - lcdFillArea(x0, y0, x1, y0+1, color); - - } else { - int16_t dy, dx; - int16_t addx = 1, addy = 1; - int16_t P, diff; - - int16_t i = 0; - dx = abs((int16_t)(x1 - x0)); - dy = abs((int16_t)(y1 - y0)); - - if(x0 > x1) - addx = -1; - if(y0 > y1) - addy = -1; - - if(dx >= dy) { - dy *= 2; - P = dy - dx; - diff = P - dx; - - for(; i<=dx; ++i) { - lcdDrawPixel(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<=dy; ++i) { - lcdDrawPixel(x0, y0, color); - if(P < 0) { - P += dx; - y0 += addy; - } else { - P += diff; - x0 += addx; - y0 += addy; - } - } - } - } -} - -uint16_t lcdDrawChar(uint16_t cx, uint16_t cy, char c, font_t font, uint16_t color, uint16_t bkcolor, bool_t tpText) { - struct glcd_msg_draw_char msg; - - msg.action = GLCD_DRAW_CHAR; - msg.cx = cx; - msg.cy = cy; - msg.c = c; - msg.font = font; - msg.color = color; - msg.bkcolor = bkcolor; - msg.tpText = tpText; - msg.ret_width = 0; - - chMsgSend(workerThread, (msg_t)&msg); - - return msg.ret_width; -} - -glcd_result_t _lcdDrawChar(struct glcd_msg_draw_char *m) { - /* Working pointer */ - const uint8_t* ptr; - uint8_t x, y; - - /* Variables to store character details */ - uint8_t charWidth; - uint8_t charHeight = lcdGetFontHeight(m->font); - uint8_t padAfterChar = m->font[FONT_TABLE_PAD_AFTER_CHAR_IDX]; - - /* Local var to hold offset in font table */ - uint16_t charStartOffset; - - /* Working buffer for fast non-transparent text rendering [patch by Badger] */ - static uint16_t buf[20*16]; - - /* No support for nongraphic characters, so just ignore them */ - if(m->c < 0x20 || m->c > 0x7F) { - return GLCD_DONE; - } - - /* Read the offset of the character data in the font table from the lookup table */ - charStartOffset = *(uint16_t*)(&m->font[FONT_TABLE_CHAR_LOOKUP_IDX + (m->c - 0x20) * 2]); - - /* After we're done, position the pointer at the offset. - * The first byte that is immediately read will be the font width - * After that, actual 16-bit font data follows, first column down */ - ptr = m->font + charStartOffset; - charWidth = *(ptr++); - - /* Loop through the data and display. The font data is LSB first, down the column */ - for(x = 0; x < charWidth; x++) { - /* Get the font bitmap data for the column */ - uint16_t charData = *(uint16_t*)ptr; - - for(y = 0; y < charHeight; y++) { - /* Draw the LSB on the screen accordingly. */ - if(!m->tpText) { - /* Store data into working buffer (patch by Badger), - * Then write it all onto the LCD in one stroke */ - buf[y*charWidth + x] = (charData & 0x01) ? m->color : m->bkcolor; - } else { - /* Just draw the needed pixels onto the LCD */ - if (charData & 0x01) - lcdDrawPixel(m->cx+x, m->cy+y, m->color); - } - - /* Shift the data down by one bit */ - charData >>= 1; - } - - /* Increment pointer by 2 bytes to the next column */ - ptr += 2; - } - - if(!m->tpText) { - /* [Patch by Badger] Write all in one stroke */ - _lcdWriteArea(m->cx, m->cy, m->cx+charWidth, m->cy+charHeight, buf, charWidth*charHeight); - - /* Do padding after character, if needed for solid text rendering - * TODO: To be optimised */ - if (padAfterChar != 0) { - _lcdFillArea(m->cx+charWidth, m->cy+charHeight, m->cx+charWidth+padAfterChar, m->cy+charHeight, m->bkcolor); - } - } - - /* Return the width of the character, we need it so that lcdDrawString may work - * We don't have a static address counter */ - m->ret_width = charWidth + padAfterChar; - - return GLCD_DONE; -} - -/* WARNING: No boundary checks! Unpredictable behaviour if text exceeds boundary */ -void lcdDrawString(uint16_t x, uint16_t y, const char *str, font_t font, uint16_t color, uint16_t bkcolor, bool_t tpText) { - uint16_t cx = x, cy = y; - - while (*str) { - cx += lcdDrawChar(cx, cy, *str++, font, color, bkcolor, tpText); - } -} - -uint16_t lcdMeasureChar(char c, font_t font) { - /* Variables to store character details */ - uint8_t charWidth; - uint8_t padAfterChar = font[FONT_TABLE_PAD_AFTER_CHAR_IDX]; - - /* Local var to hold offset in font table */ - uint16_t charStartOffset; - - /* No support for nongraphic characters, so just ignore them */ - if(c < 0x20 || c > 0x7F) { - return 0; - } - - /* Read the offset of the character data in the font table from the lookup table */ - charStartOffset = *(uint16_t*)(&font[FONT_TABLE_CHAR_LOOKUP_IDX + (c - 0x20) * 2]); - - /* Retrurn the byte at the offset, that's our charWidth */ - charWidth = *(font + charStartOffset); - - return charWidth+padAfterChar; -} - -uint16_t lcdMeasureString(const char *str, font_t font) { - uint16_t result = 0; - - /* Measure each char width, add it, return the result */ - while (*str) - result += lcdMeasureChar(*str++, font); - - return result; -} - -uint16_t lcdBGR2RGB(uint16_t color) { - uint16_t r, g, b, rgb; - - b = ( color>>0 ) & 0x1f; - g = ( color>>5 ) & 0x3f; - r = ( color>>11 ) & 0x1f; - - rgb = (b<<11) + (g<<5) + (r<<0); - - return( rgb ); -} - -void lcdDrawRect(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t filled, uint16_t color) { - uint16_t i, TempX; - uint16_t j, TempY; - - if (x0 > x1) { - TempX = x1; - x1 = x0; - x0 = TempX; - } - if (y0 > y1) { - TempY = y1; - y1 = y0; - y0 = TempY; - } - if(filled) { - lcdFillArea(x0, y0, x1+1, y1+1, color); - } else { - lcdDrawLine(x0, y0, x1, y0, color); - lcdDrawLine(x0, y1, x1, y1, color); - lcdDrawLine(x0, y0, x0, y1, color); - lcdDrawLine(x1, y0, x1, y1+1, color); - } -} - -void lcdDrawRectString(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, const char* str, font_t font, uint16_t fontColor, uint16_t bkColor) { - uint16_t off_left, off_up; - - off_left = ((x1-x0)-lcdMeasureString(str, font))/2; - off_up = ((y1-y0) - lcdGetFontHeight(font)) / 2; - - lcdDrawRect(x0, y0, x1, y1, filled, bkColor); - /* Abhishek: default to solid text for this? */ - lcdDrawString(x0+off_left, y0+off_up, str, font, fontColor, bkColor, solid); -} - -void lcdDrawCircle(uint16_t x, uint16_t y, uint16_t radius, uint8_t filled, uint16_t color) { - int16_t a, b, P; - a = 0; - b = radius; - P = 1 - radius; - - do { - if(filled) { - lcdDrawLine(x-a, y+b, x+a, y+b, color); - lcdDrawLine(x-a, y-b, x+a, y-b, color); - lcdDrawLine(x-b, y+a, x+b, y+a, color); - lcdDrawLine(x-b, y-a, x+b, y-a, color); - } else { - lcdDrawPixel(a+x, b+y, color); - lcdDrawPixel(b+x, a+y, color); - lcdDrawPixel(x-a, b+y, color); - lcdDrawPixel(x-b, a+y, color); - lcdDrawPixel(b+x, y-a, color); - lcdDrawPixel(a+x, y-b, color); - lcdDrawPixel(x-a, y-b, color); - lcdDrawPixel(x-b, y-a, color); - } - - if(P < 0) - P += 3 + 2*a++; - else - P += 5 + 2*(a++ - b--); - } while(a <= b); -} - -void lcdDrawEllipse(uint16_t x, uint16_t y, uint16_t a, uint16_t b, uint8_t filled, uint16_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 { - if(filled){ - lcdDrawLine(x-dx,y+dy,x+dx,y+dy, color); - lcdDrawLine(x-dx,y-dy,x+dx,y-dy, color); - }else{ - lcdDrawPixel(x+dx, y+dy, color); /* I. Quadrant */ - lcdDrawPixel(x-dx, y+dy, color); /* II. Quadrant */ - lcdDrawPixel(x-dx, y-dy, color); /* III. Quadrant */ - lcdDrawPixel(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) */ - lcdDrawPixel(x+dx, y, color); /* -> Spitze der Ellipse vollenden */ - lcdDrawPixel(x-dx, y, color); - } -} - +/* + ChibiOS/RT - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS-LCD-Driver. + + ChibiOS-LCD-Driver 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-LCD-Driver 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 . +*/ + +#include "ch.h" +#include "hal.h" + +#ifdef UNUSED +#elif defined(__GNUC__) +# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) +#elif defined(__LCLINT__) +# define UNUSED(x) /*@unused@*/ x +#else +# define UNUSED(x) x +#endif + +/* Hack 1: Manually load the low level driver capabilities first so we can + * control what we implement with hardware scrolling and pixel read. + */ +#include "gdisp_lld_config.h" + +/* Hack 2: Force on the bits of functionality that glcd needs. */ +#define HAL_USE_GDISP TRUE +#define GDISP_NEED_VALIDATION FALSE /* The original glcd didn't so we don't here either */ +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_ELLIPSE TRUE +#define GDISP_NEED_TEXT TRUE +#define GDISP_NEED_SCROLL GDISP_HARDWARE_SCROLL +#define GDISP_NEED_PIXELREAD GDISP_HARDWARE_PIXELREAD +#define GDISP_NEED_CONTROL TRUE +#define GDISP_NEED_MULTITHREAD FALSE /* We implement multi-thread here */ + +/* Now load the low level driver and font structure definitions */ +#include "gdisp_lld.h" +#include "gdisp_fonts.h" + +/* Hack 3: GLCD only supports RGB565. Anything else would require significant API changes. */ +#ifndef GDISP_PIXELFORMAT_RGB565 +#error "GLCD only support drivers with RGB565 pixel format" +#endif + +/* Now load the glcd headers */ +#include "glcd.h" +#include "glcdWorker.h" + +/* Hack 4: Include the emulation code and font tables. + * We have to include it here rather than compiling + * the files as we need to pass our control defines + * as they are not being defined by the application. + * We need to turn off the inclusion of gdisp.h due + * to conflicting type defines etc. + */ +#define _GDISP_H // Prevent gdisp.h from being included +#include "gdisp_emulation.c" +#include "gdisp_fonts.c" + +#define EMSG(a) struct a *emsg = (struct a*)msg + +static Thread *workerThread = NULL; + +static WORKING_AREA(waGLCDWorkerThread, GLCD_WORKER_SIZE); +static msg_t ThreadGLCDWorker(void *arg) { + (void)arg; + Thread *p; + + chRegSetThreadName("GLCDWorker"); + + while(TRUE) { + /* Wait for msg with work to do. */ + p = chMsgWait(); + struct glcd_msg_base *msg = (struct glcd_msg_base*)chMsgGet(p); + glcd_result_t result = GLCD_PROGRESS; + + /* do work here */ + switch(msg->action) { + case GLCD_SET_POWERMODE: { + EMSG(glcd_msg_powermode); + gdisp_lld_control(GDISP_CONTROL_POWER, (void *)(int)emsg->powermode); + result = GLCD_DONE; + break; + } + + case GLCD_SET_ORIENTATION: { + EMSG(glcd_msg_orientation); + gdisp_lld_control(GDISP_CONTROL_ORIENTATION, (void *)(int)emsg->newOrientation); + result = GLCD_DONE; + break; + } + case GLCD_FILL_AREA: { + EMSG(glcd_msg_fill_area); + gdisp_lld_fillarea(emsg->x0, emsg->y0, emsg->x1-emsg->x0+1,emsg->y1-emsg->y0+1,emsg->color); + result = GLCD_DONE; + break; + } + + case GLCD_WRITE_AREA: { + EMSG(glcd_msg_write_area); + gdisp_lld_blitarea(emsg->x0, emsg->y0, emsg->x1-emsg->x0+1, emsg->y1-emsg->y0+1, emsg->buffer); + result = GLCD_DONE; + break; + } + + case GLCD_CLEAR: { + EMSG(glcd_msg_clear); + gdisp_lld_clear(emsg->color); + result = GLCD_DONE; + break; + } + + case GLCD_GET_PIXEL_COLOR: { + /* Hack 5: This may now fail if the low level driver doesn't + * support it. Previously this support was required + * in the driver by GLCD + */ +#if GDISP_HARDWARE_READPIXEL + ((struct glcd_msg_get_pixel_color *)emsg)->color = + gdisp_lld_getpixelcolor(emsg->x, emsg->y); + result = GLCD_DONE; +#else + EMSG(glcd_msg_get_pixel_color); + ((struct glcd_msg_get_pixel_color *)emsg)->color = 0; + result = GLCD_FAILED; +#endif + break; + } + + case GLCD_DRAW_PIXEL: { + EMSG(glcd_msg_draw_pixel); + gdisp_lld_drawpixel(emsg->x, emsg->y, emsg->color); + result = GLCD_DONE; + break; + } + + case GLCD_VERTICAL_SCROLL: { + /* Hack 6: This may now fail if the low level driver doesn't + * support it. Previously this support was required + * in the driver by GLCD + */ +#if GDISP_HARDWARE_SCROLL + EMSG(glcd_msg_vertical_scroll); + gdisp_lld_verticalscroll(emsg->x0, emsg->y0, emsg->x1-emsg->x0+1, emsg->y1-emsg->y0+1, emsg->lines, 0); + result = GLCD_DONE; +#else + result = GLCD_FAILED; +#endif + break; + } + + case GLCD_DRAW_CHAR: { + EMSG(glcd_msg_draw_char); + if (emsg->tpText) + gdisp_lld_drawchar(emsg->cx, emsg->cy, emsg->c, emsg->font, emsg->color); + else + gdisp_lld_fillchar(emsg->cx, emsg->cy, emsg->c, emsg->font, emsg->color, emsg->bkcolor); + /* We can't normally access a high level function here but in this case it is safe + * because the routine only accesses const data members (multi-thread safe). + */ + emsg->ret_width = lcdMeasureChar(emsg->c, emsg->font); + result = GLCD_DONE; + break; + } + + default: { + result = GLCD_FAILED; + break; + } + } + + /* Done, release msg again. */ + chMsgRelease(p, (msg_t)result); + + } + + return 0; +} + +void lcdInit(GLCDDriver *UNUSED(glcdp)) { + workerThread = chThdCreateStatic(waGLCDWorkerThread, sizeof(waGLCDWorkerThread), NORMALPRIO, ThreadGLCDWorker, NULL); + + gdisp_lld_init(); +} + +uint16_t lcdGetHeight(void) { + return GDISP.Height; +} + +uint16_t lcdGetWidth(void) { + return GDISP.Width; +} + +uint16_t lcdGetOrientation(void) { + return GDISP.Orientation; +} + +glcd_result_t lcdSetPowerMode(uint8_t powerMode) { + struct glcd_msg_powermode msg; + + msg.action = GLCD_SET_POWERMODE; + msg.powermode = powerMode; + + return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); +} + +glcd_result_t lcdSetOrientation(uint8_t newOrientation) { + struct glcd_msg_orientation msg; + + msg.action = GLCD_SET_ORIENTATION; + msg.newOrientation = newOrientation; + + return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); +} + +glcd_result_t lcdFillArea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { + struct glcd_msg_fill_area msg; + + msg.action = GLCD_FILL_AREA; + msg.x0 = x0; + msg.y0 = y0; + msg.x1 = x1; + msg.y1 = y1; + msg.color = color; + + return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); +} + +glcd_result_t lcdWriteArea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t *buffer, size_t n) { + struct glcd_msg_write_area msg; + + msg.action = GLCD_WRITE_AREA; + msg.x0 = x0; + msg.y0 = y0; + msg.x1 = x1; + msg.y1 = y1; + msg.buffer = buffer; + msg.size = n; + + return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); +} + +glcd_result_t lcdClear(uint16_t color) { + struct glcd_msg_clear msg; + + msg.action = GLCD_CLEAR; + msg.color = color; + + return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); +} + +uint16_t lcdGetPixelColor(uint16_t x, uint16_t y) { + struct glcd_msg_get_pixel_color msg; + + msg.action = GLCD_GET_PIXEL_COLOR; + msg.x = x; + msg.y = y; + + chMsgSend(workerThread, (msg_t)&msg); + + return msg.color; +} + +glcd_result_t lcdDrawPixel(uint16_t x, uint16_t y, uint16_t color) { + struct glcd_msg_draw_pixel msg; + + msg.action = GLCD_DRAW_PIXEL; + msg.x = x; + msg.y = y; + msg.color = color; + + return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); +} + +glcd_result_t lcdVerticalScroll(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, int16_t lines) { + struct glcd_msg_vertical_scroll msg; + + msg.action = GLCD_VERTICAL_SCROLL; + msg.x0 = x0; + msg.y0 = y0; + msg.x1 = x1; + msg.y1 = y1; + msg.lines = lines; + + return (glcd_result_t)chMsgSend(workerThread, (msg_t)&msg); +} + +void lcdDrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { + struct glcd_msg_draw_line msg; + + msg.action = GLCD_DRAW_LINE; + msg.x0 = x0; + msg.y0 = y0; + msg.x1 = x1; + msg.y1 = y1; + msg.color = color; + + chMsgSend(workerThread, (msg_t)&msg); +} + +uint16_t lcdDrawChar(uint16_t cx, uint16_t cy, char c, font_t font, uint16_t color, uint16_t bkcolor, bool_t tpText) { + struct glcd_msg_draw_char msg; + + msg.action = GLCD_DRAW_CHAR; + msg.cx = cx; + msg.cy = cy; + msg.c = c; + msg.font = font; + msg.color = color; + msg.bkcolor = bkcolor; + msg.tpText = tpText; + msg.ret_width = 0; + + chMsgSend(workerThread, (msg_t)&msg); + + return msg.ret_width; +} + +void lcdDrawCircle(uint16_t x, uint16_t y, uint16_t radius, uint8_t filled, uint16_t color) { + struct glcd_msg_draw_circle msg; + + msg.action = GLCD_DRAW_CIRCLE; + msg.x = x; + msg.y = y; + msg.radius = radius; + msg.filled = filled; + msg.color = color; + + chMsgSend(workerThread, (msg_t)&msg); +} + +void lcdDrawEllipse(uint16_t x, uint16_t y, uint16_t a, uint16_t b, uint8_t filled, uint16_t color) { + struct glcd_msg_draw_ellipse msg; + + msg.action = GLCD_DRAW_ELLIPSE; + msg.x = x; + msg.y = y; + msg.a = a; + msg.b = b; + msg.filled = filled; + msg.color = color; + + chMsgSend(workerThread, (msg_t)&msg); +} + +/* WARNING: No boundary checks! Unpredictable behaviour if text exceeds boundary */ +void lcdDrawString(uint16_t x, uint16_t y, const char *str, font_t font, uint16_t color, uint16_t bkcolor, bool_t tpText) { + uint16_t cx = x, cy = y; + + while (*str) { + cx += lcdDrawChar(cx, cy, *str++, font, color, bkcolor, tpText); + } +} + +uint16_t lcdMeasureChar(char c, font_t font) { + return (_getCharWidth(font, c)+font->charPadding) * font->xscale; +} + +uint16_t lcdMeasureString(const char *str, font_t font) { + uint16_t result = 0; + + /* Measure each char width, add it, return the result */ + while (*str) + result += lcdMeasureChar(*str++, font); + + return result; +} + +uint16_t lcdGetFontHeight(font_t font) { + return font->height; +} + +uint16_t lcdBGR2RGB(uint16_t color) { + uint16_t r, g, b, rgb; + + b = ( color>>0 ) & 0x1f; + g = ( color>>5 ) & 0x3f; + r = ( color>>11 ) & 0x1f; + + rgb = (b<<11) + (g<<5) + (r<<0); + + return( rgb ); +} + +void lcdDrawRect(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t filled, uint16_t color) { + uint16_t TempX; + uint16_t TempY; + + if (x0 > x1) { + TempX = x1; + x1 = x0; + x0 = TempX; + } + if (y0 > y1) { + TempY = y1; + y1 = y0; + y0 = TempY; + } + if(filled) { + lcdFillArea(x0, y0, x1+1, y1+1, color); + } else { + lcdDrawLine(x0, y0, x1, y0, color); + lcdDrawLine(x0, y1, x1, y1, color); + lcdDrawLine(x0, y0, x0, y1, color); + lcdDrawLine(x1, y0, x1, y1+1, color); + } +} + +void lcdDrawRectString(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, const char* str, font_t font, uint16_t fontColor, uint16_t bkColor) { + uint16_t off_left, off_up; + + off_left = ((x1-x0)-lcdMeasureString(str, font))/2; + off_up = ((y1-y0) - lcdGetFontHeight(font)) / 2; + + lcdDrawRect(x0, y0, x1, y1, filled, bkColor); + /* Abhishek: default to solid text for this? */ + lcdDrawString(x0+off_left, y0+off_up, str, font, fontColor, bkColor, solid); +} -- cgit v1.2.3