diff options
author | Tectu <joel@unormal.org> | 2013-02-17 23:52:34 -0800 |
---|---|---|
committer | Tectu <joel@unormal.org> | 2013-02-17 23:52:34 -0800 |
commit | 778cfcd928211246b45ce67c373280fe6adceb11 (patch) | |
tree | 2af82d8674eb0c69c8a2d8b9055f3a5e57833cfe | |
parent | d41120ee2dc37f7feee7dde40abbb4dae430f7d3 (diff) | |
parent | 9bec5967b293d6c23c9d7e9338d8ece4873f6eac (diff) | |
download | uGFX-778cfcd928211246b45ce67c373280fe6adceb11.tar.gz uGFX-778cfcd928211246b45ce67c373280fe6adceb11.tar.bz2 uGFX-778cfcd928211246b45ce67c373280fe6adceb11.zip |
Merge pull request #33 from inmarket/master
GADC implementation, TDISP fix and GDISP fixes
36 files changed, 10566 insertions, 9140 deletions
diff --git a/demos/modules/gadc/gfxconf.h b/demos/modules/gadc/gfxconf.h new file mode 100644 index 00000000..58475fba --- /dev/null +++ b/demos/modules/gadc/gfxconf.h @@ -0,0 +1,105 @@ +/** + * 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 + +/* 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_OLD_FONT_DEFINITIONS FALSE +#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/gadc/gwinosc.c b/demos/modules/gadc/gwinosc.c new file mode 100644 index 00000000..d08fbc0d --- /dev/null +++ b/demos/modules/gadc/gwinosc.c @@ -0,0 +1,183 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * --------------------------- Our Custom GWIN Oscilloscope --------------- + * + * This GWIN superset implements a simple audio oscilloscope using the GADC high speed device. + */ +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#include "gwinosc.h" + +/* Include internal GWIN routines so we can build our own superset class */ +#include "gwin/internal.h" + +/* Our GWIN identifier */ +#define GW_SCOPE (GW_FIRST_USER_WINDOW+0) + +/* The size of our dynamically allocated audio buffer */ +#define AUDIOBUFSZ 64*2 + +/* How many flat-line sample before we trigger */ +#define FLATLINE_SAMPLES 8 + +GHandle gwinCreateScope(GScopeObject *gs, coord_t x, coord_t y, coord_t cx, coord_t cy, uint32_t physdev, uint32_t frequency) { + /* Initialise the base class GWIN */ + if (!(gs = (GScopeObject *)_gwinInit((GWindowObject *)gs, x, y, cx, cy, sizeof(GScopeObject)))) + return 0; + + /* Initialise the scope object members and allocate memory for buffers */ + gs->gwin.type = GW_SCOPE; + chBSemInit(&gs->bsem, TRUE); + gs->nextx = 0; + if (!(gs->lastscopetrace = (coord_t *)chHeapAlloc(NULL, gs->gwin.width * sizeof(coord_t)))) + return 0; + if (!(gs->audiobuf = (adcsample_t *)chHeapAlloc(NULL, AUDIOBUFSZ * sizeof(adcsample_t)))) + return 0; +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + gs->lasty = gs->gwin.height/2; +#elif TRIGGER_METHOD == TRIGGER_MINVALUE + gs->lasty = gs->gwin.height/2; + gs->scopemin = 0; +#endif + + /* Start the GADC high speed converter */ + gadcHighSpeedInit(physdev, frequency, gs->audiobuf, AUDIOBUFSZ, AUDIOBUFSZ/2); + gadcHighSpeedSetBSem(&gs->bsem, &gs->myEvent); + gadcHighSpeedStart(); + + return (GHandle)gs; +} + +void gwinWaitForScopeTrace(GHandle gh) { + #define gs ((GScopeObject *)(gh)) + int i; + coord_t x, y; + coord_t yoffset; + adcsample_t *pa; + coord_t *pc; +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + bool_t rdytrigger; + int flsamples; +#elif TRIGGER_METHOD == TRIGGER_MINVALUE + bool_t rdytrigger; + int flsamples; + coord_t scopemin; +#endif + + /* Wait for a set of audio conversions */ + chBSemWait(&gs->bsem); + + /* Ensure we are drawing in the right area */ + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + + yoffset = gh->height/2 + (1<<SCOPE_Y_BITS)/2; + x = gs->nextx; + pc = gs->lastscopetrace+x; + pa = gs->myEvent.buffer; +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + rdytrigger = FALSE; + flsamples = 0; +#elif TRIGGER_METHOD == TRIGGER_MINVALUE + rdytrigger = FALSE; + flsamples = 0; + scopemin = 0; +#endif + + for(i = gs->myEvent.count; i; i--) { + + /* Calculate the new scope value - re-scale using simple shifts for efficiency, re-center and y-invert */ + #if GADC_BITS_PER_SAMPLE > SCOPE_Y_BITS + y = yoffset - (*pa++ >> (GADC_BITS_PER_SAMPLE - SCOPE_Y_BITS)); + #else + y = yoffset - (*pa++ << (SCOPE_Y_BITS - GADC_BITS_PER_SAMPLE)); + #endif + +#if TRIGGER_METHOD == TRIGGER_MINVALUE + /* Calculate the scopemin ready for the next trace */ + if (y > scopemin) + scopemin = y; +#endif + + /* Have we reached the end of a scope trace? */ + if (x >= gh->width) { + +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP || TRIGGER_METHOD == TRIGGER_MINVALUE + /* Handle triggering - we trigger on the next sample minimum (y value maximum) or a flat-line */ + + #if TRIGGER_METHOD == TRIGGER_MINVALUE + /* Arm when we reach the sample minimum (y value maximum) of the previous trace */ + if (!rdytrigger && y >= gs->scopemin) + rdytrigger = TRUE; + #endif + + if (y == gs->lasty) { + /* Trigger if we get too many flat-line samples regardless of the armed state */ + if (++flsamples < FLATLINE_SAMPLES) + continue; + flsamples = 0; + } else if (y > gs->lasty) { + gs->lasty = y; + flsamples = 0; + #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + /* Arm the trigger when samples fall (y increases) ie. negative slope */ + rdytrigger = TRUE; + #endif + continue; + } else { + /* If the trigger is armed, Trigger when samples increases (y decreases) ie. positive slope */ + gs->lasty = y; + flsamples = 0; + if (!rdytrigger) + continue; + } + + /* Ready for a the next trigger cycle */ + rdytrigger = FALSE; +#endif + + /* Prepare for a scope trace */ + x = 0; + pc = gs->lastscopetrace; + } + + /* Clear the old scope pixel and then draw the new scope value */ + gdispDrawPixel(gh->x+x, gh->y+pc[0], gh->bgcolor); + gdispDrawPixel(gh->x+x, gh->y+y, gh->color); + + /* Save the value */ + *pc++ = y; + x++; + #if TRIGGER_METHOD == TRIGGER_POSITIVERAMP || TRIGGER_METHOD == TRIGGER_MINVALUE + gs->lasty = y; + #endif + } + gs->nextx = x; +#if TRIGGER_METHOD == TRIGGER_MINVALUE + gs->scopemin = scopemin; +#endif + + #undef gs +} diff --git a/demos/modules/gadc/gwinosc.h b/demos/modules/gadc/gwinosc.h new file mode 100644 index 00000000..ec44937d --- /dev/null +++ b/demos/modules/gadc/gwinosc.h @@ -0,0 +1,89 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +#ifndef _GWINOSC_H +#define _GWINOSC_H + +/** + * --------------------------- Our Custom GWIN Oscilloscope --------------- + * + * This GWIN superset implements a simple audio oscilloscope using the GADC high speed device. + */ + +/* The extent of scaling for our audio data - fixed scale at the moment */ +#ifndef SCOPE_Y_BITS + #define SCOPE_Y_BITS 7 // 7 bits = 0..128 +#endif + +/* Trigger methods */ +#define TRIGGER_NONE 0 /* No triggering */ +#define TRIGGER_POSITIVERAMP 1 /* Trigger on a positive going signal */ +#define TRIGGER_MINVALUE 2 /* Trigger on reaching the minimum value from the last scope */ + +/** + * Which trigger we want to use. + * Experiments suggests that TRIGGER_MINVALUE gives the best result + */ +#ifndef TRIGGER_METHOD + #define TRIGGER_METHOD TRIGGER_MINVALUE +#endif + +/* A scope window object. Treat it as a black box */ +typedef struct GScopeObject_t { + GWindowObject gwin; // Base Class + + coord_t *lastscopetrace; // To store last scope trace + BinarySemaphore bsem; // We get signalled on this + adcsample_t *audiobuf; // To store audio samples + GEventADC myEvent; // Information on received samples + coord_t nextx; // Where we are up to +#if TRIGGER_METHOD == TRIGGER_POSITIVERAMP + coord_t lasty; // The last y value - used for trigger slope detection +#elif TRIGGER_METHOD == TRIGGER_MINVALUE + coord_t lasty; // The last y value - used for trigger slope detection + coord_t scopemin; // The last scopes minimum value +#endif + } GScopeObject; + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Create a scope window. + */ + GHandle gwinCreateScope(GScopeObject *gs, coord_t x, coord_t y, coord_t cx, coord_t cy, uint32_t physdev, uint32_t frequency); + + /** + * Wait for a scope trace to be ready and then draw it. + */ + void gwinWaitForScopeTrace(GHandle gh); + + /** + * We should also have a special destroy routine here as we have dynamically + * allocated some memory. There is no point implementing this however as, for + * this demo, we never destroy the window. + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GWINOSC_H */ diff --git a/demos/modules/gadc/main.c b/demos/modules/gadc/main.c new file mode 100644 index 00000000..07802521 --- /dev/null +++ b/demos/modules/gadc/main.c @@ -0,0 +1,176 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * This demo demonstrates the use of the GADC module using it read both a microphone, + * an analogue dial wheel and a temperature sensor. + * The microphone gets read at high frequency to display a very simple oscilloscope. + * The dial and temperature gets read at a low frequency to just print when + * it changes value. + * + * It also demonstrates how to write your own custom GWIN window type. + */ +#include "ch.h" +#include "hal.h" +#include "chprintf.h" + +#include "gfx.h" + +/* Include our custom gwin oscilloscope */ +#include "gwinosc.h" + +/* + * Match these to your hardware + * If you don't have a DIAL device or a TEMP device - just don't define it. + */ +#define MY_MIC_DEVICE GADC_PHYSDEV_MICROPHONE +#define MY_DIAL_DEVICE GADC_PHYSDEV_DIAL +#define MY_TEMP_DEVICE GADC_PHYSDEV_TEMPERATURE +#define MY_DIAL_JITTER 1 +#define MY_TEMP_JITTER 3 + +/* Specify our timing parameters */ +#define MY_MIC_FREQUENCY 4000 /* 4khz */ +#define MY_LS_DELAY 200 /* 200ms (5 times per second) for the dial and temperature */ + +/* The desired size for our scope window */ +#define SCOPE_CX 64 +#define SCOPE_CY 64 + +/* Data */ +static GScopeObject gScopeWindow; +static GConsoleObject gTextWindow; +static GTimer lsTimer; + +#ifdef MY_DIAL_DEVICE + static adcsample_t dialvalue; + static adcsample_t lastdial = -(MY_DIAL_JITTER+1); + + /** + * We have got a dial reading - handle it + */ + static void GotDialReading(adcsample_t *buffer, void *param) { + (void) buffer; + + /* Buffer should always point to "dialvalue" anyway */ + + /* Remove jitter from the value */ + if ((dialvalue > lastdial && dialvalue - lastdial > MY_DIAL_JITTER) + || (lastdial > dialvalue && lastdial - dialvalue > MY_DIAL_JITTER)) { + + /* Write the value */ + chprintf((BaseSequentialStream *)param, "DIAL: %u\n", dialvalue); + + /* Save for next time */ + lastdial = dialvalue; + } + } +#endif + +#ifdef MY_TEMP_DEVICE + static adcsample_t tempvalue; + static adcsample_t lasttemp = -(MY_TEMP_JITTER+1); + + /** + * We have got a temperature reading - handle it + */ + static void GotTempReading(adcsample_t *buffer, void *param) { + (void) buffer; + + /* Buffer should always point to "tempvalue" anyway */ + + /* Remove jitter from the value */ + if ((tempvalue > lasttemp && tempvalue - lasttemp > MY_TEMP_JITTER) + || (lasttemp > tempvalue && lasttemp - tempvalue > MY_TEMP_JITTER)) { + + /* Write the value */ + chprintf((BaseSequentialStream *)param, "TEMP: %u\n", tempvalue); + + /* Save for next time */ + lasttemp = tempvalue; + } + } +#endif + +#if defined(MY_DIAL_DEVICE) || defined(MY_TEMP_DEVICE) + /** + * Start a read of the dial and temperature + */ + static void LowSpeedTimer(void *param) { + /* We are not checking for an error here - but who cares, this is just a demo */ + #ifdef MY_DIAL_DEVICE + gadcLowSpeedStart(MY_DIAL_DEVICE, &dialvalue, GotDialReading, param); + #endif + #ifdef MY_TEMP_DEVICE + gadcLowSpeedStart(MY_TEMP_DEVICE, &tempvalue, GotTempReading, param); + #endif + } +#endif + +/* + * Application entry point. + */ +int main(void) { + GHandle ghScope; + coord_t swidth, sheight; + #if defined(MY_DIAL_DEVICE) || defined(MY_TEMP_DEVICE) + GHandle ghText; + BaseSequentialStream *gsText; + font_t font; + #endif + + halInit(); + chSysInit(); + gdispInit(); + gdispClear(Black); + + /* Get the screen dimensions */ + swidth = gdispGetWidth(); + sheight = gdispGetHeight(); + + #if defined(MY_DIAL_DEVICE) || defined(MY_TEMP_DEVICE) + /* Set up the console window we use for dial readings */ + font = gdispOpenFont("UI2"); + ghText = gwinCreateConsole(&gTextWindow, 0, 0, swidth-SCOPE_CX, sheight, font); + gwinSetBgColor(ghText, Black); + gwinSetColor(ghText, Yellow); + gwinClear(ghText); + gsText = gwinGetConsoleStream(ghText); + + /* Start our timer for reading the dial */ + gtimerInit(&lsTimer); + gtimerStart(&lsTimer, LowSpeedTimer, gsText, TRUE, MY_LS_DELAY); + #endif + + /* Set up the scope window in the top right on the screen */ + ghScope = gwinCreateScope(&gScopeWindow, swidth-SCOPE_CX, 0, SCOPE_CX, SCOPE_CY, MY_MIC_DEVICE, MY_MIC_FREQUENCY); + gwinSetBgColor(ghScope, White); + gwinSetColor(ghScope, Red); + gwinClear(ghScope); + + /* Just keep displaying the scope traces */ + while (TRUE) { + /** + * The function below internally performs a wait thus giving the timer thread a + * chance to run. + */ + gwinWaitForScopeTrace(ghScope); + } +} diff --git a/demos/modules/gadc/results_264x264.jpg b/demos/modules/gadc/results_264x264.jpg Binary files differnew file mode 100644 index 00000000..25aadf81 --- /dev/null +++ b/demos/modules/gadc/results_264x264.jpg diff --git a/drivers/gadc/AT91SAM7/gadc_lld.c b/drivers/gadc/AT91SAM7/gadc_lld.c new file mode 100644 index 00000000..4b3c6cae --- /dev/null +++ b/drivers/gadc/AT91SAM7/gadc_lld.c @@ -0,0 +1,102 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ +/** + * @file include/gadc/lld/gadc_lld.c + * @brief GADC - Periodic ADC driver source file for the AT91SAM7 cpu. + * + * @defgroup Driver Driver + * @ingroup GADC + * @{ + */ + +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if GFX_USE_GADC + +#include "gadc/lld/gadc_lld.h" + +static ADCConversionGroup acg = { + FALSE, // circular + 1, // num_channels + GADC_ISR_CompleteI, // end_cb + GADC_ISR_ErrorI, // error_cb + 0, // channelselects + 0, // trigger + 0, // frequency + }; + +void gadc_lld_init(void) { + adcStart(&ADCD1, NULL); +} + +size_t gadc_lld_samples_per_conversion(uint32_t physdev) { + size_t cnt; + int i; + + /* The AT91SAM7 has AD0..7 - physdev is a bitmap of those channels */ + for(cnt = 0, i = 0; i < 8; i++, physdev >>= 1) + if (physdev & 0x01) + cnt++; + return cnt; +} + +void gadc_lld_start_timer(uint32_t physdev, uint32_t frequency) { + (void) physdev; + /** + * The AT91SAM7 ADC driver supports triggering the ADC using a timer without having to implement + * an interrupt handler for the timer. The driver also initialises the timer correctly for us. + * Because we aren't trapping the interrupt ourselves we can't increment GADC_Timer_Missed if an + * interrupt is missed. + */ + acg.frequency = frequency; +} + +void gadc_lld_stop_timer(uint32_t physdev) { + (void) physdev; + if ((acg.trigger & ~ADC_TRIGGER_SOFTWARE) == ADC_TRIGGER_TIMER) + adcStop(&ADCD1); +} + +void gadc_lld_adc_timerI(GadcLldTimerData *pgtd) { + /** + * We don't need to calculate num_channels because the AT91SAM7 ADC does this for us. + */ + acg.channelselects = pgtd->physdev; + acg.trigger = pgtd->now ? (ADC_TRIGGER_TIMER|ADC_TRIGGER_SOFTWARE) : ADC_TRIGGER_TIMER; + + adcStartConversionI(&ADCD1, &acg, pgtd->buffer, pgtd->count); + + /* Next time assume the same (still running) timer */ + acg.frequency = 0; +} + +void gadc_lld_adc_nontimerI(GadcLldNonTimerData *pgntd) { + /** + * We don't need to calculate num_channels because the AT91SAM7 ADC does this for us. + */ + acg.channelselects = pgntd->physdev; + acg.trigger = ADC_TRIGGER_SOFTWARE; + adcStartConversionI(&ADCD1, &acg, pgntd->buffer, 1); +} + +#endif /* GFX_USE_GADC */ +/** @} */ diff --git a/drivers/gadc/AT91SAM7/gadc_lld.mk b/drivers/gadc/AT91SAM7/gadc_lld.mk new file mode 100644 index 00000000..001d44b1 --- /dev/null +++ b/drivers/gadc/AT91SAM7/gadc_lld.mk @@ -0,0 +1,5 @@ +# List the required driver. +GFXSRC += $(GFXLIB)/drivers/gadc/AT91SAM7/gadc_lld.c + +# Required include directories +GFXINC += $(GFXLIB)/drivers/gadc/AT91SAM7 diff --git a/drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h b/drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h new file mode 100644 index 00000000..6f23db17 --- /dev/null +++ b/drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h @@ -0,0 +1,46 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h + * @brief GADC Driver config file. + * + * @addtogroup GADC + * @{ + */ + +#ifndef _GADC_LLD_BOARD_OLIMEXSAM7EX256_H +#define _GADC_LLD_BOARD_OLIMEXSAM7EX256_H + +#if GFX_USE_GADC + +/*===========================================================================*/ +/* Analogue devices on this board */ +/*===========================================================================*/ + +#define GADC_PHYSDEV_MICROPHONE 0x00000080 +#define GADC_PHYSDEV_DIAL 0x00000040 +#define GADC_PHYSDEV_TEMPERATURE 0x00000020 + +#endif /* GFX_USE_GADC */ + +#endif /* _GADC_LLD_BOARD_OLIMEXSAM7EX256_H */ +/** @} */ + diff --git a/drivers/gadc/AT91SAM7/gadc_lld_config.h b/drivers/gadc/AT91SAM7/gadc_lld_config.h new file mode 100644 index 00000000..882573c8 --- /dev/null +++ b/drivers/gadc/AT91SAM7/gadc_lld_config.h @@ -0,0 +1,78 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gadc/AT91SAM7/gadc_lld_config.h + * @brief GADC Driver config file. + * + * @addtogroup GADC + * @{ + */ + +#ifndef GADC_LLD_CONFIG_H +#define GADC_LLD_CONFIG_H + +#if GFX_USE_GADC + +/*===========================================================================*/ +/* Driver hardware support. */ +/*===========================================================================*/ + +/** + * @brief ChibiOS has a nasty bug in its _adc_isr_full_code() routine (defined in adc.h as a macro). + * Do we have the version of ChibiOS with this bug. + * @detail Set to TRUE if ChibiOS has this bug. + * @note Fixed in ChibiOS 2.4.4stable and 2.5.2unstable (and the repository from 18th Feb 2013) + * @note This bug prevents us re-calling adcStartConversionI() from with the ISR even though + * it is clearly designed to handle it. For some reason (on this micro) the high speed timer + * is not affected only the single sample low speed timer. In that situation we wait until + * we get back to thread land. This is terrible for the accuracy of the high speed timer + * but what can we do (other than fix the bug). + * @note For the AT91SAM7 ADC driver, it post-dates the finding of the bug so we safely + * say that the bug doesn't exist for this driver. + */ +#define ADC_ISR_FULL_CODE_BUG FALSE + +/** + * @brief The maximum sample frequency supported by this CPU + */ +#define GADC_MAX_SAMPLE_FREQUENCY 132000 + +/** + * @brief The number of bits in a sample + */ +#define GADC_BITS_PER_SAMPLE AT91_ADC1_RESOLUTION + +/* 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 + +#endif /* GFX_USE_GADC */ + +#endif /* _GDISP_LLD_CONFIG_H */ +/** @} */ + diff --git a/drivers/gdisp/ILI9320/gdisp_lld.c b/drivers/gdisp/ILI9320/gdisp_lld.c index 6a324cd4..d8c5be86 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld.c +++ b/drivers/gdisp/ILI9320/gdisp_lld.c @@ -1,570 +1,570 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/ILI9320/gdisp_lld.c
- * @brief GDISP Graphics Driver subsystem low level driver source for the ILI9320 display.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.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"
-
-#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#elif defined(BOARD_OLIMEX_STM32_LCD)
- #include "gdisp_lld_board_olimex_stm32_lcd.h"
-#else
- #include "gdisp_lld_board.h"
-#endif
-
-/*===========================================================================*/
-/* 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."
- #undef GDISP_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_SCREEN_WIDTH 240
-#define GDISP_SCREEN_HEIGHT 320
-
-#define GDISP_INITIAL_CONTRAST 50
-#define GDISP_INITIAL_BACKLIGHT 100
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables. */
-/*===========================================================================*/
-uint32_t DISPLAY_CODE;
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-static __inline void lld_lcdDelay(uint16_t us) {
- chThdSleepMicroseconds(us);
-}
-
-static __inline void lld_lcdWriteIndex(uint16_t index) {
- lld_gdisp_write_index(index);
-}
-
-static __inline void lld_lcdWriteData(uint16_t data) {
- lld_gdisp_write_data(data);
-}
-
-static __inline void lld_lcdWriteReg(uint16_t lcdReg, uint16_t lcdRegValue) {
- lld_gdisp_write_index(lcdReg);
- lld_gdisp_write_data(lcdRegValue);
-}
-
-static __inline uint16_t lld_lcdReadData(void) {
- /* fix this! */
- //return lld_gdisp_read_data;
- return GDISP_RAM;
-}
-
-static __inline uint16_t lld_lcdReadReg(uint16_t lcdReg) {
- volatile uint16_t dummy;
-
- lld_gdisp_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 lld_gdisp_init(void) {
- /* Initialise your display */
- lld_gdisp_init_board();
-
- /* Hardware reset */
- lld_gdisp_reset_pin(TRUE);
- lld_lcdDelay(1000);
- lld_gdisp_reset_pin(FALSE);
- lld_lcdDelay(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
- switch (DISPLAY_CODE) {
- case 0x9320:
- lld_lcdWriteReg(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
- 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
-
- // Turn on the backlight
- lld_gdisp_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
-
- return TRUE;
-}
-
-static void lld_lcdSetCursor(uint16_t x, uint16_t y) {
- uint32_t addr;
-
- addr = y * 0x100 + x;
-
- switch(GDISP.Orientation) {
- case GDISP_ROTATE_0:
- lld_lcdWriteReg(0x0020, addr & 0xff); /* low addr */
- lld_lcdWriteReg(0x0021, (addr >> 8) & 0x1ff); /* high addr */
- break;
-
- case GDISP_ROTATE_90:
- lld_lcdWriteReg(0x0020, (addr >> 8) & 0x1ff); /* low addr */
- lld_lcdWriteReg(0x0021, addr & 0xff); /* high addr */
- break;
-
- case GDISP_ROTATE_180:
- break;
-
- case GDISP_ROTATE_270:
- break;
- }
-}
-
-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:
- break;
-
- case GDISP_ROTATE_270:
- break;
-
- }
-
- 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 lld_gdisp_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 lld_gdisp_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();
- }
-#endif
-
-#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__)
- void lld_gdisp_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();
- }
-#endif
-
-#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__)
- void lld_gdisp_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 lld_gdisp_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 lld_gdisp_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 lld_gdisp_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:
- lld_lcdWriteReg(0x0007, 0x0000);
- lld_lcdWriteReg(0x0010, 0x0000);
- lld_lcdWriteReg(0x0011, 0x0000);
- lld_lcdWriteReg(0x0012, 0x0000);
- lld_lcdWriteReg(0x0013, 0x0000);
- lld_gdisp_backlight(0);
- break;
-
- case powerOn:
- //*************Power On sequence ******************//
- 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 */
- lld_gdisp_backlight(GDISP.Backlight);
- if(GDISP.Powermode != powerSleep || GDISP.Powermode != powerDeepSleep)
- lld_gdisp_init();
- break;
-
- case powerSleep:
- 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 */
- lld_gdisp_backlight(0);
- break;
-
- case powerDeepSleep:
- 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 */
- lld_gdisp_backlight(0);
- break;
-
- default:
- return;
- }
- GDISP.Powermode = (gdisp_powermode_t)value;
- return;
-
- case GDISP_CONTROL_ORIENTATION:
- if(GDISP.Orientation == (gdisp_orientation_t)value)
- return;
- switch((gdisp_orientation_t)value) {
- case GDISP_ROTATE_0:
- lld_lcdWriteReg(0x0001, 0x0100);
- lld_lcdWriteReg(0x0003, 0x1038);
- GDISP.Height = GDISP_SCREEN_HEIGHT;
- GDISP.Width = GDISP_SCREEN_WIDTH;
- break;
-
- case GDISP_ROTATE_90:
- lld_lcdWriteReg(0x0001, 0x0000);
- lld_lcdWriteReg(0x0003, 0x1030);
- GDISP.Height = GDISP_SCREEN_WIDTH;
- GDISP.Width = GDISP_SCREEN_HEIGHT;
- break;
-
- case GDISP_ROTATE_180:
- /* ToDo */
- GDISP.Height = GDISP_SCREEN_HEIGHT;
- GDISP.Width = GDISP_SCREEN_WIDTH;
- break;
-
- case GDISP_ROTATE_270:
- /* ToDo */
- 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;
- lld_gdisp_backlight((unsigned)value);
- GDISP.Backlight = (unsigned)value;
- break;
-
- default:
- return;
- }
- }
-
-#endif
-
-#endif /* GFX_USE_GDISP */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/ILI9320/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the ILI9320 display. + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.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" + +#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#elif defined(BOARD_OLIMEX_STM32_LCD) + #include "gdisp_lld_board_olimex_stm32_lcd.h" +#else + #include "gdisp_lld_board.h" +#endif + +/*===========================================================================*/ +/* 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." + #undef GDISP_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_SCREEN_WIDTH 240 +#define GDISP_SCREEN_HEIGHT 320 + +#define GDISP_INITIAL_CONTRAST 50 +#define GDISP_INITIAL_BACKLIGHT 100 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ +uint32_t DISPLAY_CODE; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +static __inline void lld_lcdDelay(uint16_t us) { + chThdSleepMicroseconds(us); +} + +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) { + /* fix this! */ + //return gdisp_lld_read_data; + return GDISP_RAM; +} + +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) { + /* Initialise your display */ + gdisp_lld_init_board(); + + /* Hardware reset */ + gdisp_lld_reset_pin(TRUE); + lld_lcdDelay(1000); + gdisp_lld_reset_pin(FALSE); + lld_lcdDelay(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 + switch (DISPLAY_CODE) { + case 0x9320: + lld_lcdWriteReg(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 + 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 + + // Turn on the backlight + gdisp_lld_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 + + return TRUE; +} + +static void lld_lcdSetCursor(uint16_t x, uint16_t y) { + uint32_t addr; + + addr = y * 0x100 + x; + + switch(GDISP.Orientation) { + case GDISP_ROTATE_0: + lld_lcdWriteReg(0x0020, addr & 0xff); /* low addr */ + lld_lcdWriteReg(0x0021, (addr >> 8) & 0x1ff); /* high addr */ + break; + + case GDISP_ROTATE_90: + lld_lcdWriteReg(0x0020, (addr >> 8) & 0x1ff); /* low addr */ + lld_lcdWriteReg(0x0021, addr & 0xff); /* high addr */ + break; + + case GDISP_ROTATE_180: + break; + + case GDISP_ROTATE_270: + break; + } +} + +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: + break; + + case GDISP_ROTATE_270: + break; + + } + + 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(); + } +#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(); + } +#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: + lld_lcdWriteReg(0x0007, 0x0000); + lld_lcdWriteReg(0x0010, 0x0000); + lld_lcdWriteReg(0x0011, 0x0000); + lld_lcdWriteReg(0x0012, 0x0000); + lld_lcdWriteReg(0x0013, 0x0000); + gdisp_lld_backlight(0); + break; + + case powerOn: + //*************Power On sequence ******************// + 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 */ + gdisp_lld_backlight(GDISP.Backlight); + if(GDISP.Powermode != powerSleep || GDISP.Powermode != powerDeepSleep) + gdisp_lld_init(); + break; + + case powerSleep: + 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 */ + gdisp_lld_backlight(0); + break; + + case powerDeepSleep: + 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 */ + gdisp_lld_backlight(0); + break; + + default: + return; + } + GDISP.Powermode = (gdisp_powermode_t)value; + return; + + case GDISP_CONTROL_ORIENTATION: + if(GDISP.Orientation == (gdisp_orientation_t)value) + return; + switch((gdisp_orientation_t)value) { + case GDISP_ROTATE_0: + lld_lcdWriteReg(0x0001, 0x0100); + lld_lcdWriteReg(0x0003, 0x1038); + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_90: + lld_lcdWriteReg(0x0001, 0x0000); + lld_lcdWriteReg(0x0003, 0x1030); + GDISP.Height = GDISP_SCREEN_WIDTH; + GDISP.Width = GDISP_SCREEN_HEIGHT; + break; + + case GDISP_ROTATE_180: + /* ToDo */ + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_270: + /* ToDo */ + 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; + break; + + default: + return; + } + } + +#endif + +#endif /* GFX_USE_GDISP */ +/** @} */ + diff --git a/drivers/gdisp/ILI9320/gdisp_lld_board_example.h b/drivers/gdisp/ILI9320/gdisp_lld_board_example.h index f07b34c6..0f4def57 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_board_example.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_board_example.h @@ -1,59 +1,59 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/ILI9320/gdisp_lld_board_example.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 lld_gdisp_init_board(void) {
- #error "ILI9320: You must implement the init_board routine for your board"
-}
-
-static __inline void lld_gdisp_reset_pin(bool_t state) {
- #error "ILI9320: You must implement setpin_reset routine for your board"
-}
-
-static __inline void lld_gdisp_write_index(uint16_t data) {
- #error "ILI9320: You must implement write_index routine for your board"
-}
-
-static __inline void lld_gdisp_write_data(uint16_t data) {
- #error "ILI9320: You must implement write_data routine for your board"
-}
-
-static __inline uint16_t lld_gdisp_read_data(void) {
- #error "ILI9320: You must implement read_data routine for your board"
-}
-
-/* if not available, just ignore the argument and return */
-static __inline uint16_t lld_gdisp_backlight(uint8_t percentage) {
- #error "ILI9320: You must implement set_backlight routine for your board"
-}
-
-#endif /* GDISP_LLD_BOARD_H */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/ILI9320/gdisp_lld_board_example.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 gdisp_lld_init_board(void) { + #error "ILI9320: You must implement the init_board routine for your board" +} + +static __inline void gdisp_lld_reset_pin(bool_t state) { + #error "ILI9320: You must implement setpin_reset routine for your board" +} + +static __inline void gdisp_lld_write_index(uint16_t data) { + #error "ILI9320: You must implement write_index routine for your board" +} + +static __inline void gdisp_lld_write_data(uint16_t data) { + #error "ILI9320: You must implement write_data routine for your board" +} + +static __inline uint16_t gdisp_lld_read_data(void) { + #error "ILI9320: You must implement read_data routine for your board" +} + +/* if not available, just ignore the argument and return */ +static __inline uint16_t gdisp_lld_backlight(uint8_t percentage) { + #error "ILI9320: You must implement set_backlight routine for your board" +} + +#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 d2d54ce9..2bdf367a 100644 --- a/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h +++ b/drivers/gdisp/ILI9320/gdisp_lld_board_olimex_stm32_lcd.h @@ -1,85 +1,85 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @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 lld_gdisp_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 lld_gdisp_reset_pin(bool_t state) {
- if(state)
- palClearPad(GPIOE, GPIOE_TFT_RST);
- else
- palSetPad(GPIOE, GPIOE_TFT_RST);
-}
-
-static __inline void lld_gdisp_write_index(uint16_t reg) {
- GDISP_REG = reg;
-}
-
-static __inline void lld_gdisp_write_data(uint16_t data) {
- GDISP_RAM = data;
-}
-
-static __inline uint16_t lld_gdisp_read_data(void) {
- return GDISP_RAM;
-}
-
-static __inline void lld_gdisp_backlight(uint8_t percent) {
- if(percent == 100)
- palClearPad(GPIOD, GPIOD_TFT_LIGHT);
- else
- palSetPad(GPIOD, GPIOD_TFT_LIGHT);
-}
-
-#endif /* GDISP_LLD_BOARD_H */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @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 gdisp_lld_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 gdisp_lld_reset_pin(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) { + GDISP_REG = reg; +} + +static __inline void gdisp_lld_write_data(uint16_t data) { + GDISP_RAM = data; +} + +static __inline uint16_t gdisp_lld_read_data(void) { + return GDISP_RAM; +} + +static __inline void gdisp_lld_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/ILI9325/gdisp_lld.c b/drivers/gdisp/ILI9325/gdisp_lld.c index e9500cc5..187c54c6 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld.c +++ b/drivers/gdisp/ILI9325/gdisp_lld.c @@ -1,580 +1,580 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/ILI9325/gdisp_lld.c
- * @brief GDISP Graphics Driver subsystem low level driver source for the ILI9325 display.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.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"
-
-#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#elif defined(BOARD_HY_STM32_100P)
- #include "gdisp_lld_board_hy_stm32_100p.h"
-#else
- #include "gdisp_lld_board.h"
-#endif
-
-/*===========================================================================*/
-/* 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."
- #undef GDISP_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_SCREEN_WIDTH 240
-#define GDISP_SCREEN_HEIGHT 320
-
-#define GDISP_INITIAL_CONTRAST 50
-#define GDISP_INITIAL_BACKLIGHT 100
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables. */
-/*===========================================================================*/
-uint32_t DISPLAY_CODE;
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-static __inline void lld_lcdDelay(uint16_t us) {
- chThdSleepMicroseconds(us);
-}
-
-static __inline void lld_lcdWriteIndex(uint16_t index) {
- lld_gdisp_write_index(index);
-}
-
-static __inline void lld_lcdWriteData(uint16_t data) {
- lld_gdisp_write_data(data);
-}
-
-static __inline void lld_lcdWriteReg(uint16_t lcdReg, uint16_t lcdRegValue) {
- lld_gdisp_write_index(lcdReg);
- lld_gdisp_write_data(lcdRegValue);
-}
-
-static __inline uint16_t lld_lcdReadData(void) {
- /* fix this! */
- //return lld_gdisp_read_data;
- return GDISP_RAM;
-}
-
-static __inline uint16_t lld_lcdReadReg(uint16_t lcdReg) {
- volatile uint16_t dummy;
-
- lld_gdisp_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 lld_gdisp_init(void) {
- /* Initialise your display */
- lld_gdisp_init_board();
-
- /* Hardware reset */
- lld_gdisp_reset_pin(TRUE);
- lld_lcdDelay(1000);
- lld_gdisp_reset_pin(FALSE);
- lld_lcdDelay(1000);
-
- // chinese code starts here
- lld_lcdWriteReg(0x0000,0x0001);
- lld_lcdDelay(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);
-
- 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);
-
- 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);
-
- //################# 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);
-
- //################## 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);
-
- // chinese code ends here
-
- // Turn on the backlight
- lld_gdisp_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
-
- 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;
- }
-}
-
-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;
-
- }
-
- 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 lld_gdisp_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 lld_gdisp_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();
- }
-#endif
-
-#if GDISP_HARDWARE_FILLS || defined(__DOXYGEN__)
- void lld_gdisp_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();
- }
-#endif
-
-#if GDISP_HARDWARE_BITFILLS || defined(__DOXYGEN__)
- void lld_gdisp_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 lld_gdisp_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 lld_gdisp_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 lld_gdisp_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:
- lld_lcdWriteReg(0x0007, 0x0000);
- lld_lcdWriteReg(0x0010, 0x0000);
- lld_lcdWriteReg(0x0011, 0x0000);
- lld_lcdWriteReg(0x0012, 0x0000);
- lld_lcdWriteReg(0x0013, 0x0000);
- lld_gdisp_backlight(0);
- break;
-
- case powerOn:
- //*************Power On sequence ******************//
- 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 */
- lld_gdisp_backlight(GDISP.Backlight);
- if(GDISP.Powermode != powerSleep || GDISP.Powermode != powerDeepSleep)
- lld_gdisp_init();
- break;
-
- case powerSleep:
- 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 */
- lld_gdisp_backlight(0);
- break;
-
- case powerDeepSleep:
- 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 */
- lld_gdisp_backlight(0);
- break;
-
- default:
- return;
- }
- GDISP.Powermode = (gdisp_powermode_t)value;
- return;
-
- case GDISP_CONTROL_ORIENTATION:
- if(GDISP.Orientation == (gdisp_orientation_t)value)
- return;
- switch((gdisp_orientation_t)value) {
- case GDISP_ROTATE_0:
- lld_lcdWriteReg(0x0001, 0x0100);
- lld_lcdWriteReg(0x0003, 0x1038);
- lld_lcdWriteReg(0x0060, 0x2700);
- GDISP.Height = GDISP_SCREEN_HEIGHT;
- GDISP.Width = GDISP_SCREEN_WIDTH;
- break;
-
- case GDISP_ROTATE_90:
- lld_lcdWriteReg(0x0001, 0x0000);
- lld_lcdWriteReg(0x0003, 0x1030);
- lld_lcdWriteReg(0x0060, 0x2700);
- GDISP.Height = GDISP_SCREEN_WIDTH;
- GDISP.Width = GDISP_SCREEN_HEIGHT;
- break;
-
- case GDISP_ROTATE_180:
- lld_lcdWriteReg(0x0001, 0x0000);
- lld_lcdWriteReg(0x0003, 0x1038);
- lld_lcdWriteReg(0x0060, 0xa700);
- GDISP.Height = GDISP_SCREEN_HEIGHT;
- GDISP.Width = GDISP_SCREEN_WIDTH;
- break;
-
- case GDISP_ROTATE_270:
- lld_lcdWriteReg(0x0001, 0x0100);
- lld_lcdWriteReg(0x0003, 0x1030);
- lld_lcdWriteReg(0x0060, 0xA700);
- 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;
- lld_gdisp_backlight((unsigned)value);
- GDISP.Backlight = (unsigned)value;
- break;
-
- default:
- return;
- }
- }
-
-#endif
-
-#endif /* GFX_USE_GDISP */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/ILI9325/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the ILI9325 display. + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.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" + +#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#elif defined(BOARD_HY_STM32_100P) + #include "gdisp_lld_board_hy_stm32_100p.h" +#else + #include "gdisp_lld_board.h" +#endif + +/*===========================================================================*/ +/* 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." + #undef GDISP_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_SCREEN_WIDTH 240 +#define GDISP_SCREEN_HEIGHT 320 + +#define GDISP_INITIAL_CONTRAST 50 +#define GDISP_INITIAL_BACKLIGHT 100 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ +uint32_t DISPLAY_CODE; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +static __inline void lld_lcdDelay(uint16_t us) { + chThdSleepMicroseconds(us); +} + +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) { + /* fix this! */ + //return gdisp_lld_read_data; + return GDISP_RAM; +} + +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) { + /* Initialise your display */ + gdisp_lld_init_board(); + + /* Hardware reset */ + gdisp_lld_reset_pin(TRUE); + lld_lcdDelay(1000); + gdisp_lld_reset_pin(FALSE); + lld_lcdDelay(1000); + + // chinese code starts here + lld_lcdWriteReg(0x0000,0x0001); + lld_lcdDelay(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); + + 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); + + 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); + + //################# 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); + + //################## 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); + + // chinese code ends here + + // Turn on the backlight + gdisp_lld_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 + + 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; + } +} + +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; + + } + + 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(); + } +#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(); + } +#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: + lld_lcdWriteReg(0x0007, 0x0000); + lld_lcdWriteReg(0x0010, 0x0000); + lld_lcdWriteReg(0x0011, 0x0000); + lld_lcdWriteReg(0x0012, 0x0000); + lld_lcdWriteReg(0x0013, 0x0000); + gdisp_lld_backlight(0); + break; + + case powerOn: + //*************Power On sequence ******************// + 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 */ + gdisp_lld_backlight(GDISP.Backlight); + if(GDISP.Powermode != powerSleep || GDISP.Powermode != powerDeepSleep) + gdisp_lld_init(); + break; + + case powerSleep: + 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 */ + gdisp_lld_backlight(0); + break; + + case powerDeepSleep: + 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 */ + gdisp_lld_backlight(0); + break; + + default: + return; + } + GDISP.Powermode = (gdisp_powermode_t)value; + return; + + case GDISP_CONTROL_ORIENTATION: + if(GDISP.Orientation == (gdisp_orientation_t)value) + return; + switch((gdisp_orientation_t)value) { + case GDISP_ROTATE_0: + lld_lcdWriteReg(0x0001, 0x0100); + lld_lcdWriteReg(0x0003, 0x1038); + lld_lcdWriteReg(0x0060, 0x2700); + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_90: + lld_lcdWriteReg(0x0001, 0x0000); + lld_lcdWriteReg(0x0003, 0x1030); + lld_lcdWriteReg(0x0060, 0x2700); + GDISP.Height = GDISP_SCREEN_WIDTH; + GDISP.Width = GDISP_SCREEN_HEIGHT; + break; + + case GDISP_ROTATE_180: + lld_lcdWriteReg(0x0001, 0x0000); + lld_lcdWriteReg(0x0003, 0x1038); + lld_lcdWriteReg(0x0060, 0xa700); + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Width = GDISP_SCREEN_WIDTH; + break; + + case GDISP_ROTATE_270: + lld_lcdWriteReg(0x0001, 0x0100); + lld_lcdWriteReg(0x0003, 0x1030); + lld_lcdWriteReg(0x0060, 0xA700); + 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; + break; + + default: + return; + } + } + +#endif + +#endif /* GFX_USE_GDISP */ +/** @} */ + diff --git a/drivers/gdisp/ILI9325/gdisp_lld_board_example.h b/drivers/gdisp/ILI9325/gdisp_lld_board_example.h index 547952ee..80adf6ab 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld_board_example.h +++ b/drivers/gdisp/ILI9325/gdisp_lld_board_example.h @@ -1,59 +1,59 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/ILI9325/gdisp_lld_board_example.h
- * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#ifndef GDISP_LLD_BOARD_H
-#define GDISP_LLD_BOARD_H
-
-static __inline void lld_gdisp_init_board(void) {
- #error "ILI9325: You must implement the init_board routine for your board"
-}
-
-static __inline void lld_gdisp_reset_pin(bool_t state) {
- #error "ILI9325: You must implement setpin_reset routine for your board"
-}
-
-static __inline void lld_gdisp_write_index(uint16_t data) {
- #error "ILI9325: You must implement write_index routine for your board"
-}
-
-static __inline void lld_gdisp_write_data(uint16_t data) {
- #error "ILI9325: You must implement write_data routine for your board"
-}
-
-static __inline uint16_t lld_gdisp_read_data(void) {
- #error "ILI9325: You must implement read_data routine for your board"
-}
-
-/* if not available, just ignore the argument and return */
-static __inline uint16_t lld_gdisp_backlight(uint8_t percentage) {
- #error "ILI9325: You must implement set_backlight routine for your board"
-}
-
-#endif /* GDISP_LLD_BOARD_H */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/ILI9325/gdisp_lld_board_example.h + * @brief GDISP Graphic Driver subsystem board interface for the ILI9325 display. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef GDISP_LLD_BOARD_H +#define GDISP_LLD_BOARD_H + +static __inline void gdisp_lld_init_board(void) { + #error "ILI9325: You must implement the init_board routine for your board" +} + +static __inline void gdisp_lld_reset_pin(bool_t state) { + #error "ILI9325: You must implement setpin_reset routine for your board" +} + +static __inline void gdisp_lld_write_index(uint16_t data) { + #error "ILI9325: You must implement write_index routine for your board" +} + +static __inline void gdisp_lld_write_data(uint16_t data) { + #error "ILI9325: You must implement write_data routine for your board" +} + +static __inline uint16_t gdisp_lld_read_data(void) { + #error "ILI9325: You must implement read_data routine for your board" +} + +/* if not available, just ignore the argument and return */ +static __inline uint16_t gdisp_lld_backlight(uint8_t percentage) { + #error "ILI9325: You must implement set_backlight routine for your board" +} + +#endif /* GDISP_LLD_BOARD_H */ +/** @} */ + 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 94d418b0..a9e61dcb 100644 --- a/drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h +++ b/drivers/gdisp/ILI9325/gdisp_lld_board_hy_stm32_100p.h @@ -1,96 +1,96 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/*
- 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 lld_gdisp_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 lld_gdisp_reset_pin(bool_t state) {
- if(state)
- palClearPad(GPIOE, GPIOE_TFT_RST);
- else
- palSetPad(GPIOE, GPIOE_TFT_RST);
-}
-
-static __inline void lld_gdisp_write_index(uint16_t reg) {
- GDISP_REG = reg;
-}
-
-static __inline void lld_gdisp_write_data(uint16_t data) {
- GDISP_RAM = data;
-}
-
-static __inline uint16_t lld_gdisp_read_data(void) {
- return GDISP_RAM;
-}
-
-static __inline void lld_gdisp_backlight(uint8_t percent) {
- percent=percent; // avoid a warning
-}
-
-#endif /* GDISP_LLD_BOARD_H */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/* + 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 gdisp_lld_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 gdisp_lld_reset_pin(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) { + GDISP_REG = reg; +} + +static __inline void gdisp_lld_write_data(uint16_t data) { + GDISP_RAM = data; +} + +static __inline uint16_t gdisp_lld_read_data(void) { + return GDISP_RAM; +} + +static __inline void gdisp_lld_backlight(uint8_t percent) { + percent=percent; // avoid a warning +} + +#endif /* GDISP_LLD_BOARD_H */ +/** @} */ + diff --git a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c index 6ce7b581..ee9a5fc7 100644 --- a/drivers/gdisp/Nokia6610GE12/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE12/gdisp_lld.c @@ -1,528 +1,528 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/Nokia6610GE12/gdisp_lld.c
- * @brief GDISP Graphics Driver subsystem low level driver source for the Nokia6610 GE12 display.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.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"
-
-/*===========================================================================*/
-/* 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
-#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_SCREEN_HEIGHT 132
-#define GDISP_SCREEN_WIDTH 132
-
-#define GDISP_INITIAL_CONTRAST 38
-#define GDISP_INITIAL_BACKLIGHT 100
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#elif defined(BOARD_OLIMEX_SAM7_EX256)
- #include "gdisp_lld_board_olimexsam7ex256.h"
-#else
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#endif
-
-// Some macros just to make reading the code easier
-#define delayms(ms) chThdSleepMilliseconds(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); }
-
-// 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 lld_gdisp_init(void) {
- /* Initialise your display */
- init_board();
-
- // Hardware reset
- setpin_reset(TRUE);
- delayms(20);
- 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
- 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
- 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 lld_gdisp_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 lld_gdisp_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.
-
- acquire_bus();
- setviewport(x, y, cx, cy);
- write_cmd(RAMWR);
- for(i=0; i < tuples; i++)
- write_data3(((color >> 4) & 0xFF), (((color << 4) & 0xF0)|((color >> 8) & 0x0F)), (color & 0xFF));
- 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 lld_gdisp_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 lld_gdisp_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 lld_gdisp_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 lld_gdisp_control(unsigned what, void *value) {
- /* 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_CONTRAST - supported
- */
- switch(what) {
-#if 0
- // NOT IMPLEMENTED YET
- case GDISP_CONTROL_POWER:
- if (GDISP.Powermode == (gdisp_powermode_t)value)
- return;
- switch((gdisp_powermode_t)value) {
- case powerOff:
- // Code here
- break;
- case powerOn:
- // Code here
- /* You may need this ---
- * if (GDISP.Powermode != powerSleep)
- * lld_gdisp_init();
- */
- break;
- case powerSleep:
- /* Code here */
- break;
- default:
- return;
- }
- GDISP.Powermode = (gdisp_powermode_t)value;
- return;
-#endif
-#if 0
- // NOT IMPLEMENTED YET
- case GDISP_CONTROL_ORIENTATION:
- if (GDISP.Orientation == (gdisp_orientation_t)value)
- 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;
- return;
-#endif
- case GDISP_CONTROL_BACKLIGHT:
- if ((unsigned)value > 100) value = (void *)100;
- set_backlight((unsigned)value);
- GDISP.Backlight = (unsigned)value;
- return;
- case GDISP_CONTROL_CONTRAST:
- if ((unsigned)value > 100) value = (void *)100;
- acquire_bus();
- write_cmd1(CONTRAST,(unsigned)value);
- release_bus();
- GDISP.Contrast = (unsigned)value;
- return;
- }
- }
-#endif
-
-#endif /* GFX_USE_GDISP */
-/** @} */
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/Nokia6610GE12/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the Nokia6610 GE12 display. + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.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" + +/*===========================================================================*/ +/* 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 +#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_SCREEN_HEIGHT 132 +#define GDISP_SCREEN_WIDTH 132 + +#define GDISP_INITIAL_CONTRAST 38 +#define GDISP_INITIAL_BACKLIGHT 100 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#elif defined(BOARD_OLIMEX_SAM7_EX256) + #include "gdisp_lld_board_olimexsam7ex256.h" +#else + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#endif + +// Some macros just to make reading the code easier +#define delayms(ms) chThdSleepMilliseconds(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); } + +// 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) { + /* Initialise your display */ + init_board(); + + // Hardware reset + setpin_reset(TRUE); + delayms(20); + 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 + 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 + 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. + + acquire_bus(); + setviewport(x, y, cx, cy); + write_cmd(RAMWR); + for(i=0; i < tuples; i++) + write_data3(((color >> 4) & 0xFF), (((color << 4) & 0xF0)|((color >> 8) & 0x0F)), (color & 0xFF)); + 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) { + /* 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_CONTRAST - supported + */ + switch(what) { +#if 0 + // NOT IMPLEMENTED YET + case GDISP_CONTROL_POWER: + if (GDISP.Powermode == (gdisp_powermode_t)value) + 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; + return; +#endif +#if 0 + // NOT IMPLEMENTED YET + case GDISP_CONTROL_ORIENTATION: + if (GDISP.Orientation == (gdisp_orientation_t)value) + 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; + return; +#endif + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)value > 100) value = (void *)100; + set_backlight((unsigned)value); + GDISP.Backlight = (unsigned)value; + return; + case GDISP_CONTROL_CONTRAST: + if ((unsigned)value > 100) value = (void *)100; + acquire_bus(); + write_cmd1(CONTRAST,(unsigned)value); + release_bus(); + GDISP.Contrast = (unsigned)value; + return; + } + } +#endif + +#endif /* GFX_USE_GDISP */ +/** @} */ diff --git a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c index 006c964b..079900aa 100644 --- a/drivers/gdisp/Nokia6610GE8/gdisp_lld.c +++ b/drivers/gdisp/Nokia6610GE8/gdisp_lld.c @@ -1,483 +1,483 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/Nokia6610GE8/gdisp_lld.c
- * @brief GDISP Graphics Driver subsystem low level driver source for the Nokia6610 GE8 display.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.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"
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#include "GE8.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
-#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_SCREEN_HEIGHT 132
-#define GDISP_SCREEN_WIDTH 132
-
-#define GDISP_INITIAL_CONTRAST 38
-#define GDISP_INITIAL_BACKLIGHT 100
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#elif defined(BOARD_OLIMEX_SAM7_EX256)
- #include "gdisp_lld_board_olimexsam7ex256.h"
-#else
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#endif
-
-// Some macros just to make reading the code easier
-#define delayms(ms) chThdSleepMilliseconds(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); }
-
-// 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 lld_gdisp_init(void) {
- /* Initialise your display */
- init_board();
-
- // Hardware reset
- setpin_reset(TRUE);
- delayms(20);
- setpin_reset(FALSE);
- delayms(20);
-
- // Get the bus for the following initialisation commands
- acquire_bus();
-
- write_cmd3(DISCTL, 0x00, 0x20, 0x00); // Display control
- // P1: 0x00 = 2 divisions, switching period=8 (default)
- // P2: 0x20 = nlines/4 - 1 = 132/4 - 1 = 32)
- // P3: 0x00 = no inversely highlighted lines
- write_cmd1(COMSCN, 0x01); // COM scan P1: 0x01 = Scan 1->80, 160<-81
- write_cmd(OSCON); // Internal oscilator 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, 0x48, 0x00, 0x02); // Data control
- // P1: 0x01 = page address inverted, column address normal, address scan in column direction
- // P2: 0x00 = RGB sequence (default value)
- // P3: 0x02 = Grayscale -> 16 (selects 12-bit color, type A)
- write_cmd2(VOLCTR, GDISP_INITIAL_CONTRAST, 0x03); // Voltage control (contrast setting)
- // P1 = Contrast
- // P2 = 3 resistance ratio (only value that works)
- delayms(100); // allow power supply to stabilize
- write_cmd(DISON); // Turn on the display
-
- // Release the bus
- 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
- 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 lld_gdisp_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 lld_gdisp_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.
-
- acquire_bus();
- setviewport(x, y, cx, cy);
- write_cmd(RAMWR);
- for(i=0; i < tuples; i++)
- write_data3(((color >> 4) & 0xFF), (((color << 4) & 0xF0)|((color >> 8) & 0x0F)), (color & 0xFF));
- 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 lld_gdisp_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 lld_gdisp_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 lld_gdisp_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 lld_gdisp_control(unsigned what, void *value) {
- /* 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_CONTRAST - supported
- */
- switch(what) {
-#if 0
- // NOT IMPLEMENTED YET
- case GDISP_CONTROL_POWER:
- if (GDISP.Powermode == (gdisp_powermode_t)value)
- return;
- switch((gdisp_powermode_t)value) {
- case powerOff:
- // Code here
- break;
- case powerOn:
- // Code here
- /* You may need this ---
- * if (GDISP.Powermode != powerSleep)
- * lld_gdisp_init();
- */
- break;
- case powerSleep:
- /* Code here */
- break;
- default:
- return;
- }
- GDISP.Powermode = (gdisp_powermode_t)value;
- return;
-#endif
-#if 0
- // NOT IMPLEMENTED YET
- case GDISP_CONTROL_ORIENTATION:
- if (GDISP.Orientation == (gdisp_orientation_t)value)
- 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;
- return;
-#endif
- case GDISP_CONTROL_BACKLIGHT:
- if ((unsigned)value > 100) value = (void *)100;
- set_backlight((unsigned)value);
- GDISP.Backlight = (unsigned)value;
- return;
- case GDISP_CONTROL_CONTRAST:
- if ((unsigned)value > 100) value = (void *)100;
- acquire_bus();
- write_cmd2(VOLCTR, (unsigned)value, 0x03);
- release_bus();
- GDISP.Contrast = (unsigned)value;
- return;
- }
- }
-#endif
-
-#endif /* GFX_USE_GDISP */
-/** @} */
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/Nokia6610GE8/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the Nokia6610 GE8 display. + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.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" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#include "GE8.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 +#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_SCREEN_HEIGHT 132 +#define GDISP_SCREEN_WIDTH 132 + +#define GDISP_INITIAL_CONTRAST 38 +#define GDISP_INITIAL_BACKLIGHT 100 + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#elif defined(BOARD_OLIMEX_SAM7_EX256) + #include "gdisp_lld_board_olimexsam7ex256.h" +#else + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#endif + +// Some macros just to make reading the code easier +#define delayms(ms) chThdSleepMilliseconds(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); } + +// 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) { + /* Initialise your display */ + init_board(); + + // Hardware reset + setpin_reset(TRUE); + delayms(20); + setpin_reset(FALSE); + delayms(20); + + // Get the bus for the following initialisation commands + acquire_bus(); + + write_cmd3(DISCTL, 0x00, 0x20, 0x00); // Display control + // P1: 0x00 = 2 divisions, switching period=8 (default) + // P2: 0x20 = nlines/4 - 1 = 132/4 - 1 = 32) + // P3: 0x00 = no inversely highlighted lines + write_cmd1(COMSCN, 0x01); // COM scan P1: 0x01 = Scan 1->80, 160<-81 + write_cmd(OSCON); // Internal oscilator 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, 0x48, 0x00, 0x02); // Data control + // P1: 0x01 = page address inverted, column address normal, address scan in column direction + // P2: 0x00 = RGB sequence (default value) + // P3: 0x02 = Grayscale -> 16 (selects 12-bit color, type A) + write_cmd2(VOLCTR, GDISP_INITIAL_CONTRAST, 0x03); // Voltage control (contrast setting) + // P1 = Contrast + // P2 = 3 resistance ratio (only value that works) + delayms(100); // allow power supply to stabilize + write_cmd(DISON); // Turn on the display + + // Release the bus + 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 + 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. + + acquire_bus(); + setviewport(x, y, cx, cy); + write_cmd(RAMWR); + for(i=0; i < tuples; i++) + write_data3(((color >> 4) & 0xFF), (((color << 4) & 0xF0)|((color >> 8) & 0x0F)), (color & 0xFF)); + 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) { + /* 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_CONTRAST - supported + */ + switch(what) { +#if 0 + // NOT IMPLEMENTED YET + case GDISP_CONTROL_POWER: + if (GDISP.Powermode == (gdisp_powermode_t)value) + 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; + return; +#endif +#if 0 + // NOT IMPLEMENTED YET + case GDISP_CONTROL_ORIENTATION: + if (GDISP.Orientation == (gdisp_orientation_t)value) + 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; + return; +#endif + case GDISP_CONTROL_BACKLIGHT: + if ((unsigned)value > 100) value = (void *)100; + set_backlight((unsigned)value); + GDISP.Backlight = (unsigned)value; + return; + case GDISP_CONTROL_CONTRAST: + if ((unsigned)value > 100) value = (void *)100; + acquire_bus(); + write_cmd2(VOLCTR, (unsigned)value, 0x03); + release_bus(); + GDISP.Contrast = (unsigned)value; + return; + } + } +#endif + +#endif /* GFX_USE_GDISP */ +/** @} */ diff --git a/drivers/gdisp/S6D1121/gdisp_lld.c b/drivers/gdisp/S6D1121/gdisp_lld.c index 863e5e46..c4523999 100644 --- a/drivers/gdisp/S6D1121/gdisp_lld.c +++ b/drivers/gdisp/S6D1121/gdisp_lld.c @@ -1,571 +1,571 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/S6D1121/gdisp_lld.c
- * @brief GDISP Graphics Driver subsystem low level driver source for the S6d1121 display.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.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"
-
-/*===========================================================================*/
-/* 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
-#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_SCREEN_HEIGHT 320
-#define GDISP_SCREEN_WIDTH 240
-
-#define GDISP_INITIAL_CONTRAST 50
-#define GDISP_INITIAL_BACKLIGHT 100
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#elif defined(BOARD_OLIMEX_STM32_E407)
- #include "gdisp_lld_board_olimex_e407.h"
-#else
- #include "gdisp_lld_board.h"
-#endif
-
-/* 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) chThdSleepMicroseconds(us)
-#define delayms(ms) chThdSleepMilliseconds(ms)
-
-static __inline void set_cursor(coord_t x, coord_t y) {
- /* R20h - 8 bit
- * R21h - 9 bit
- */
- switch(GDISP.Orientation) {
- case GDISP_ROTATE_0:
- write_reg(0x0020, x & 0x00FF);
- write_reg(0x0021, 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);
- break;
- case GDISP_ROTATE_180:
- write_reg(0x0020, (GDISP_SCREEN_WIDTH - 1 - x) & 0x00FF);
- write_reg(0x0021, (GDISP_SCREEN_HEIGHT - 1 - 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);
- break;
- }
-}
-
-static __inline void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) {
- /* HSA / HEA are 8 bit
- * VSA / VEA are 9 bit
- * use masks 0x00FF and 0x01FF to enforce this
- */
-
- switch(GDISP.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);
- 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);
- 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);
- 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);
- 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 lld_gdisp_init(void) {
- /* initialize the hardware */
- init_board();
-
- /* Hardware reset */
- setpin_reset(TRUE);
- delayms(20);
- setpin_reset(TRUE);
- delayms(20);
-
- /* Get the bus for the following initialisation commands */
- acquire_bus();
-
- write_reg(0x11,0x2004);
- write_reg(0x13,0xCC00);
- write_reg(0x15,0x2600);
- write_reg(0x14,0x252A);
- write_reg(0x12,0x0033);
- write_reg(0x13,0xCC04);
-
- delayms(1);
-
- write_reg(0x13,0xCC06);
-
- delayms(1);
-
- write_reg(0x13,0xCC4F);
-
- delayms(1);
-
- write_reg(0x13,0x674F);
- write_reg(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(0x16,0x0007);
- write_reg(0x02,0x0013);
- write_reg(0x03,0x0003);
- write_reg(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);
-
- delayms(1);
-
- write_reg(0x07,0x0053);
- write_reg(0x79,0x0000);
-
- reset_viewport();
- set_backlight(GDISP_INITIAL_BACKLIGHT);
-
- /* 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
- 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 lld_gdisp_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 lld_gdisp_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();
- }
-#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 lld_gdisp_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();
- }
-#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 lld_gdisp_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 lld_gdisp_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 lld_gdisp_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 lld_gdisp_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:
- /* Code here */
- /* break; */
- case powerOn:
- /* Code here */
- /* You may need this ---
- if (GDISP.Powermode != powerSleep)
- lld_gdisp_init();
- */
- /* break; */
- case powerSleep:
- /* Code here */
- /* break; */
- default:
- return;
- }
- GDISP.Powermode = (gdisp_powermode_t)value;
- return;
- case GDISP_CONTROL_ORIENTATION:
- if (GDISP.Orientation == (gdisp_orientation_t)value)
- return;
- switch((gdisp_orientation_t)value) {
- case GDISP_ROTATE_0:
- write_reg(0x0001,0x0127);
- write_reg(0x03, 0b0011);
- GDISP.Height = GDISP_SCREEN_HEIGHT;
- GDISP.Width = GDISP_SCREEN_WIDTH;
- break;
- case GDISP_ROTATE_90:
- write_reg(0x0001,0x0027);
- write_reg(0x0003, 0b1011);
- GDISP.Height = GDISP_SCREEN_WIDTH;
- GDISP.Width = GDISP_SCREEN_HEIGHT;
- break;
- case GDISP_ROTATE_180:
- write_reg(0x0001,0x0127);
- write_reg(0x0003, 0b0000);
- GDISP.Height = GDISP_SCREEN_HEIGHT;
- GDISP.Width = GDISP_SCREEN_WIDTH;
- break;
- case GDISP_ROTATE_270:
- write_reg(0x0001,0x0027);
- write_reg(0x0003, 0b1000);
- 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:
- case GDISP_CONTROL_CONTRAST:
-*/
- }
- }
-#endif
-
-#endif /* GFX_USE_GDISP */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/S6D1121/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the S6d1121 display. + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.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" + +/*===========================================================================*/ +/* 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 +#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_SCREEN_HEIGHT 320 +#define GDISP_SCREEN_WIDTH 240 + +#define GDISP_INITIAL_CONTRAST 50 +#define GDISP_INITIAL_BACKLIGHT 100 + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#elif defined(BOARD_OLIMEX_STM32_E407) + #include "gdisp_lld_board_olimex_e407.h" +#else + #include "gdisp_lld_board.h" +#endif + +/* 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) chThdSleepMicroseconds(us) +#define delayms(ms) chThdSleepMilliseconds(ms) + +static __inline void set_cursor(coord_t x, coord_t y) { + /* R20h - 8 bit + * R21h - 9 bit + */ + switch(GDISP.Orientation) { + case GDISP_ROTATE_0: + write_reg(0x0020, x & 0x00FF); + write_reg(0x0021, 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); + break; + case GDISP_ROTATE_180: + write_reg(0x0020, (GDISP_SCREEN_WIDTH - 1 - x) & 0x00FF); + write_reg(0x0021, (GDISP_SCREEN_HEIGHT - 1 - 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); + break; + } +} + +static __inline void set_viewport(coord_t x, coord_t y, coord_t cx, coord_t cy) { + /* HSA / HEA are 8 bit + * VSA / VEA are 9 bit + * use masks 0x00FF and 0x01FF to enforce this + */ + + switch(GDISP.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); + 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); + 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); + 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); + 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) { + /* initialize the hardware */ + init_board(); + + /* Hardware reset */ + setpin_reset(TRUE); + delayms(20); + setpin_reset(TRUE); + delayms(20); + + /* Get the bus for the following initialisation commands */ + acquire_bus(); + + write_reg(0x11,0x2004); + write_reg(0x13,0xCC00); + write_reg(0x15,0x2600); + write_reg(0x14,0x252A); + write_reg(0x12,0x0033); + write_reg(0x13,0xCC04); + + delayms(1); + + write_reg(0x13,0xCC06); + + delayms(1); + + write_reg(0x13,0xCC4F); + + delayms(1); + + write_reg(0x13,0x674F); + write_reg(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(0x16,0x0007); + write_reg(0x02,0x0013); + write_reg(0x03,0x0003); + write_reg(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); + + delayms(1); + + write_reg(0x07,0x0053); + write_reg(0x79,0x0000); + + reset_viewport(); + set_backlight(GDISP_INITIAL_BACKLIGHT); + + /* 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 + 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(); + } +#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(); + } +#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) { + 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; + return; + case GDISP_CONTROL_ORIENTATION: + if (GDISP.Orientation == (gdisp_orientation_t)value) + return; + switch((gdisp_orientation_t)value) { + case GDISP_ROTATE_0: + write_reg(0x0001,0x0127); + write_reg(0x03, 0b0011); + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_90: + write_reg(0x0001,0x0027); + write_reg(0x0003, 0b1011); + GDISP.Height = GDISP_SCREEN_WIDTH; + GDISP.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + write_reg(0x0001,0x0127); + write_reg(0x0003, 0b0000); + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + write_reg(0x0001,0x0027); + write_reg(0x0003, 0b1000); + 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: + case GDISP_CONTROL_CONTRAST: +*/ + } + } +#endif + +#endif /* GFX_USE_GDISP */ +/** @} */ + diff --git a/drivers/gdisp/SSD1289/gdisp_lld.c b/drivers/gdisp/SSD1289/gdisp_lld.c index 96fb94e6..de6edfe8 100644 --- a/drivers/gdisp/SSD1289/gdisp_lld.c +++ b/drivers/gdisp/SSD1289/gdisp_lld.c @@ -1,583 +1,583 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/SSD1289/gdisp_lld.c
- * @brief GDISP Graphics Driver subsystem low level driver source for the SSD1289 display.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.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"
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#ifndef GDISP_SCREEN_HEIGHT
- #define GDISP_SCREEN_HEIGHT 320
-#endif
-#ifndef GDISP_SCREEN_WIDTH
- #define GDISP_SCREEN_WIDTH 240
-#endif
-
-#define GDISP_INITIAL_CONTRAST 50
-#define GDISP_INITIAL_BACKLIGHT 100
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#elif defined(BOARD_FIREBULL_STM32_F103)
- #include "gdisp_lld_board_firebullstm32f103.h"
-#else
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#endif
-
-// 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) chThdSleepMicroseconds(us)
-#define delayms(ms) chThdSleepMilliseconds(ms)
-
-static __inline void set_cursor(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(GDISP.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(coord_t x, coord_t y, coord_t cx, coord_t cy) {
-
- set_cursor(x, y);
-
- /* 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
- */
-
- switch(GDISP.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);
- 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);
- break;
- }
-
- set_cursor(x, y);
-}
-
-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 lld_gdisp_init(void) {
- /* Initialise your display */
- init_board();
-
- // Hardware reset
- setpin_reset(TRUE);
- delayms(20);
- setpin_reset(FALSE);
- delayms(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);
-
- // Release the bus
- release_bus();
-
- /* 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
- 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 lld_gdisp_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 lld_gdisp_clear(color_t color) {
- unsigned i;
-
- acquire_bus();
- reset_viewport();
- set_cursor(0, 0);
- stream_start();
- for(i = 0; i < GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT; i++)
- write_data(color);
- 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 lld_gdisp_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();
- 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 lld_gdisp_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 lld_gdisp_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 lld_gdisp_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 (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; j < cx; j++)
- buf[j] = read_data();
- stream_stop();
-
- set_viewport(x, row1, cx, 1);
- stream_start();
- for (j = 0; j < cx; j++)
- write_data(buf[j]);
- 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();
- 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 lld_gdisp_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(0x0010, 0x0000); // leave sleep mode
- write_reg(0x0007, 0x0000); // halt operation
- write_reg(0x0000, 0x0000); // turn off oszillator
- write_reg(0x0010, 0x0001); // enter sleepmode
- release_bus();
- break;
- case powerOn:
- acquire_bus();
- write_reg(0x0010, 0x0000); // leave sleep mode
- release_bus();
- if (GDISP.Powermode != powerSleep)
- lld_gdisp_init();
- break;
- case powerSleep:
- acquire_bus();
- write_reg(0x0010, 0x0001); // enter sleep mode
- release_bus();
- break;
- default:
- return;
- }
- GDISP.Powermode = (gdisp_powermode_t)value;
- return;
- case GDISP_CONTROL_ORIENTATION:
- if (GDISP.Orientation == (gdisp_orientation_t)value)
- return;
- switch((gdisp_orientation_t)value) {
- 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;
- break;
- case GDISP_ROTATE_90:
- acquire_bus();
- write_reg(0x0001, 0x293F);
- /* ID = 11 AM = 1 */
- write_reg(0x0011, 0x6078);
- release_bus();
- GDISP.Height = GDISP_SCREEN_WIDTH;
- GDISP.Width = GDISP_SCREEN_HEIGHT;
- break;
- case GDISP_ROTATE_180:
- acquire_bus();
- write_reg(0x0001, 0x2B3F);
- /* ID = 01 AM = 0 */
- write_reg(0x0011, 0x6040);
- release_bus();
- GDISP.Height = GDISP_SCREEN_HEIGHT;
- GDISP.Width = GDISP_SCREEN_WIDTH;
- break;
- case GDISP_ROTATE_270:
- acquire_bus();
- write_reg(0x0001, 0x293F);
- /* ID = 01 AM = 1 */
- write_reg(0x0011, 0x6048);
- 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:
- case GDISP_CONTROL_CONTRAST:
-*/
- }
- }
-#endif
-
-#endif /* GFX_USE_GDISP */
-/** @} */
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/SSD1289/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for the SSD1289 display. + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.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" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 320 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif + +#define GDISP_INITIAL_CONTRAST 50 +#define GDISP_INITIAL_BACKLIGHT 100 + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if defined(GDISP_USE_CUSTOM_BOARD) && GDISP_USE_CUSTOM_BOARD + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#elif defined(BOARD_FIREBULL_STM32_F103) + #include "gdisp_lld_board_firebullstm32f103.h" +#else + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#endif + +// 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) chThdSleepMicroseconds(us) +#define delayms(ms) chThdSleepMilliseconds(ms) + +static __inline void set_cursor(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(GDISP.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(coord_t x, coord_t y, coord_t cx, coord_t cy) { + + set_cursor(x, y); + + /* 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 + */ + + switch(GDISP.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); + 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); + break; + } + + set_cursor(x, y); +} + +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) { + /* Initialise your display */ + init_board(); + + // Hardware reset + setpin_reset(TRUE); + delayms(20); + setpin_reset(FALSE); + delayms(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); + + // Release the bus + release_bus(); + + /* 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 + 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 i; + + acquire_bus(); + reset_viewport(); + set_cursor(0, 0); + stream_start(); + for(i = 0; i < GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT; i++) + write_data(color); + 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 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(); + 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 (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; j < cx; j++) + buf[j] = read_data(); + stream_stop(); + + set_viewport(x, row1, cx, 1); + stream_start(); + for (j = 0; j < cx; j++) + write_data(buf[j]); + 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(); + 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) { + case GDISP_CONTROL_POWER: + if (GDISP.Powermode == (gdisp_powermode_t)value) + return; + switch((gdisp_powermode_t)value) { + 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 + release_bus(); + break; + case powerOn: + acquire_bus(); + write_reg(0x0010, 0x0000); // leave sleep mode + release_bus(); + if (GDISP.Powermode != powerSleep) + gdisp_lld_init(); + break; + case powerSleep: + acquire_bus(); + write_reg(0x0010, 0x0001); // enter sleep mode + release_bus(); + break; + default: + return; + } + GDISP.Powermode = (gdisp_powermode_t)value; + return; + case GDISP_CONTROL_ORIENTATION: + if (GDISP.Orientation == (gdisp_orientation_t)value) + return; + switch((gdisp_orientation_t)value) { + 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; + break; + case GDISP_ROTATE_90: + acquire_bus(); + write_reg(0x0001, 0x293F); + /* ID = 11 AM = 1 */ + write_reg(0x0011, 0x6078); + release_bus(); + GDISP.Height = GDISP_SCREEN_WIDTH; + GDISP.Width = GDISP_SCREEN_HEIGHT; + break; + case GDISP_ROTATE_180: + acquire_bus(); + write_reg(0x0001, 0x2B3F); + /* ID = 01 AM = 0 */ + write_reg(0x0011, 0x6040); + release_bus(); + GDISP.Height = GDISP_SCREEN_HEIGHT; + GDISP.Width = GDISP_SCREEN_WIDTH; + break; + case GDISP_ROTATE_270: + acquire_bus(); + write_reg(0x0001, 0x293F); + /* ID = 01 AM = 1 */ + write_reg(0x0011, 0x6048); + 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: + case GDISP_CONTROL_CONTRAST: +*/ + } + } +#endif + +#endif /* GFX_USE_GDISP */ +/** @} */ diff --git a/drivers/gdisp/SSD1963/gdisp_lld.c b/drivers/gdisp/SSD1963/gdisp_lld.c index 0b676ebc..4044d8d0 100644 --- a/drivers/gdisp/SSD1963/gdisp_lld.c +++ b/drivers/gdisp/SSD1963/gdisp_lld.c @@ -1,613 +1,613 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/SSD1963/gdisp_lld.c
- * @brief GDISP Graphics Driver subsystem low level driver source.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.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"
-
-#ifndef GDISP_SCREEN_HEIGHT
- #define GDISP_SCREEN_HEIGHT 320
-#endif
-#ifndef GDISP_SCREEN_WIDTH
- #define GDISP_SCREEN_WIDTH 240
-#endif
-
-/* 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.
- */
-//#if defined(BOARD_YOURBOARDNAME)
-// #include "gdisp_lld_board_yourboardname.h"
-//#else
-// /* Include the user supplied board definitions */
-// #include "gdisp_lld_board.h"
-//#endif
-
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-#include "ssd1963.h"
-
-
-#if defined(GDISP_USE_FSMC)
-__inline void GDISP_LLD(writeindex)(uint8_t cmd) {
- GDISP_REG = cmd;
-}
-
-__inline void GDISP_LLD(writereg)(uint16_t lcdReg,uint16_t lcdRegValue) {
- GDISP_REG = lcdReg;
- GDISP_RAM = lcdRegValue;
-}
-
-__inline void GDISP_LLD(writedata)(uint16_t data) {
- GDISP_RAM = data;
-}
-
-__inline uint16_t GDISP_LLD(readdata)(void) {
- return (GDISP_RAM);
-}
-
-__inline uint8_t GDISP_LLD(readreg)(uint8_t lcdReg) {
- GDISP_REG = lcdReg;
- return (GDISP_RAM);
-}
-
-__inline void GDISP_LLD(writestreamstart)(void) {
- GDISP_LLD(writeindex)(SSD1963_WRITE_MEMORY_START);
-}
-
-__inline void GDISP_LLD(readstreamstart)(void) {
- GDISP_LLD(writeindex)(SSD1963_READ_MEMORY_START);
-}
-
-__inline void GDISP_LLD(writestream)(uint16_t *buffer, uint16_t size) {
- uint16_t i;
- for(i = 0; i < size; i++)
- GDISP_RAM = buffer[i];
-}
-
-__inline void GDISP_LLD(readstream)(uint16_t *buffer, size_t size) {
- uint16_t i;
-
- for(i = 0; i < size; i++) {
- buffer[i] = GDISP_RAM;
- }
-}
-
-#elif defined(GDISP_USE_GPIO)
-
-__inline void GDISP_LLD(writeindex)(uint8_t cmd) {
- Set_CS; Set_RS; Set_WR; Clr_RD;
- palWritePort(GDISP_DATA_PORT, cmd);
- Clr_CS;
-}
-
-__inline void GDISP_LLD(writereg)(uint16_t lcdReg,uint16_t lcdRegValue) {
- Set_CS; Set_RS; Set_WR; Clr_RD;
- palWritePort(GDISP_DATA_PORT, lcdReg);
- Clr_RS;
- palWritePort(GDISP_DATA_PORT, lcdRegValue);
- Clr_CS;
-}
-__inline void GDISP_LLD(writedata)(uint16_t data) {
- Set_CS; Clr_RS; Set_WR; Clr_RD;
- palWritePort(GDISP_DATA_PORT, data);
- Clr_CS;
-}
-
-__inline uint16_t GDISP_LLD(readdata)(void) {
- Set_CS; Clr_RS; Clr_WR; Set_RD;
- uint16_t data = palReadPort(GDISP_DATA_PORT);
- Clr_CS;
- return data;
-}
-
-__inline uint8_t GDISP_LLD(readreg)(uint8_t lcdReg) {
- Set_CS; Set_RS; Clr_WR; Set_RD;
- palWritePort(GDISP_DATA_PORT, lcdReg);
- Clr_RS;
- uint16_t data = palReadPort(GDISP_DATA_PORT);
- Clr_CS;
- return data;
-}
-
-__inline void GDISP_LLD(writestreamstart)(void) {
- GDISP_LLD(writeindex)(SSD1963_WRITE_MEMORY_START);
-}
-
-__inline void GDISP_LLD(readstreamstart)(void) {
- GDISP_LLD(writeindex)(SSD1963_READ_MEMORY_START);
-}
-
-__inline void GDISP_LLD(writestream)(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 GDISP_LLD(readstream)(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;
- }
-}
-#endif
-
-/* ---- Required Routines ---- */
-/*
- The following 2 routines are required.
- All other routines are optional.
-*/
-
-/**
- * @brief Low level GDISP driver initialisation.
- * @return TRUE if successful, FALSE on error.
- *
- * @notapi
- */
-bool_t lld_gdisp_init(void) {
- /* Initialise the display */
-
-#if defined(GDISP_USE_FSMC)
-
- #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 << 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));
-
- const unsigned char FSMC_Bank = 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) ;
-
- /* 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;
-
-#elif defined(GDISP_USE_GPIO)
- 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);
-
-#else
- #error "Please define GDISP_USE_FSMC or GDISP_USE_GPIO"
-#endif
- GDISP_LLD(writeindex)(SSD1963_SOFT_RESET);
- chThdSleepMicroseconds(100);
-
- /* Driver PLL config */
- GDISP_LLD(writeindex)(SSD1963_SET_PLL_MN);
- GDISP_LLD(writedata)(35); // PLLclk = REFclk (10Mhz) * 36 (360Mhz)
- GDISP_LLD(writedata)(2); // SYSclk = PLLclk / 3 (120MHz)
- GDISP_LLD(writedata)(4); // Apply calculation bit, else it is ignored
-
- GDISP_LLD(writeindex)(SSD1963_SET_PLL); // Enable PLL
- GDISP_LLD(writedata)(0x01);
- chThdSleepMicroseconds(200);
-
- GDISP_LLD(writeindex)(SSD1963_SET_PLL); // Use PLL
- GDISP_LLD(writedata)(0x03);
- chThdSleepMicroseconds(200);
-
- GDISP_LLD(writeindex)(SSD1963_SOFT_RESET);
- chThdSleepMicroseconds(100);
-
- /* Screen size */
- GDISP_LLD(writeindex)(SSD1963_SET_GDISP_MODE);
-// GDISP_LLD(writedata)(0x0000);
- GDISP_LLD(writedata)(0b00011000); //Enabled dithering
- GDISP_LLD(writedata)(0x0000);
- GDISP_LLD(writedata)(mHIGH((GDISP_SCREEN_WIDTH+1)));
- GDISP_LLD(writedata)((GDISP_SCREEN_WIDTH+1));
- GDISP_LLD(writedata)(mHIGH((GDISP_SCREEN_HEIGHT+1)));
- GDISP_LLD(writedata)((GDISP_SCREEN_HEIGHT+1));
- GDISP_LLD(writedata)(0x0000);
-
- GDISP_LLD(writeindex)(SSD1963_SET_PIXEL_DATA_INTERFACE);
- GDISP_LLD(writedata)(SSD1963_PDI_16BIT565);
-
- /* LCD Clock specs */
- GDISP_LLD(writeindex)(SSD1963_SET_LSHIFT_FREQ);
- GDISP_LLD(writedata)((GDISP_FPR >> 16) & 0xFF);
- GDISP_LLD(writedata)((GDISP_FPR >> 8) & 0xFF);
- GDISP_LLD(writedata)(GDISP_FPR & 0xFF);
-
- GDISP_LLD(writeindex)(SSD1963_SET_HORI_PERIOD);
- GDISP_LLD(writedata)(mHIGH(SCREEN_HSYNC_PERIOD));
- GDISP_LLD(writedata)(mLOW(SCREEN_HSYNC_PERIOD));
- GDISP_LLD(writedata)(mHIGH((SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH)));
- GDISP_LLD(writedata)(mLOW((SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH)));
- GDISP_LLD(writedata)(SCREEN_HSYNC_PULSE);
- GDISP_LLD(writedata)(0x00);
- GDISP_LLD(writedata)(0x00);
- GDISP_LLD(writedata)(0x00);
-
- GDISP_LLD(writeindex)(SSD1963_SET_VERT_PERIOD);
- GDISP_LLD(writedata)(mHIGH(SCREEN_VSYNC_PERIOD));
- GDISP_LLD(writedata)(mLOW(SCREEN_VSYNC_PERIOD));
- GDISP_LLD(writedata)(mHIGH((SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH)));
- GDISP_LLD(writedata)(mLOW((SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH)));
- GDISP_LLD(writedata)(SCREEN_VSYNC_PULSE);
- GDISP_LLD(writedata)(0x00);
- GDISP_LLD(writedata)(0x00);
-
- /* Tear effect indicator ON. This is used to tell the host MCU when the driver is not refreshing the panel */
- GDISP_LLD(writeindex)(SSD1963_SET_TEAR_ON);
- GDISP_LLD(writedata)(0x0000);
-
- /* Turn on */
- GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_ON);
- #if defined(GDISP_USE_FSMC)
- /* 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;
- #endif
-
- /* 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
-
- 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
- */
- GDISP_LLD(writeindex)(SSD1963_SET_PAGE_ADDRESS);
- GDISP_LLD(writedata)((y0 >> 8) & 0xFF);
- GDISP_LLD(writedata)((y0 >> 0) & 0xFF);
- GDISP_LLD(writedata)((y1 >> 8) & 0xFF);
- GDISP_LLD(writedata)((y1 >> 0) & 0xFF);
- GDISP_LLD(writeindex)(SSD1963_SET_COLUMN_ADDRESS);
- GDISP_LLD(writedata)((x0 >> 8) & 0xFF);
- GDISP_LLD(writedata)((x0 >> 0) & 0xFF);
- GDISP_LLD(writedata)((x1 >> 8) & 0xFF);
- GDISP_LLD(writedata)((x1 >> 0) & 0xFF);
-}
-
-/**
- * @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 lld_gdisp_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);
- GDISP_LLD(writestreamstart)();
- GDISP_LLD(writedata)(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 lld_gdisp_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
-
- uint32_t area;
- area = cx*cy;
-
- GDISP_LLD(setwindow)(x, y, x+cx-1, y+cy-1);
- GDISP_LLD(writestreamstart)();
-
- #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++)
- GDISP_LLD(writedata)(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 lld_gdisp_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);
- GDISP_LLD(writestreamstart)();
-
- 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;
- unsigned lg;
- endx = srcx + cx;
- endy = y + cy;
- lg = srccx - cx;
- for(; y < endy; y++, buffer += lg)
- for(x=srcx; x < endx; x++)
- GDISP_LLD(writedata)(*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 lld_gdisp_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 ;
-
- lld_lcdWriteIndex(SSD1963_SET_SCROLL_AREA);
- lld_lcdWriteData((x0 >> 8) & 0xFF);
- lld_lcdWriteData((x0 >> 0) & 0xFF);
- lld_lcdWriteData((size >> 8) & 0xFF);
- lld_lcdWriteData((size >> 0) & 0xFF);
- lld_lcdWriteData(((lcd_height-x1) >> 8) & 0xFF);
- lld_lcdWriteData(((lcd_height-x1) >> 0) & 0xFF);
-
- lld_lcdWriteIndex(SSD1963_SET_SCROLL_START);
- lld_lcdWriteData((lines >> 8) & 0xFF);
- lld_lcdWriteData((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 lld_gdisp_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:
- GDISP_LLD(writeindex)(SSD1963_EXIT_SLEEP_MODE); // leave sleep mode
- chThdSleepMicroseconds(5000);
- GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_OFF);
- GDISP_LLD(writeindex)(SSD1963_SET_DEEP_SLEEP); // enter deep sleep mode
- break;
- case powerOn:
- GDISP_LLD(readreg)(0x0000); chThdSleepMicroseconds(5000); // 2x Dummy reads to wake up from deep sleep
- GDISP_LLD(readreg)(0x0000); chThdSleepMicroseconds(5000);
- if (GDISP.Powermode != powerSleep)
- lld_gdisp_init();
- GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_ON);
-
- break;
- case powerSleep:
- GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_OFF);
- GDISP_LLD(writeindex)(SSD1963_ENTER_SLEEP_MODE); // enter sleep mode
- chThdSleepMicroseconds(5000);
- break;
- default:
- return;
- }
- GDISP.Powermode = (gdisp_powermode_t)value;
- 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;
- return;
-/*
- case GDISP_CONTROL_BACKLIGHT:
- case GDISP_CONTROL_CONTRAST:
-*/
- }
- }
-#endif
-
-#endif /* GFX_USE_GDISP */
-/** @} */
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/SSD1963/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source. + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.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" + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 320 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 240 +#endif + +/* 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. + */ +//#if defined(BOARD_YOURBOARDNAME) +// #include "gdisp_lld_board_yourboardname.h" +//#else +// /* Include the user supplied board definitions */ +// #include "gdisp_lld_board.h" +//#endif + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +#include "ssd1963.h" + + +#if defined(GDISP_USE_FSMC) +__inline void GDISP_LLD(writeindex)(uint8_t cmd) { + GDISP_REG = cmd; +} + +__inline void GDISP_LLD(writereg)(uint16_t lcdReg,uint16_t lcdRegValue) { + GDISP_REG = lcdReg; + GDISP_RAM = lcdRegValue; +} + +__inline void GDISP_LLD(writedata)(uint16_t data) { + GDISP_RAM = data; +} + +__inline uint16_t GDISP_LLD(readdata)(void) { + return (GDISP_RAM); +} + +__inline uint8_t GDISP_LLD(readreg)(uint8_t lcdReg) { + GDISP_REG = lcdReg; + return (GDISP_RAM); +} + +__inline void GDISP_LLD(writestreamstart)(void) { + GDISP_LLD(writeindex)(SSD1963_WRITE_MEMORY_START); +} + +__inline void GDISP_LLD(readstreamstart)(void) { + GDISP_LLD(writeindex)(SSD1963_READ_MEMORY_START); +} + +__inline void GDISP_LLD(writestream)(uint16_t *buffer, uint16_t size) { + uint16_t i; + for(i = 0; i < size; i++) + GDISP_RAM = buffer[i]; +} + +__inline void GDISP_LLD(readstream)(uint16_t *buffer, size_t size) { + uint16_t i; + + for(i = 0; i < size; i++) { + buffer[i] = GDISP_RAM; + } +} + +#elif defined(GDISP_USE_GPIO) + +__inline void GDISP_LLD(writeindex)(uint8_t cmd) { + Set_CS; Set_RS; Set_WR; Clr_RD; + palWritePort(GDISP_DATA_PORT, cmd); + Clr_CS; +} + +__inline void GDISP_LLD(writereg)(uint16_t lcdReg,uint16_t lcdRegValue) { + Set_CS; Set_RS; Set_WR; Clr_RD; + palWritePort(GDISP_DATA_PORT, lcdReg); + Clr_RS; + palWritePort(GDISP_DATA_PORT, lcdRegValue); + Clr_CS; +} +__inline void GDISP_LLD(writedata)(uint16_t data) { + Set_CS; Clr_RS; Set_WR; Clr_RD; + palWritePort(GDISP_DATA_PORT, data); + Clr_CS; +} + +__inline uint16_t GDISP_LLD(readdata)(void) { + Set_CS; Clr_RS; Clr_WR; Set_RD; + uint16_t data = palReadPort(GDISP_DATA_PORT); + Clr_CS; + return data; +} + +__inline uint8_t GDISP_LLD(readreg)(uint8_t lcdReg) { + Set_CS; Set_RS; Clr_WR; Set_RD; + palWritePort(GDISP_DATA_PORT, lcdReg); + Clr_RS; + uint16_t data = palReadPort(GDISP_DATA_PORT); + Clr_CS; + return data; +} + +__inline void GDISP_LLD(writestreamstart)(void) { + GDISP_LLD(writeindex)(SSD1963_WRITE_MEMORY_START); +} + +__inline void GDISP_LLD(readstreamstart)(void) { + GDISP_LLD(writeindex)(SSD1963_READ_MEMORY_START); +} + +__inline void GDISP_LLD(writestream)(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 GDISP_LLD(readstream)(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; + } +} +#endif + +/* ---- Required Routines ---- */ +/* + The following 2 routines are required. + All other routines are optional. +*/ + +/** + * @brief Low level GDISP driver initialisation. + * @return TRUE if successful, FALSE on error. + * + * @notapi + */ +bool_t gdisp_lld_init(void) { + /* Initialise the display */ + +#if defined(GDISP_USE_FSMC) + + #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 << 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)); + + const unsigned char FSMC_Bank = 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) ; + + /* 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; + +#elif defined(GDISP_USE_GPIO) + 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); + +#else + #error "Please define GDISP_USE_FSMC or GDISP_USE_GPIO" +#endif + GDISP_LLD(writeindex)(SSD1963_SOFT_RESET); + chThdSleepMicroseconds(100); + + /* Driver PLL config */ + GDISP_LLD(writeindex)(SSD1963_SET_PLL_MN); + GDISP_LLD(writedata)(35); // PLLclk = REFclk (10Mhz) * 36 (360Mhz) + GDISP_LLD(writedata)(2); // SYSclk = PLLclk / 3 (120MHz) + GDISP_LLD(writedata)(4); // Apply calculation bit, else it is ignored + + GDISP_LLD(writeindex)(SSD1963_SET_PLL); // Enable PLL + GDISP_LLD(writedata)(0x01); + chThdSleepMicroseconds(200); + + GDISP_LLD(writeindex)(SSD1963_SET_PLL); // Use PLL + GDISP_LLD(writedata)(0x03); + chThdSleepMicroseconds(200); + + GDISP_LLD(writeindex)(SSD1963_SOFT_RESET); + chThdSleepMicroseconds(100); + + /* Screen size */ + GDISP_LLD(writeindex)(SSD1963_SET_GDISP_MODE); +// GDISP_LLD(writedata)(0x0000); + GDISP_LLD(writedata)(0b00011000); //Enabled dithering + GDISP_LLD(writedata)(0x0000); + GDISP_LLD(writedata)(mHIGH((GDISP_SCREEN_WIDTH+1))); + GDISP_LLD(writedata)((GDISP_SCREEN_WIDTH+1)); + GDISP_LLD(writedata)(mHIGH((GDISP_SCREEN_HEIGHT+1))); + GDISP_LLD(writedata)((GDISP_SCREEN_HEIGHT+1)); + GDISP_LLD(writedata)(0x0000); + + GDISP_LLD(writeindex)(SSD1963_SET_PIXEL_DATA_INTERFACE); + GDISP_LLD(writedata)(SSD1963_PDI_16BIT565); + + /* LCD Clock specs */ + GDISP_LLD(writeindex)(SSD1963_SET_LSHIFT_FREQ); + GDISP_LLD(writedata)((GDISP_FPR >> 16) & 0xFF); + GDISP_LLD(writedata)((GDISP_FPR >> 8) & 0xFF); + GDISP_LLD(writedata)(GDISP_FPR & 0xFF); + + GDISP_LLD(writeindex)(SSD1963_SET_HORI_PERIOD); + GDISP_LLD(writedata)(mHIGH(SCREEN_HSYNC_PERIOD)); + GDISP_LLD(writedata)(mLOW(SCREEN_HSYNC_PERIOD)); + GDISP_LLD(writedata)(mHIGH((SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH))); + GDISP_LLD(writedata)(mLOW((SCREEN_HSYNC_PULSE + SCREEN_HSYNC_BACK_PORCH))); + GDISP_LLD(writedata)(SCREEN_HSYNC_PULSE); + GDISP_LLD(writedata)(0x00); + GDISP_LLD(writedata)(0x00); + GDISP_LLD(writedata)(0x00); + + GDISP_LLD(writeindex)(SSD1963_SET_VERT_PERIOD); + GDISP_LLD(writedata)(mHIGH(SCREEN_VSYNC_PERIOD)); + GDISP_LLD(writedata)(mLOW(SCREEN_VSYNC_PERIOD)); + GDISP_LLD(writedata)(mHIGH((SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH))); + GDISP_LLD(writedata)(mLOW((SCREEN_VSYNC_PULSE + SCREEN_VSYNC_BACK_PORCH))); + GDISP_LLD(writedata)(SCREEN_VSYNC_PULSE); + GDISP_LLD(writedata)(0x00); + GDISP_LLD(writedata)(0x00); + + /* Tear effect indicator ON. This is used to tell the host MCU when the driver is not refreshing the panel */ + GDISP_LLD(writeindex)(SSD1963_SET_TEAR_ON); + GDISP_LLD(writedata)(0x0000); + + /* Turn on */ + GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_ON); + #if defined(GDISP_USE_FSMC) + /* 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; + #endif + + /* 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 + + 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 + */ + GDISP_LLD(writeindex)(SSD1963_SET_PAGE_ADDRESS); + GDISP_LLD(writedata)((y0 >> 8) & 0xFF); + GDISP_LLD(writedata)((y0 >> 0) & 0xFF); + GDISP_LLD(writedata)((y1 >> 8) & 0xFF); + GDISP_LLD(writedata)((y1 >> 0) & 0xFF); + GDISP_LLD(writeindex)(SSD1963_SET_COLUMN_ADDRESS); + GDISP_LLD(writedata)((x0 >> 8) & 0xFF); + GDISP_LLD(writedata)((x0 >> 0) & 0xFF); + GDISP_LLD(writedata)((x1 >> 8) & 0xFF); + GDISP_LLD(writedata)((x1 >> 0) & 0xFF); +} + +/** + * @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); + GDISP_LLD(writestreamstart)(); + GDISP_LLD(writedata)(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) { + + #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 + + uint32_t area; + area = cx*cy; + + GDISP_LLD(setwindow)(x, y, x+cx-1, y+cy-1); + GDISP_LLD(writestreamstart)(); + + #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++) + GDISP_LLD(writedata)(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); + GDISP_LLD(writestreamstart)(); + + 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; + unsigned lg; + endx = srcx + cx; + endy = y + cy; + lg = srccx - cx; + for(; y < endy; y++, buffer += lg) + for(x=srcx; x < endx; x++) + GDISP_LLD(writedata)(*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 ; + + lld_lcdWriteIndex(SSD1963_SET_SCROLL_AREA); + lld_lcdWriteData((x0 >> 8) & 0xFF); + lld_lcdWriteData((x0 >> 0) & 0xFF); + lld_lcdWriteData((size >> 8) & 0xFF); + lld_lcdWriteData((size >> 0) & 0xFF); + lld_lcdWriteData(((lcd_height-x1) >> 8) & 0xFF); + lld_lcdWriteData(((lcd_height-x1) >> 0) & 0xFF); + + lld_lcdWriteIndex(SSD1963_SET_SCROLL_START); + lld_lcdWriteData((lines >> 8) & 0xFF); + lld_lcdWriteData((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: + GDISP_LLD(writeindex)(SSD1963_EXIT_SLEEP_MODE); // leave sleep mode + chThdSleepMicroseconds(5000); + GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_OFF); + GDISP_LLD(writeindex)(SSD1963_SET_DEEP_SLEEP); // enter deep sleep mode + break; + case powerOn: + GDISP_LLD(readreg)(0x0000); chThdSleepMicroseconds(5000); // 2x Dummy reads to wake up from deep sleep + GDISP_LLD(readreg)(0x0000); chThdSleepMicroseconds(5000); + if (GDISP.Powermode != powerSleep) + gdisp_lld_init(); + GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_ON); + + break; + case powerSleep: + GDISP_LLD(writeindex)(SSD1963_SET_DISPLAY_OFF); + GDISP_LLD(writeindex)(SSD1963_ENTER_SLEEP_MODE); // enter sleep mode + chThdSleepMicroseconds(5000); + break; + default: + return; + } + GDISP.Powermode = (gdisp_powermode_t)value; + 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; + return; +/* + case GDISP_CONTROL_BACKLIGHT: + case GDISP_CONTROL_CONTRAST: +*/ + } + } +#endif + +#endif /* GFX_USE_GDISP */ +/** @} */ diff --git a/drivers/gdisp/TestStub/gdisp_lld.c b/drivers/gdisp/TestStub/gdisp_lld.c index be323912..a1f3de3e 100644 --- a/drivers/gdisp/TestStub/gdisp_lld.c +++ b/drivers/gdisp/TestStub/gdisp_lld.c @@ -1,133 +1,133 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/gdisp/TestStub/gdisp_lld.c
- * @brief GDISP Graphics Driver subsystem low level driver source (stub).
- *
- * @addtogroup GDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.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"
-
-#ifndef GDISP_SCREEN_HEIGHT
- #define GDISP_SCREEN_HEIGHT 128
-#endif
-#ifndef GDISP_SCREEN_WIDTH
- #define GDISP_SCREEN_WIDTH 128
-#endif
-
-/* ---- Required Routines ---- */
-/*
- The following 2 routines are required.
- All other routines are optional.
-*/
-
-/**
- * @brief Low level GDISP driver initialization.
- *
- * @notapi
- */
-bool_t lld_gdisp_init(void) {
- /* 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
- 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 lld_gdisp_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 lld_gdisp_get_pixel_color(coord_t x, coord_t y) {
- (void)x;
- (void)y;
-
- 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 lld_gdisp_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 */
-/** @} */
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/gdisp/TestStub/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source (stub). + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.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" + +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 128 +#endif +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 128 +#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) { + /* 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 + 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; + + 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/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index 8a46abc9..220776d2 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -1,1026 +1,1026 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/multiple/Win32/gdisp_lld.c
- * @brief GDISP Graphics Driver subsystem low level driver source for Win32.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.h"
-#include "gfx.h"
-
-#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <windows.h>
-#include <wingdi.h>
-#include <assert.h>
-
-#ifndef GDISP_SCREEN_WIDTH
- #define GDISP_SCREEN_WIDTH 640
-#endif
-#ifndef GDISP_SCREEN_HEIGHT
- #define GDISP_SCREEN_HEIGHT 480
-#endif
-
-#if GINPUT_NEED_TOGGLE
- /* Include toggle support code */
- #include "ginput/lld/toggle.h"
-
- const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES] = {
- {0, 0xFF, 0x00, PAL_MODE_INPUT},
- };
-#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"
-
-/*===========================================================================*/
-/* 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 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;
-
-#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;
- #if GINPUT_NEED_TOGGLE
- HBRUSH hbrOn, hbrOff;
- HPEN pen;
- RECT rect;
- HGDIOBJ old;
- POINT p;
- coord_t pos;
- uint8_t bit;
- #endif
-
- switch (Msg) {
- case WM_CREATE:
- 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();
- #endif
- #endif
- break;
- case WM_LBUTTONUP:
- #if GINPUT_NEED_TOGGLE
- if ((toggles & 0xF0)) {
- 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;
- 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_SYSKEYDOWN:
- case WM_KEYDOWN:
- case WM_SYSKEYUP:
- case WM_KEYUP:
- break;
- case WM_CHAR:
- case WM_DEADCHAR:
- case WM_SYSCHAR:
- case WM_SYSDEADCHAR:
- break;
- case WM_PAINT:
- 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);
- #if GINPUT_NEED_TOGGLE
- if (ps.rcPaint.bottom >= wHeight) {
- 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);
- 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);
- if (pos > 0) {
- MoveToEx(dc, rect.left, rect.top, &p);
- LineTo(dc, rect.left, rect.bottom);
- }
- }
- DeleteObject(hbrOn);
- DeleteObject(hbrOff);
- SelectObject(dc, old);
- }
- #endif
- EndPaint(hWnd, &ps);
- break;
- case WM_DESTROY:
- PostQuitMessage(0);
- SelectObject(dcBuffer, dcOldBitmap);
- DeleteDC(dcBuffer);
- DeleteObject(dcBitmap);
- winRootWindow = NULL;
- break;
- default:
- return DefWindowProc(hWnd, Msg, wParam, lParam);
- }
- return 0;
-}
-
-static DWORD WINAPI WindowThread(LPVOID lpParameter) {
- (void)lpParameter;
-
- MSG msg;
- 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;
-
- while(GetMessage(&msg, NULL, 0, 0) > 0) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- ExitProcess(0);
- return msg.wParam;
-}
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/* ---- Required Routines ---- */
-/*
- The following 2 routines are required.
- All other routines are optional.
-*/
-
-/**
- * @brief Low level GDISP driver initialisation.
- * @return TRUE if successful, FALSE on error.
- *
- * @notapi
- */
-bool_t lld_gdisp_init(void) {
- RECT rect;
-
- /* 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 */
- CreateThread(0, 0, WindowThread, 0, 0, 0);
- while (!isReady)
- 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
- 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 lld_gdisp_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
-
- // Draw the pixel in the buffer
- color = COLOR2BGR(color);
- SetPixel(dcBuffer, x, y, 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
-}
-
-/* ---- Optional Routines ---- */
-
-#if GDISP_HARDWARE_LINES || defined(__DOXYGEN__)
- /**
- * @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 lld_gdisp_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(GDISP.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);
- #endif
- break;
- case GDISP_ROTATE_90:
- t = GDISP.Height - 1 - y0;
- y0 = x0;
- x0 = t;
- t = GDISP.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);
- #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;
- #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);
- #endif
- break;
- case GDISP_ROTATE_270:
- t = GDISP.Width - 1 - x0;
- x0 = y0;
- y0 = t;
- t = GDISP.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);
- #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);
- #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
-
-#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 lld_gdisp_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_NEED_CONTROL
- switch(GDISP.Orientation) {
- case GDISP_ROTATE_0:
- rect.top = y;
- rect.bottom = rect.top+cy;
- rect.left = x;
- rect.right = rect.left+cx;
- break;
- case GDISP_ROTATE_90:
- rect.top = x;
- rect.bottom = rect.top+cx;
- rect.right = GDISP.Height - y;
- rect.left = rect.right-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;
- break;
- case GDISP_ROTATE_270:
- rect.bottom = GDISP.Width - x;
- rect.top = rect.bottom-cx;
- rect.left = y;
- rect.right = rect.left+cy;
- break;
- }
- #else
- rect.top = y;
- rect.bottom = rect.top+cy;
- rect.left = x;
- rect.right = rect.left+cx;
- #endif
-
- color = COLOR2BGR(color);
- hbr = CreateSolidBrush(color);
-
- if (hbr) {
- // Fill the area
- FillRect(dcBuffer, &rect, hbr);
-
- #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);
- }
- }
-#endif
-
-#if (GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL) || defined(__DOXYGEN__)
- 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;
- const pixel_t *src;
- size_t sz;
- coord_t i, j;
-
- // Shortcut.
- if (GDISP.Orientation == GDISP_ROTATE_0 && srcx == 0 && cx == srccx)
- return (pixel_t *)buffer;
-
- // Allocate the destination buffer
- sz = (size_t)cx * (size_t)cy;
- if (!(dstbuf = (pixel_t *)malloc(sz * sizeof(pixel_t))))
- return 0;
-
- // Copy the bits we need
- switch(GDISP.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)
- *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)
- *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)
- *--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)
- *dst = *src++;
- }
- break;
- }
- return dstbuf;
- }
-#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 lld_gdisp_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) {
- 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 < 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
-
- // Make everything relative to the start of the line
- buffer += srccx*srcy;
- srcy = 0;
-
- memset(&bmpInfo, 0, sizeof(bmpInfo));
- bmpInfo.bV4Size = sizeof(bmpInfo);
- bmpInfo.bV4Planes = 1;
- bmpInfo.bV4BitCount = 32;
- bmpInfo.bV4AlphaMask = 0;
- bmpInfo.bV4RedMask = RGB2COLOR(255,0,0);
- bmpInfo.bV4GreenMask = RGB2COLOR(0,255,0);
- bmpInfo.bV4BlueMask = RGB2COLOR(0,0,255);
- bmpInfo.bV4V4Compression = BI_BITFIELDS;
- bmpInfo.bV4XPelsPerMeter = 3078;
- bmpInfo.bV4YPelsPerMeter = 3078;
- bmpInfo.bV4ClrUsed = 0;
- bmpInfo.bV4ClrImportant = 0;
- bmpInfo.bV4CSType = 0; //LCS_sRGB;
-
- #if GDISP_NEED_CONTROL
- bmpInfo.bV4SizeImage = (cy*cx) * sizeof(pixel_t);
- srcimg = rotateimg(cx, cy, srcx, srccx, buffer);
- if (!srcimg) return;
-
- switch(GDISP.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;
- break;
- case GDISP_ROTATE_90:
- bmpInfo.bV4Width = cy;
- bmpInfo.bV4Height = -cx; /* top-down image */
- rect.top = x;
- rect.bottom = rect.top+cx;
- rect.right = GDISP.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.top = rect.bottom-cy;
- rect.right = GDISP.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.top = rect.bottom-cx;
- rect.left = y;
- rect.right = rect.left+cy;
- break;
- }
- 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)
- 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);
- #endif
-
- // Invalidate the region to get it on the screen.
- InvalidateRect(winRootWindow, &rect, FALSE);
- UpdateWindow(winRootWindow);
- }
-#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 lld_gdisp_get_pixel_color(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;
- #endif
-
- #if GDISP_NEED_CONTROL
- switch(GDISP.Orientation) {
- 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
-
- 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 lld_gdisp_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_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;
- #endif
-
- if (lines > cy) lines = cy;
- else if (-lines > cy) lines = -cy;
-
- bgcolor = COLOR2BGR(bgcolor);
- hbr = CreateSolidBrush(bgcolor);
-
- #if GDISP_NEED_CONTROL
- switch(GDISP.Orientation) {
- case GDISP_ROTATE_0:
- rect.top = y;
- rect.bottom = rect.top+cy;
- rect.left = x;
- rect.right = rect.left+cx;
- lines = -lines;
- goto vertical_scroll;
- case GDISP_ROTATE_90:
- rect.top = x;
- rect.bottom = rect.top+cx;
- rect.right = GDISP.Height - y;
- rect.left = rect.right-cy;
- goto horizontal_scroll;
- case GDISP_ROTATE_180:
- rect.bottom = GDISP.Height - y;
- rect.top = rect.bottom-cy;
- rect.right = GDISP.Width - x;
- rect.left = rect.right-cx;
- 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;
- } else {
- srect.bottom = frect.bottom = rect.bottom;
- frect.top = rect.bottom+lines;
- srect.top = rect.top-lines;
- }
- if (cy >= lines && cy >= -lines)
- ScrollDC(dcBuffer, 0, lines, &srect, 0, 0, 0);
- break;
- case GDISP_ROTATE_270:
- rect.bottom = GDISP.Width - x;
- rect.top = rect.bottom-cx;
- rect.left = y;
- rect.right = rect.left+cy;
- lines = -lines;
- 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;
- } else {
- srect.right = frect.right = rect.right;
- frect.left = rect.right+lines;
- srect.left = rect.left-lines;
- }
- 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;
- if (lines > 0) {
- srect.top = frect.top = rect.top;
- frect.bottom = rect.top+lines;
- srect.bottom = rect.bottom-lines;
- } else {
- srect.bottom = frect.bottom = rect.bottom;
- frect.top = rect.bottom+lines;
- srect.top = rect.top-lines;
- }
- 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 lld_gdisp_control(unsigned what, void *value) {
- switch(what) {
- case GDISP_CONTROL_ORIENTATION:
- if (GDISP.Orientation == (gdisp_orientation_t)value)
- return;
- switch((gdisp_orientation_t)value) {
- case GDISP_ROTATE_0:
- GDISP.Width = wWidth;
- GDISP.Height = wHeight;
- break;
- case GDISP_ROTATE_90:
- GDISP.Height = wWidth;
- GDISP.Width = wHeight;
- break;
- case GDISP_ROTATE_180:
- GDISP.Width = wWidth;
- GDISP.Height = wHeight;
- break;
- case GDISP_ROTATE_270:
- GDISP.Height = wWidth;
- GDISP.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;
- #endif
- GDISP.Orientation = (gdisp_orientation_t)value;
- return;
-/*
- case GDISP_CONTROL_POWER:
- case GDISP_CONTROL_BACKLIGHT:
- case GDISP_CONTROL_CONTRAST:
-*/
- }
- }
-#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
-
- 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 */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/multiple/Win32/gdisp_lld.c + * @brief GDISP Graphics Driver subsystem low level driver source for Win32. + * + * @addtogroup GDISP + * @{ + */ + +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if GFX_USE_GDISP /*|| defined(__DOXYGEN__)*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <windows.h> +#include <wingdi.h> +#include <assert.h> + +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 640 +#endif +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 480 +#endif + +#if GINPUT_NEED_TOGGLE + /* Include toggle support code */ + #include "ginput/lld/toggle.h" + + const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES] = { + {0, 0xFF, 0x00, PAL_MODE_INPUT}, + }; +#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" + +/*===========================================================================*/ +/* 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 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; + +#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; + #if GINPUT_NEED_TOGGLE + HBRUSH hbrOn, hbrOff; + HPEN pen; + RECT rect; + HGDIOBJ old; + POINT p; + coord_t pos; + uint8_t bit; + #endif + + switch (Msg) { + case WM_CREATE: + 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(); + #endif + #endif + break; + case WM_LBUTTONUP: + #if GINPUT_NEED_TOGGLE + if ((toggles & 0xF0)) { + 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; + 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_SYSKEYDOWN: + case WM_KEYDOWN: + case WM_SYSKEYUP: + case WM_KEYUP: + break; + case WM_CHAR: + case WM_DEADCHAR: + case WM_SYSCHAR: + case WM_SYSDEADCHAR: + break; + case WM_PAINT: + 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); + #if GINPUT_NEED_TOGGLE + if (ps.rcPaint.bottom >= wHeight) { + 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); + 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); + if (pos > 0) { + MoveToEx(dc, rect.left, rect.top, &p); + LineTo(dc, rect.left, rect.bottom); + } + } + DeleteObject(hbrOn); + DeleteObject(hbrOff); + SelectObject(dc, old); + } + #endif + EndPaint(hWnd, &ps); + break; + case WM_DESTROY: + PostQuitMessage(0); + SelectObject(dcBuffer, dcOldBitmap); + DeleteDC(dcBuffer); + DeleteObject(dcBitmap); + winRootWindow = NULL; + break; + default: + return DefWindowProc(hWnd, Msg, wParam, lParam); + } + return 0; +} + +static DWORD WINAPI WindowThread(LPVOID lpParameter) { + (void)lpParameter; + + MSG msg; + 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; + + while(GetMessage(&msg, NULL, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + ExitProcess(0); + return msg.wParam; +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/* ---- Required Routines ---- */ +/* + The following 2 routines are required. + All other routines are optional. +*/ + +/** + * @brief Low level GDISP driver initialisation. + * @return TRUE if successful, FALSE on error. + * + * @notapi + */ +bool_t gdisp_lld_init(void) { + RECT rect; + + /* 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 */ + CreateThread(0, 0, WindowThread, 0, 0, 0); + while (!isReady) + 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 + 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 + + // Draw the pixel in the buffer + color = COLOR2BGR(color); + SetPixel(dcBuffer, x, y, 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 +} + +/* ---- Optional Routines ---- */ + +#if GDISP_HARDWARE_LINES || defined(__DOXYGEN__) + /** + * @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(GDISP.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); + #endif + break; + case GDISP_ROTATE_90: + t = GDISP.Height - 1 - y0; + y0 = x0; + x0 = t; + t = GDISP.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); + #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; + #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); + #endif + break; + case GDISP_ROTATE_270: + t = GDISP.Width - 1 - x0; + x0 = y0; + y0 = t; + t = GDISP.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); + #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); + #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 + +#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_NEED_CONTROL + switch(GDISP.Orientation) { + case GDISP_ROTATE_0: + rect.top = y; + rect.bottom = rect.top+cy; + rect.left = x; + rect.right = rect.left+cx; + break; + case GDISP_ROTATE_90: + rect.top = x; + rect.bottom = rect.top+cx; + rect.right = GDISP.Height - y; + rect.left = rect.right-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; + break; + case GDISP_ROTATE_270: + rect.bottom = GDISP.Width - x; + rect.top = rect.bottom-cx; + rect.left = y; + rect.right = rect.left+cy; + break; + } + #else + rect.top = y; + rect.bottom = rect.top+cy; + rect.left = x; + rect.right = rect.left+cx; + #endif + + color = COLOR2BGR(color); + hbr = CreateSolidBrush(color); + + if (hbr) { + // Fill the area + FillRect(dcBuffer, &rect, hbr); + + #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); + } + } +#endif + +#if (GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL) || defined(__DOXYGEN__) + 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; + const pixel_t *src; + size_t sz; + coord_t i, j; + + // Shortcut. + if (GDISP.Orientation == GDISP_ROTATE_0 && srcx == 0 && cx == srccx) + return (pixel_t *)buffer; + + // Allocate the destination buffer + sz = (size_t)cx * (size_t)cy; + if (!(dstbuf = (pixel_t *)malloc(sz * sizeof(pixel_t)))) + return 0; + + // Copy the bits we need + switch(GDISP.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) + *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) + *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) + *--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) + *dst = *src++; + } + break; + } + return dstbuf; + } +#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) { + 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 < 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 + + // Make everything relative to the start of the line + buffer += srccx*srcy; + srcy = 0; + + memset(&bmpInfo, 0, sizeof(bmpInfo)); + bmpInfo.bV4Size = sizeof(bmpInfo); + bmpInfo.bV4Planes = 1; + bmpInfo.bV4BitCount = 32; + bmpInfo.bV4AlphaMask = 0; + bmpInfo.bV4RedMask = RGB2COLOR(255,0,0); + bmpInfo.bV4GreenMask = RGB2COLOR(0,255,0); + bmpInfo.bV4BlueMask = RGB2COLOR(0,0,255); + bmpInfo.bV4V4Compression = BI_BITFIELDS; + bmpInfo.bV4XPelsPerMeter = 3078; + bmpInfo.bV4YPelsPerMeter = 3078; + bmpInfo.bV4ClrUsed = 0; + bmpInfo.bV4ClrImportant = 0; + bmpInfo.bV4CSType = 0; //LCS_sRGB; + + #if GDISP_NEED_CONTROL + bmpInfo.bV4SizeImage = (cy*cx) * sizeof(pixel_t); + srcimg = rotateimg(cx, cy, srcx, srccx, buffer); + if (!srcimg) return; + + switch(GDISP.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; + break; + case GDISP_ROTATE_90: + bmpInfo.bV4Width = cy; + bmpInfo.bV4Height = -cx; /* top-down image */ + rect.top = x; + rect.bottom = rect.top+cx; + rect.right = GDISP.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.top = rect.bottom-cy; + rect.right = GDISP.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.top = rect.bottom-cx; + rect.left = y; + rect.right = rect.left+cy; + break; + } + 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) + 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); + #endif + + // Invalidate the region to get it on the screen. + InvalidateRect(winRootWindow, &rect, FALSE); + UpdateWindow(winRootWindow); + } +#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_VALIDATION || GDISP_NEED_CLIP + // Clip pre orientation change + if (x < 0 || x >= GDISP.Width || y < 0 || y >= GDISP.Height) return 0; + #endif + + #if GDISP_NEED_CONTROL + switch(GDISP.Orientation) { + 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 + + 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_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; + #endif + + if (lines > cy) lines = cy; + else if (-lines > cy) lines = -cy; + + bgcolor = COLOR2BGR(bgcolor); + hbr = CreateSolidBrush(bgcolor); + + #if GDISP_NEED_CONTROL + switch(GDISP.Orientation) { + case GDISP_ROTATE_0: + rect.top = y; + rect.bottom = rect.top+cy; + rect.left = x; + rect.right = rect.left+cx; + lines = -lines; + goto vertical_scroll; + case GDISP_ROTATE_90: + rect.top = x; + rect.bottom = rect.top+cx; + rect.right = GDISP.Height - y; + rect.left = rect.right-cy; + goto horizontal_scroll; + case GDISP_ROTATE_180: + rect.bottom = GDISP.Height - y; + rect.top = rect.bottom-cy; + rect.right = GDISP.Width - x; + rect.left = rect.right-cx; + 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; + } else { + srect.bottom = frect.bottom = rect.bottom; + frect.top = rect.bottom+lines; + srect.top = rect.top-lines; + } + if (cy >= lines && cy >= -lines) + ScrollDC(dcBuffer, 0, lines, &srect, 0, 0, 0); + break; + case GDISP_ROTATE_270: + rect.bottom = GDISP.Width - x; + rect.top = rect.bottom-cx; + rect.left = y; + rect.right = rect.left+cy; + lines = -lines; + 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; + } else { + srect.right = frect.right = rect.right; + frect.left = rect.right+lines; + srect.left = rect.left-lines; + } + 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; + if (lines > 0) { + srect.top = frect.top = rect.top; + frect.bottom = rect.top+lines; + srect.bottom = rect.bottom-lines; + } else { + srect.bottom = frect.bottom = rect.bottom; + frect.top = rect.bottom+lines; + srect.top = rect.top-lines; + } + 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) { + case GDISP_CONTROL_ORIENTATION: + if (GDISP.Orientation == (gdisp_orientation_t)value) + return; + switch((gdisp_orientation_t)value) { + case GDISP_ROTATE_0: + GDISP.Width = wWidth; + GDISP.Height = wHeight; + break; + case GDISP_ROTATE_90: + GDISP.Height = wWidth; + GDISP.Width = wHeight; + break; + case GDISP_ROTATE_180: + GDISP.Width = wWidth; + GDISP.Height = wHeight; + break; + case GDISP_ROTATE_270: + GDISP.Height = wWidth; + GDISP.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; + #endif + GDISP.Orientation = (gdisp_orientation_t)value; + return; +/* + case GDISP_CONTROL_POWER: + case GDISP_CONTROL_BACKLIGHT: + case GDISP_CONTROL_CONTRAST: +*/ + } + } +#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 + + 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/tdisp/HD44780/tdisp_lld.c b/drivers/tdisp/HD44780/tdisp_lld.c index 8a9c886f..32b2b8c9 100644 --- a/drivers/tdisp/HD44780/tdisp_lld.c +++ b/drivers/tdisp/HD44780/tdisp_lld.c @@ -1,164 +1,164 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/tdisp/HD44780/tdisp_lld.c
- * @brief TDISP driver subsystem low level driver source for the HD44780 display
- *
- * @addtogroup TDISP
- * @{
- */
-
-#include "ch.h"
-#include "hal.h"
-#include "gfx.h"
-
-#if GFX_USE_TDISP /*|| defined(__DOXYGEN__)*/
-
-/* The user may override the default display size */
-#ifndef TDISP_COLUMNS
- #define TDISP_COLUMNS 16
-#endif
-#ifndef TDISP_ROWS
- #define TDISP_ROWS 2
-#endif
-
-/* Controller Specific Properties */
-#define CUSTOM_CHAR_COUNT 8
-#define CUSTOM_CHAR_XBITS 5
-#define CUSTOM_CHAR_YBITS 8
-
-/* Define the properties of our controller */
-tdispStruct TDISP = {
- TDISP_COLUMNS, TDISP_ROWS, /* cols, rows */
- CUSTOM_CHAR_XBITS, CUSTOM_CHAR_YBITS, /* charBitsX, charBitsY */
- CUSTOM_CHAR_COUNT /* maxCustomChars */
- };
-
-/* Include the hardware interface details */
-#if defined(TDISP_USE_CUSTOM_BOARD) && TDISP_USE_CUSTOM_BOARD
- /* Include the user supplied board definitions */
- #include "tdisp_lld_board.h"
-#elif defined(BOARD_UNKNOWN)
- #include "gdisp_lld_board_unknown.h"
-#else
- /* Include the user supplied board definitions */
- #include "gdisp_lld_board.h"
-#endif
-
-/* Our display control */
-#define DISPLAY_ON 0x04
-#define CURSOR_ON 0x02
-#define CURSOR_BLINK 0x01
-
-static uint8_t displaycontrol;
-
-
-bool_t tdisp_lld_init(void) {
- /* initialise hardware */
- init_board();
-
- /* wait some time */
- chThdSleepMilliseconds(50);
-
- write_cmd(0x38);
- chThdSleepMilliseconds(64);
-
- displaycontrol = DISPLAY_ON | CURSOR_ON | CURSOR_BLINK; // The default displaycontrol
- write_cmd(0x08 | displaycontrol);
- chThdSleepMicroseconds(50);
-
- write_cmd(0x01); // Clear the screen
- chThdSleepMilliseconds(5);
-
- write_cmd(0x06);
- chThdSleepMicroseconds(50);
-
- return TRUE;
-}
-
-void tdisp_lld_clear(void) {
- write_cmd(0x01);
-}
-
-void tdisp_lld_draw_char(char c) {
- write_data(c);
-}
-
-void tdisp_lld_set_cursor(coord_t col, coord_t row) {
- static const uint8_t row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
-
- /*
- * Short-cut:
- *
- * If x and y = 0 then use the home command.
- *
- * Note: There is probably no advantage as both commands are a single byte
- */
-// if (col == 0 && row == 0) {
-// write_cmd(0x02);
-// return;
-// }
-
- write_cmd(0x80 | (col + row_offsets[row]));
-}
-
-void tdisp_lld_create_char(uint8_t address, uint8_t *charmap) {
- int i;
-
- write_cmd(0x40 | (address << 3));
- for(i = 0; i < CUSTOM_CHAR_YBITS; i++)
- write_data(charmap[i]);
-}
-
-void tdisp_lld_control(uint16_t what, void *value) {
- switch(what) {
- case TDISP_CTRL_BACKLIGHT:
- if ((uint8_t)value)
- displaycontrol |= DISPLAY_ON;
- else
- displaycontrol &= ~DISPLAY_ON;
- write_cmd(0x08 | displaycontrol);
- break;
- case TDISP_CTRL_CURSOR:
- switch((cursorshape)value) {
- case cursorOff:
- displaycontrol &= ~CURSOR_ON;
- break;
- case cursorBlock:
- case cursorUnderline:
- case cursorBar:
- displaycontrol = (displaycontrol | CURSOR_ON) & ~CURSOR_BLINK;
- break;
- case cursorBlinkingBlock:
- case cursorBlinkingUnderline:
- case cursorBlinkingBar:
- default:
- displaycontrol |= (CURSOR_ON | CURSOR_BLINK);
- break;
- }
- write_cmd(0x08 | displaycontrol);
- break;
- }
-}
-
-#endif /* GFX_USE_TDISP */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/tdisp/HD44780/tdisp_lld.c + * @brief TDISP driver subsystem low level driver source for the HD44780 display + * + * @addtogroup TDISP + * @{ + */ + +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if GFX_USE_TDISP /*|| defined(__DOXYGEN__)*/ + +/* Include the hardware interface details */ +#if defined(TDISP_USE_CUSTOM_BOARD) && TDISP_USE_CUSTOM_BOARD + /* Include the user supplied board definitions */ + #include "tdisp_lld_board.h" +#elif defined(BOARD_UNKNOWN) + #include "gdisp_lld_board_unknown.h" +#else + /* Include the user supplied board definitions */ + #include "gdisp_lld_board.h" +#endif + +/* The user may override the default display size */ +#ifndef TDISP_COLUMNS + #define TDISP_COLUMNS 16 +#endif +#ifndef TDISP_ROWS + #define TDISP_ROWS 2 +#endif + +/* Controller Specific Properties */ +#define CUSTOM_CHAR_COUNT 8 +#define CUSTOM_CHAR_XBITS 5 +#define CUSTOM_CHAR_YBITS 8 + +/* Define the properties of our controller */ +tdispStruct TDISP = { + TDISP_COLUMNS, TDISP_ROWS, /* cols, rows */ + CUSTOM_CHAR_XBITS, CUSTOM_CHAR_YBITS, /* charBitsX, charBitsY */ + CUSTOM_CHAR_COUNT /* maxCustomChars */ + }; + +/* Our display control */ +#define DISPLAY_ON 0x04 +#define CURSOR_ON 0x02 +#define CURSOR_BLINK 0x01 + +static uint8_t displaycontrol; + + +bool_t tdisp_lld_init(void) { + /* initialise hardware */ + init_board(); + + /* wait some time */ + chThdSleepMilliseconds(50); + + write_cmd(0x38); + chThdSleepMilliseconds(64); + + displaycontrol = DISPLAY_ON | CURSOR_ON | CURSOR_BLINK; // The default displaycontrol + write_cmd(0x08 | displaycontrol); + chThdSleepMicroseconds(50); + + write_cmd(0x01); // Clear the screen + chThdSleepMilliseconds(5); + + write_cmd(0x06); + chThdSleepMicroseconds(50); + + return TRUE; +} + +void tdisp_lld_clear(void) { + write_cmd(0x01); +} + +void tdisp_lld_draw_char(char c) { + write_data(c); +} + +void tdisp_lld_set_cursor(coord_t col, coord_t row) { + static const uint8_t row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; + + /* + * Short-cut: + * + * If x and y = 0 then use the home command. + * + * Note: There is probably no advantage as both commands are a single byte + */ +// if (col == 0 && row == 0) { +// write_cmd(0x02); +// return; +// } + + write_cmd(0x80 | (col + row_offsets[row])); +} + +void tdisp_lld_create_char(uint8_t address, uint8_t *charmap) { + int i; + + write_cmd(0x40 | (address << 3)); + for(i = 0; i < CUSTOM_CHAR_YBITS; i++) + write_data(charmap[i]); +} + +void tdisp_lld_control(uint16_t what, void *value) { + switch(what) { + case TDISP_CTRL_BACKLIGHT: + if ((uint8_t)value) + displaycontrol |= DISPLAY_ON; + else + displaycontrol &= ~DISPLAY_ON; + write_cmd(0x08 | displaycontrol); + break; + case TDISP_CTRL_CURSOR: + switch((cursorshape)value) { + case cursorOff: + displaycontrol &= ~CURSOR_ON; + break; + case cursorBlock: + case cursorUnderline: + case cursorBar: + displaycontrol = (displaycontrol | CURSOR_ON) & ~CURSOR_BLINK; + break; + case cursorBlinkingBlock: + case cursorBlinkingUnderline: + case cursorBlinkingBar: + default: + displaycontrol |= (CURSOR_ON | CURSOR_BLINK); + break; + } + write_cmd(0x08 | displaycontrol); + break; + } +} + +#endif /* GFX_USE_TDISP */ +/** @} */ + diff --git a/drivers/tdisp/HD44780/tdisp_lld_board_example.h b/drivers/tdisp/HD44780/tdisp_lld_board_example.h index 37463d37..1b41f0c3 100644 --- a/drivers/tdisp/HD44780/tdisp_lld_board_example.h +++ b/drivers/tdisp/HD44780/tdisp_lld_board_example.h @@ -1,48 +1,61 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file drivers/tdisp/HD44780/tdisp_lld_board_example.h
- * @brief TDISP driver subsystem board interface for the HD44780 display
- *
- * @addtogroup TDISP
- * @{
- */
-
-#ifndef _TDISP_LLD_BOARD_H
-#define _TDISP_LLD_BOARD_H
-
-static void init_board(void) {
- /* Code here */
- #error "tdispHD44780: You must supply a definition for init_board for your board"
-}
-
-static void write_cmd(uint8_t data) {
- /* Code here */
- #error "tdispHD44780: You must supply a definition for write_cmd for your board"
-}
-
-static void write_data(uint8_t data) {
- /* Code here */
- #error "tdispHD44780: You must supply a definition for write_data for your board"
-}
-
-#endif /* _TDISP_LLD_BOARD_H */
-/** @} */
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file drivers/tdisp/HD44780/tdisp_lld_board_example.h + * @brief TDISP driver subsystem board interface for the HD44780 display + * + * @addtogroup TDISP + * @{ + */ + +#ifndef _TDISP_LLD_BOARD_H +#define _TDISP_LLD_BOARD_H + +/** + * The board may override the default display size. + * Uncomment the below if your board needs a non-standard size. + */ +/* +#ifndef TDISP_COLUMNS + #define TDISP_COLUMNS 16 +#endif +#ifndef TDISP_ROWS + #define TDISP_ROWS 2 +#endif +*/ + +static void init_board(void) { + /* Code here */ + #error "tdispHD44780: You must supply a definition for init_board for your board" +} + +static void write_cmd(uint8_t data) { + /* Code here */ + #error "tdispHD44780: You must supply a definition for write_cmd for your board" +} + +static void write_data(uint8_t data) { + /* Code here */ + #error "tdispHD44780: You must supply a definition for write_data for your board" +} + +#endif /* _TDISP_LLD_BOARD_H */ +/** @} */ diff --git a/gfxconf.example.h b/gfxconf.example.h index c601dbb9..389d4db5 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -96,10 +96,8 @@ #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/include/gadc/gadc.h b/include/gadc/gadc.h index 5c490cb9..be7af516 100644 --- a/include/gadc/gadc.h +++ b/include/gadc/gadc.h @@ -1,250 +1,258 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-/**
- * @file include/gadc/gadc.h
- * @brief GADC - Periodic ADC subsystem header file.
- *
- * @addtogroup GADC
- *
- * @details The reason why ChibiOS/GFX has it's own ADC abstraction is because
- * the Chibi-OS drivers are very CPU specific and do not
- * provide a way across all hardware platforms to create periodic
- * ADC conversions. There are also issues with devices with different
- * characteristics or periodic requirements on the same ADC
- * device (but different channels). This layer attempts to solve these
- * problems to provide a architecture neutral API. It also provides extra
- * features such as multi-buffer chaining for high speed ADC sources.
- * It provides one high speed virtual ADC device (eg a microphone) and
- * numerous low speed (less than 100Hz) virtual ADC devices (eg dials,
- * temperature sensors etc). The high speed device has timer based polling
- * to ensure exact conversion periods and a buffer management system.
- * The low speed devices are assumed to be non-critical timing devices
- * and do not have any buffer management.
- * Note that while only one high speed device has been provided it can
- * be used to read multiple physical ADC channels on the one physical
- * ADC device.
- * All callback routines are thread based unlike the Chibi-OS interrupt based
- * routines.
- *
- * @{
- */
-
-#ifndef _GADC_H
-#define _GADC_H
-
-#include "gfx.h"
-
-#if GFX_USE_GADC || defined(__DOXYGEN__)
-
-/* Include the driver defines */
-#include "gadc_lld_config.h"
-
-/*===========================================================================*/
-/* Type definitions */
-/*===========================================================================*/
-
-// Event types for GADC
-#define GEVENT_ADC (GEVENT_GADC_FIRST+0)
-
-/**
- * @brief The High Speed ADC event structure.
- * @{
- */
-typedef struct GEventADC_t {
- /**
- * @brief The type of this event (GEVENT_ADC)
- */
- GEventType type;
- /**
- * @brief The event flags
- */
- uint16_t flags;
- /**
- * @brief The event flag values.
- * @{
- */
- #define GADC_HSADC_LOSTEVENT 0x0001 /**< @brief The last GEVENT_HSDADC event was lost */
- /** @} */
- /**
- * @brief The number of conversions in the buffer
- */
- size_t count;
- /**
- * @brief The buffer containing the conversion samples
- */
- adcsample_t *buffer;
- } GEventADC;
-
-/**
- * @brief A callback function (executed in a thread context)
- */
-typedef void (*GADCCallbackFunction)(adcsample_t *buffer, void *param);
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Initialise the high speed ADC.
- * @details Initialises but does not start the conversions.
- *
- * @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
- * @param[in] frequency The frequency to create ADC conversions
- * @param[in] buffer The static buffer to put the ADC samples into.
- * @param[in] bufcount The total number of conversions that will fit in the buffer.
- * @param[in] countPerEvent The number of conversions to do before returning an event.
- *
- * @note If the high speed ADC is running it will be stopped.
- * @note Due to a bug in Chibi-OS countPerEvent must be even. If bufcount is not
- * evenly divisable by countPerEvent, the remainder must also be even.
- * @note The physdev parameter may be used to turn on more than one ADC channel.
- * Each channel is then interleaved into the provided buffer. Note 'bufcount'
- * and 'countPerEvent' parameters describe the number of conversions not the
- * number of samples.
- * As an example, if physdev turns on 2 devices then the buffer contains
- * alternate device samples and the buffer must contain 2 * bufcount samples.
- * The exact meaning of physdev is hardware dependent.
- * @note The buffer is circular. When the end of the buffer is reached it will start
- * putting data into the beginning of the buffer again.
- * @note The event listener must process the event (and the data in it) before the
- * next event occurs. If not, the following event will be lost.
- * @note If bufcount is evenly divisable by countPerEvent, then every event will return
- * countPerEvent conversions. If bufcount is not evenly divisable, it will return
- * a block of samples containing less than countPerEvent samples when it reaches the
- * end of the buffer.
- * @note While the high speed ADC is running, low speed conversions can only occur at
- * the frequency of the high speed events. Thus if high speed events are
- * being created at 50Hz (eg countPerEvent = 100, frequency = 5kHz) then the maximum
- * frequency for low speed conversions is likely to be 50Hz (although it might be
- * 100Hz on some hardware).
- *
- * @api
- */
-void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer, size_t bufcount, size_t samplesPerEvent);
-
-#if GFX_USE_GEVENT || defined(__DOXYGEN__)
- /**
- * @brief Turn on sending results to the GEVENT sub-system.
- * @details Returns a GSourceHandle to listen for GEVENT_ADC events.
- *
- * @note The high speed ADC will not use the GEVENT system unless this is
- * called first. This saves processing time if the application does
- * not want to use the GEVENT sub-system for the high speed ADC.
- * Once turned on it cannot be turned off.
- * @note The high speed ADC is capable of signalling via this method and a binary semaphore
- * at the same time.
- *
- * @api
- */
- GSourceHandle gadcHighSpeedGetSource(void);
-#endif
-
-/**
- * @brief Allow retrieving of results from the high speed ADC using a Binary Semaphore and a static event buffer.
- *
- * @param[in] pbsem The binary semaphore is signaled when data is available.
- * @param[in] pEvent The static event buffer to place the result information.
- *
- * @note Passing a NULL for pbsem or pEvent will turn off signalling via this method.
- * @note The high speed ADC is capable of signalling via this method and the GEVENT
- * sub-system at the same time.
- *
- * @api
- */
-void gadcHighSpeedSetBSem(BinarySemaphore *pbsem, GEventADC *pEvent);
-
-/**
- * @brief Start the high speed ADC conversions.
- * @pre It must have been initialised first with @p gadcHighSpeedInit()
- *
- * @api
- */
-GSourceHandle gadcHighSpeedStart(void);
-
-/**
- * @brief Stop the high speed ADC conversions.
- *
- * @api
- */
-void gadcHighSpeedStop(void);
-
-/**
- * @brief Perform a single low speed ADC conversion
- * @details Blocks until the conversion is complete
- * @pre This should not be called from within a GTimer callback as this routine
- * blocks until the conversion is ready.
- *
- * @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
- * @param[in] buffer The static buffer to put the ADC samples into.
- *
- * @note This may take a while to complete if the high speed ADC is running as the
- * conversion is interleaved with the high speed ADC conversions on a buffer
- * completion.
- * @note The result buffer must be large enough to store one sample per device
- * described by the 'physdev' parameter.
- * @note If calling this routine would exceed @p GADC_MAX_LOWSPEED_DEVICES simultaneous low
- * speed devices, the routine will wait for an available slot to complete the
- * conversion.
- * @note Specifying more than one device in physdev is possible but discouraged as the
- * calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
- * from over-running the high speed ADC include high speed samples being lost.
- *
- * @api
- */
-void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer);
-
-/**
- * @brief Perform a low speed ADC conversion with callback (in a thread context)
- * @details Returns FALSE if there are no free low speed ADC slots. See @p GADC_MAX_LOWSPEED_DEVICES for details.
- *
- * @param[in] physdev A value passed to describe which physical ADC devices/channels to use.
- * @param[in] buffer The static buffer to put the ADC samples into.
- * @param[in] fn The callback function to call when the conversion is complete.
- * @param[in] param A parameter to pass to the callback function.
- *
- * @note This may be safely called from within a GTimer callback.
- * @note The callback may take a while to occur if the high speed ADC is running as the
- * conversion is interleaved with the high speed ADC conversions on a buffer
- * completion.
- * @note The result buffer must be large enough to store one sample per device
- * described by the 'physdev' parameter.
- * @note As this routine uses a low speed ADC, it asserts if you try to run more than @p GADC_MAX_LOWSPEED_DEVICES
- * at the same time.
- * @note Specifying more than one device in physdev is possible but discouraged as the
- * calculations to ensure the high speed ADC correctness will be incorrect. Symptoms
- * from over-running the high speed ADC include high speed samples being lost.
- *
- * @api
- */
-bool gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GADC */
-
-#endif /* _GADC_H */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ +/** + * @file include/gadc/gadc.h + * @brief GADC - Periodic ADC subsystem header file. + * + * @addtogroup GADC + * + * @details The reason why ChibiOS/GFX has it's own ADC abstraction is because + * the Chibi-OS drivers are very CPU specific and do not + * provide a way across all hardware platforms to create periodic + * ADC conversions. There are also issues with devices with different + * characteristics or periodic requirements on the same ADC + * device (but different channels). This layer attempts to solve these + * problems to provide a architecture neutral API. It also provides extra + * features such as multi-buffer chaining for high speed ADC sources. + * It provides one high speed virtual ADC device (eg a microphone) and + * numerous low speed (less than 100Hz) virtual ADC devices (eg dials, + * temperature sensors etc). The high speed device has timer based polling + * to ensure exact conversion periods and a buffer management system. + * The low speed devices are assumed to be non-critical timing devices + * and do not have any buffer management. + * Note that while only one high speed device has been provided it can + * be used to read multiple physical ADC channels on the one physical + * ADC device. + * All callback routines are thread based unlike the Chibi-OS interrupt based + * routines. + * + * @{ + */ + +#ifndef _GADC_H +#define _GADC_H + +#include "gfx.h" + +#if GFX_USE_GADC || defined(__DOXYGEN__) + +/* Include the driver defines */ +#include "gadc_lld_config.h" + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +// Event types for GADC +#define GEVENT_ADC (GEVENT_GADC_FIRST+0) + +/** + * @brief The High Speed ADC event structure. + * @{ + */ +typedef struct GEventADC_t { + #if GFX_USE_GEVENT || defined(__DOXYGEN__) + /** + * @brief The type of this event (GEVENT_ADC) + */ + GEventType type; + #endif + + /** + * @brief The event flags + */ + uint16_t flags; + /** + * @brief The event flag values. + * @{ + */ + #define GADC_HSADC_LOSTEVENT 0x0001 /**< @brief The last GEVENT_HSDADC event was lost */ + /** @} */ + /** + * @brief The number of conversions in the buffer + */ + size_t count; + /** + * @brief The buffer containing the conversion samples + */ + adcsample_t *buffer; + } GEventADC; + +/** + * @brief A callback function (executed in a thread context) + */ +typedef void (*GADCCallbackFunction)(adcsample_t *buffer, void *param); + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialise the high speed ADC. + * @details Initialises but does not start the conversions. + * + * @param[in] physdev A value passed to describe which physical ADC devices/channels to use. + * @param[in] frequency The frequency to create ADC conversions + * @param[in] buffer The static buffer to put the ADC samples into. + * @param[in] bufcount The total number of conversions that will fit in the buffer. + * @param[in] countPerEvent The number of conversions to do before returning an event. + * + * @note If the high speed ADC is running it will be stopped. The Event subsystem is + * disconnected from the high speed ADC and any binary semaphore event is forgotten. + * @note bufcount must be greater than countPerEvent (usually 2 or more times) otherwise + * the buffer will be overwitten with new data while the application is still trying + * to process the old data. + * @note Due to a bug in Chibi-OS countPerEvent must be even. If bufcount is not + * evenly divisable by countPerEvent, the remainder must also be even. + * @note The physdev parameter may be used to turn on more than one ADC channel. + * Each channel is then interleaved into the provided buffer. Note 'bufcount' + * and 'countPerEvent' parameters describe the number of conversions not the + * number of samples. + * As an example, if physdev turns on 2 devices then the buffer contains + * alternate device samples and the buffer must contain 2 * bufcount samples. + * The exact meaning of physdev is hardware dependent. + * @note The buffer is circular. When the end of the buffer is reached it will start + * putting data into the beginning of the buffer again. + * @note The event listener must process the event (and the data in it) before the + * next event occurs. If not, the following event will be lost. + * @note If bufcount is evenly divisable by countPerEvent, then every event will return + * countPerEvent conversions. If bufcount is not evenly divisable, it will return + * a block of samples containing less than countPerEvent samples when it reaches the + * end of the buffer. + * @note While the high speed ADC is running, low speed conversions can only occur at + * the frequency of the high speed events. Thus if high speed events are + * being created at 50Hz (eg countPerEvent = 100, frequency = 5kHz) then the maximum + * frequency for low speed conversions is likely to be 50Hz (although it might be + * 100Hz on some hardware). + * + * @api + */ +void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer, size_t bufcount, size_t samplesPerEvent); + +#if GFX_USE_GEVENT || defined(__DOXYGEN__) + /** + * @brief Turn on sending results to the GEVENT sub-system. + * @details Returns a GSourceHandle to listen for GEVENT_ADC events. + * + * @note The high speed ADC will not use the GEVENT system unless this is + * called first. This saves processing time if the application does + * not want to use the GEVENT sub-system for the high speed ADC. + * Once turned on it can only be turned off by calling @p gadcHighSpeedInit() again. + * @note The high speed ADC is capable of signalling via this method and a binary semaphore + * at the same time. + * + * @api + */ + GSourceHandle gadcHighSpeedGetSource(void); +#endif + +/** + * @brief Allow retrieving of results from the high speed ADC using a Binary Semaphore and a static event buffer. + * + * @param[in] pbsem The binary semaphore is signaled when data is available. + * @param[in] pEvent The static event buffer to place the result information. + * + * @note Passing a NULL for pbsem or pEvent will turn off signalling via this method as will calling + * @p gadcHighSpeedInit(). + * @note The high speed ADC is capable of signalling via this method and the GEVENT + * sub-system at the same time. + * + * @api + */ +void gadcHighSpeedSetBSem(BinarySemaphore *pbsem, GEventADC *pEvent); + +/** + * @brief Start the high speed ADC conversions. + * @pre It must have been initialised first with @p gadcHighSpeedInit() + * + * @api + */ +void gadcHighSpeedStart(void); + +/** + * @brief Stop the high speed ADC conversions. + * + * @api + */ +void gadcHighSpeedStop(void); + +/** + * @brief Perform a single low speed ADC conversion + * @details Blocks until the conversion is complete + * @pre This should not be called from within a GTimer callback as this routine + * blocks until the conversion is ready. + * + * @param[in] physdev A value passed to describe which physical ADC devices/channels to use. + * @param[in] buffer The static buffer to put the ADC samples into. + * + * @note This may take a while to complete if the high speed ADC is running as the + * conversion is interleaved with the high speed ADC conversions on a buffer + * completion. + * @note The result buffer must be large enough to store one sample per device + * described by the 'physdev' parameter. + * @note If calling this routine would exceed @p GADC_MAX_LOWSPEED_DEVICES simultaneous low + * speed devices, the routine will wait for an available slot to complete the + * conversion. + * @note Specifying more than one device in physdev is possible but discouraged as the + * calculations to ensure the high speed ADC correctness will be incorrect. Symptoms + * from over-running the high speed ADC include high speed samples being lost. + * + * @api + */ +void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer); + +/** + * @brief Perform a low speed ADC conversion with callback (in a thread context) + * @details Returns FALSE if there are no free low speed ADC slots. See @p GADC_MAX_LOWSPEED_DEVICES for details. + * + * @param[in] physdev A value passed to describe which physical ADC devices/channels to use. + * @param[in] buffer The static buffer to put the ADC samples into. + * @param[in] fn The callback function to call when the conversion is complete. + * @param[in] param A parameter to pass to the callback function. + * + * @note This may be safely called from within a GTimer callback. + * @note The callback may take a while to occur if the high speed ADC is running as the + * conversion is interleaved with the high speed ADC conversions on a buffer + * completion. + * @note The result buffer must be large enough to store one sample per device + * described by the 'physdev' parameter. + * @note As this routine uses a low speed ADC, it asserts if you try to run more than @p GADC_MAX_LOWSPEED_DEVICES + * at the same time. + * @note Specifying more than one device in physdev is possible but discouraged as the + * calculations to ensure the high speed ADC correctness will be incorrect. Symptoms + * from over-running the high speed ADC include high speed samples being lost. + * + * @api + */ +bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GADC */ + +#endif /* _GADC_H */ +/** @} */ + diff --git a/include/gadc/lld/gadc_lld.h b/include/gadc/lld/gadc_lld.h new file mode 100644 index 00000000..f9cc8b47 --- /dev/null +++ b/include/gadc/lld/gadc_lld.h @@ -0,0 +1,190 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ +/** + * @file include/gadc/lld/gadc_lld.h + * @brief GADC - Periodic ADC driver header file. + * + * @defgroup Driver Driver + * @ingroup GADC + * @{ + */ + +#ifndef _GADC_LLD_H +#define _GADC_LLD_H + +#include "gfx.h" + +#if GFX_USE_GADC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +/** + * @brief The structure passed to start a timer conversion + * @note We use the structure instead of parameters purely to save + * interrupt stack space which is very limited in some platforms. + * @{ + */ +typedef struct GadcLldTimerData_t { + uint32_t physdev; /* @< A value passed to describe which physical ADC devices/channels to use. */ + adcsample_t *buffer; /* @< The static buffer to put the ADC samples into. */ + size_t count; /* @< The number of conversions to do before doing a callback and stopping the ADC. */ + bool_t now; /* @< Trigger the first conversion now rather than waiting for the first timer interrupt (if possible) */ + } GadcLldTimerData; +/* @} */ + +/** + * @brief The structure passed to start a non-timer conversion + * @note We use the structure instead of parameters purely to save + * interrupt stack space which is very limited in some platforms. + * @{ + */ +typedef struct GadcLldNonTimerData_t { + uint32_t physdev; /* @< A value passed to describe which physical ADC devices/channels to use. */ + adcsample_t *buffer; /* @< The static buffer to put the ADC samples into. */ + } GadcLldNonTimerData; +/* @} */ + +/** + * @brief These routines are the callbacks that the driver uses. + * @details Defined in the high level GADC code. + * + * @notapi + * @{ + */ +extern void GADC_ISR_CompleteI(ADCDriver *adcp, adcsample_t *buffer, size_t n); +extern void GADC_ISR_ErrorI(ADCDriver *adcp, adcerror_t err); +/** + * @} + */ + +/** + * @brief This can be incremented by the low level driver if a timer interrupt is missed. + * @details Defined in the high level GADC code. + * + * @notapi + */ +extern volatile bool_t GADC_Timer_Missed; + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialise the driver + * + * @api + */ +void gadc_lld_init(void); + +/** + * @brief Get the number of samples in a conversion. + * @details Calculates and returns the number of samples per conversion for the specified physdev. + * + * @param[in] physdev A value passed to describe which physical ADC devices/channels to use. + * + * @note A physdev describing a mono device would return 1, a stereo device would return 2. + * For most ADC's physdev is a bitmap so it is only a matter of counting the bits. + * + * @api + */ +size_t gadc_lld_samples_per_conversion(uint32_t physdev); + +/** + * @brief Start a periodic timer for high frequency conversions. + * + * @param[in] physdev A value passed to describe which physical ADC devices/channels to use. + * @param[in] frequency The frequency to create ADC conversions + * + * @note The exact meaning of physdev is hardware dependent. It describes the channels + * the will be used later on when a "timer" conversion is actually scheduled. + * @note It is assumed that the timer is capable of free-running even when the ADC + * is stopped or doing something else. + * @details When a timer interrupt occurs a conversion should start if these is a "timer" conversion + * active. + * @note If the ADC is stopped, doesn't have a "timer" conversion active or is currently executing + * a non-timer conversion then the interrupt can be ignored other than (optionally) incrementing + * the GADC_Timer_Missed variable. + * + * @api + */ +void gadc_lld_start_timer(uint32_t physdev, uint32_t frequency); + +/** + * @brief Stop the periodic timer for high frequency conversions. + * @details Also stops any current "timer" conversion (but not a current "non-timer" conversion). + * + * @param[in] physdev A value passed to describe which physical ADC devices/channels in use. + * + * @note The exact meaning of physdev is hardware dependent. + * + * @api + */ +void gadc_lld_stop_timer(uint32_t physdev); + +/** + * @brief Start a "timer" conversion. + * @details Starts a series of conversions triggered by the timer. + * + * @param[in] pgtd Contains the parameters for the timer conversion. + * + * @note The exact meaning of physdev is hardware dependent. It is likely described in the + * drivers gadc_lld_config.h + * @note Some versions of ChibiOS actually call the callback function more than once, once + * at the half-way point and once on completion. The high level code handles this. + * @note The driver should call @p GADC_ISR_CompleteI() when it completes the operation + * (or at the half-way point), or @p GAD_ISR_ErrorI() on an error. + * @note The high level code ensures that this is not called while a non-timer conversion is in + * progress + * + * @iclass + */ +void gadc_lld_adc_timerI(GadcLldTimerData *pgtd); + +/** + * @brief Start a "non-timer" conversion. + * @details Starts a single conversion now. + * + * @param[in] pgntd Contains the parameters for the non-timer conversion. + * + * @note The exact meaning of physdev is hardware dependent. It is likely described in the + * drivers gadc_lld_config.h + * @note The driver should call @p GADC_ISR_CompleteI() when it completes the operation + * or @p GAD_ISR_ErrorI() on an error. + * @note The high level code ensures that this is not called while a timer conversion is in + * progress + * + * @iclass + */ +void gadc_lld_adc_nontimerI(GadcLldNonTimerData *pgntd); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GADC */ + +#endif /* _GADC_LLD_H */ +/** @} */ diff --git a/include/gadc/options.h b/include/gadc/options.h index dc5bd300..87708efe 100644 --- a/include/gadc/options.h +++ b/include/gadc/options.h @@ -1,57 +1,55 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file include/gadc/options.h
- * @brief GADC - Periodic ADC subsystem options header file.
- *
- * @addtogroup GADC
- * @{
- */
-
-#ifndef _GADC_OPTIONS_H
-#define _GADC_OPTIONS_H
-
-/**
- * @name GADC Functionality to be included
- * @{
- */
-/**
- * @}
- *
- * @name GADC Optional Sizing Parameters
- * @{
- */
- /**
- * @brief The maximum simultaneous GADC low speed device conversions
- * @details Defaults to 4
- * @note This value must be less than the number of conversions that can occur
- * in a single high speed ADC cycle including the high speed ADC conversion.
- * For example, if the ADC can run at 132k samples per second and the high speed
- * virtual ADC is using 44kHz then GADC_MAX_LOWSPEED_DEVICES should be set to
- * 132/44 - 1 = 2
- */
- #ifndef GADC_MAX_LOWSPEED_DEVICES
- #define GADC_MAX_LOWSPEED_DEVICES 4
- #endif
-/** @} */
-
-#endif /* _GADC_OPTIONS_H */
-/** @} */
+/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file include/gadc/options.h + * @brief GADC - Periodic ADC subsystem options header file. + * + * @addtogroup GADC + * @{ + */ + +#ifndef _GADC_OPTIONS_H +#define _GADC_OPTIONS_H + +/** + * @name GADC Functionality to be included + * @{ + */ +/** + * @} + * + * @name GADC Optional Sizing Parameters + * @{ + */ + /** + * @brief The maximum GADC sample rate + * @details Defaults to 44000 + * @note This value must be less than half the maximum sample rate allowed by the CPU. + * This is to ensure there is time between high speed samples to perform low + * speed device sampling. + */ + #ifndef GADC_MAX_HIGH_SPEED_SAMPLERATE + #define GADC_MAX_HIGH_SPEED_SAMPLERATE 44000 + #endif +/** @} */ + +#endif /* _GADC_OPTIONS_H */ +/** @} */ diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h index b2e6df53..0e51a5d8 100644 --- a/include/gdisp/gdisp.h +++ b/include/gdisp/gdisp.h @@ -1,291 +1,291 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file include/gdisp/gdisp.h
- * @brief GDISP Graphic Driver subsystem header file.
- *
- * @addtogroup GDISP
- *
- * @details The GDISP module provides high level abstraction to interface pixel oriented graphic displays.
- *
- * @pre GFX_USE_GDISP must be set to TRUE in gfxconf.h
- *
- * @{
- */
-
-#ifndef _GDISP_H
-#define _GDISP_H
-
-#include "gfx.h"
-
-/* This type definition is defined here as it gets used in other gfx sub-systems even
- * if GFX_USE_GDISP is FALSE.
- */
-
-/**
- * @brief The type for a coordinate or length on the screen.
- */
-typedef int16_t coord_t;
-
-#if GFX_USE_GDISP || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver constants. */
-/*===========================================================================*/
-
-/**
- * @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)
-/** @} */
-
-/*===========================================================================*/
-/* Low Level Driver details and error checks. */
-/*===========================================================================*/
-
-/* Include the low level driver information */
-#include "gdisp/lld/gdisp_lld.h"
-
-/*===========================================================================*/
-/* Type definitions */
-/*===========================================================================*/
-
-/**
- * @brief Type for the text justification.
- */
-typedef enum justify {justifyLeft, justifyCenter, justifyRight} justify_t;
-/**
- * @brief Type for the font metric.
- */
-typedef enum fontmetric {fontHeight, fontDescendersHeight, fontLineSpacing, fontCharPadding, fontMinWidth, fontMaxWidth} fontmetric_t;
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#if (GDISP_NEED_TEXT && GDISP_OLD_FONT_DEFINITIONS) || defined(__DOXYGEN__)
- #if GDISP_INCLUDE_FONT_SMALL
- extern const struct font fontSmall;
- extern const struct font fontSmallDouble;
- extern const struct font fontSmallNarrow;
- #endif
- #if GDISP_INCLUDE_FONT_LARGER
- extern const struct font fontLarger;
- extern const struct font fontLargerDouble;
- extern const struct font fontLargerNarrow;
- #endif
- #if GDISP_INCLUDE_FONT_UI1
- extern const struct font fontUI1;
- extern const struct font fontUI1Double;
- extern const struct font fontUI1Narrow;
- #endif
- #if GDISP_INCLUDE_FONT_UI2
- extern const struct font fontUI2;
- extern const struct font fontUI2Double;
- extern const struct font fontUI2Narrow;
- #endif
- #if GDISP_INCLUDE_FONT_LARGENUMBERS
- extern const struct font fontLargeNumbers;
- extern const struct font fontLargeNumbersDouble;
- extern const struct font fontLargeNumbersNarrow;
- #endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC
- /* 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 */
- bool_t gdispInit(void);
- bool_t gdispIsBusy(void);
-
- /* Drawing Functions */
- void gdispClear(color_t color);
- void gdispDrawPixel(coord_t x, coord_t y, color_t color);
- void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color);
- void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
- 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
- void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy);
- #endif
-
- /* Circle Functions */
- #if GDISP_NEED_CIRCLE
- void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color);
- void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color);
- #endif
-
- /* Ellipse Functions */
- #if GDISP_NEED_ELLIPSE
- void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
- void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
- #endif
-
- /* Arc Functions */
- #if GDISP_NEED_ARC
- void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
- void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
- #endif
-
- /* Basic Text Rendering Functions */
- #if GDISP_NEED_TEXT
- void gdispDrawChar(coord_t x, coord_t y, char c, font_t font, color_t color);
- void gdispFillChar(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor);
- #endif
-
- /* Read a pixel Function */
- #if GDISP_NEED_PIXELREAD
- color_t gdispGetPixelColor(coord_t x, coord_t y);
- #endif
-
- /* Scrolling Function - clears the area scrolled out */
- #if GDISP_NEED_SCROLL
- 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
- void gdispControl(unsigned what, void *value);
- #endif
-
- /* Query driver specific data */
- void *gdispQuery(unsigned what);
-
-#else
-
- /* The same as above but use the low level driver directly if no multi-thread support is needed */
- #define gdispInit(gdisp) lld_gdisp_init()
- #define gdispIsBusy() FALSE
- #define gdispClear(color) lld_gdisp_clear(color)
- #define gdispDrawPixel(x, y, color) lld_gdisp_draw_pixel(x, y, color)
- #define gdispDrawLine(x0, y0, x1, y1, color) lld_gdisp_draw_line(x0, y0, x1, y1, color)
- #define gdispFillArea(x, y, cx, cy, color) lld_gdisp_fill_area(x, y, cx, cy, color)
- #define gdispBlitAreaEx(x, y, cx, cy, sx, sy, scx, buf) lld_gdisp_blit_area_ex(x, y, cx, cy, sx, sy, scx, buf)
- #define gdispSetClip(x, y, cx, cy) lld_gdisp_set_clip(x, y, cx, cy)
- #define gdispDrawCircle(x, y, radius, color) lld_gdisp_draw_circle(x, y, radius, color)
- #define gdispFillCircle(x, y, radius, color) lld_gdisp_fill_circle(x, y, radius, color)
- #define gdispDrawArc(x, y, radius, sangle, eangle, color) lld_gdisp_draw_arc(x, y, radius, sangle, eangle, color)
- #define gdispFillArc(x, y, radius, sangle, eangle, color) lld_gdisp_fill_arc(x, y, radius, sangle, eangle, color)
- #define gdispDrawEllipse(x, y, a, b, color) lld_gdisp_draw_ellipse(x, y, a, b, color)
- #define gdispFillEllipse(x, y, a, b, color) lld_gdisp_fill_ellipse(x, y, a, b, color)
- #define gdispDrawChar(x, y, c, font, color) lld_gdisp_draw_char(x, y, c, font, color)
- #define gdispFillChar(x, y, c, font, color, bgcolor) lld_gdisp_fill_char(x, y, c, font, color, bgcolor)
- #define gdispGetPixelColor(x, y) lld_gdisp_get_pixel_color(x, y)
- #define gdispVerticalScroll(x, y, cx, cy, lines, bgcolor) lld_gdisp_vertical_scroll(x, y, cx, cy, lines, bgcolor)
- #define gdispControl(what, value) lld_gdisp_control(what, value)
- #define gdispQuery(what) lld_gdisp_query(what)
-
-#endif
-
-/* These routines are not hardware accelerated
- * - Do not add a hardware accelerated routines here.
- */
-
-/* Extra drawing functions */
-void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
-
-/* Extra Text Functions */
-#if GDISP_NEED_TEXT
- void gdispDrawString(coord_t x, coord_t y, const char *str, font_t font, color_t color);
- void gdispFillString(coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor);
- 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 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);
- coord_t gdispGetFontMetric(font_t font, fontmetric_t metric);
- coord_t gdispGetCharWidth(char c, font_t font);
- coord_t gdispGetStringWidth(const char* str, font_t font);
- font_t gdispOpenFont(const char *name);
- void gdispCloseFont(font_t font);
- const char *gdispGetFontName(font_t font);
-#endif
-
-/* Extra Arc Functions */
-#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 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 */
-#ifndef gdispPackPixels
- void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color);
-#endif
-
-/*
- * Macro definitions
- */
-
-/* Now obsolete functions */
-#define gdispBlitArea(x, y, cx, cy, buffer) gdispBlitAreaEx(x, y, cx, cy, 0, 0, cx, buffer)
-
-/* Macro definitions for common gets and sets */
-#define gdispSetPowerMode(powerMode) gdispControl(GDISP_CONTROL_POWER, (void *)(unsigned)(powerMode))
-#define gdispSetOrientation(newOrientation) gdispControl(GDISP_CONTROL_ORIENTATION, (void *)(unsigned)(newOrientation))
-#define gdispSetBacklight(percent) gdispControl(GDISP_CONTROL_BACKLIGHT, (void *)(unsigned)(percent))
-#define gdispSetContrast(percent) gdispControl(GDISP_CONTROL_CONTRAST, (void *)(unsigned)(percent))
-
-#define gdispGetWidth() ((coord_t)(unsigned)gdispQuery(GDISP_QUERY_WIDTH))
-#define gdispGetHeight() ((coord_t)(unsigned)gdispQuery(GDISP_QUERY_HEIGHT))
-#define gdispGetPowerMode() ((gdisp_powermode_t)(unsigned)gdispQuery(GDISP_QUERY_POWER))
-#define gdispGetOrientation() ((gdisp_orientation_t)(unsigned)gdispQuery(GDISP_QUERY_ORIENTATION))
-#define gdispGetBacklight() ((coord_t)(unsigned)gdispQuery(GDISP_QUERY_BACKLIGHT))
-#define gdispGetContrast() ((coord_t)(unsigned)gdispQuery(GDISP_QUERY_CONTRAST))
-
-/* More interesting macro's */
-#define gdispUnsetClip() gdispSetClip(0,0,gdispGetWidth(),gdispGetHeight())
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GDISP */
-
-#endif /* _GDISP_H */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file include/gdisp/gdisp.h + * @brief GDISP Graphic Driver subsystem header file. + * + * @addtogroup GDISP + * + * @details The GDISP module provides high level abstraction to interface pixel oriented graphic displays. + * + * @pre GFX_USE_GDISP must be set to TRUE in gfxconf.h + * + * @{ + */ + +#ifndef _GDISP_H +#define _GDISP_H + +#include "gfx.h" + +/* This type definition is defined here as it gets used in other gfx sub-systems even + * if GFX_USE_GDISP is FALSE. + */ + +/** + * @brief The type for a coordinate or length on the screen. + */ +typedef int16_t coord_t; + +#if GFX_USE_GDISP || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @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) +/** @} */ + +/*===========================================================================*/ +/* Low Level Driver details and error checks. */ +/*===========================================================================*/ + +/* Include the low level driver information */ +#include "gdisp/lld/gdisp_lld.h" + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +/** + * @brief Type for the text justification. + */ +typedef enum justify {justifyLeft, justifyCenter, justifyRight} justify_t; +/** + * @brief Type for the font metric. + */ +typedef enum fontmetric {fontHeight, fontDescendersHeight, fontLineSpacing, fontCharPadding, fontMinWidth, fontMaxWidth} fontmetric_t; + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (GDISP_NEED_TEXT && GDISP_OLD_FONT_DEFINITIONS) || defined(__DOXYGEN__) + #if GDISP_INCLUDE_FONT_SMALL + extern const struct font fontSmall; + extern const struct font fontSmallDouble; + extern const struct font fontSmallNarrow; + #endif + #if GDISP_INCLUDE_FONT_LARGER + extern const struct font fontLarger; + extern const struct font fontLargerDouble; + extern const struct font fontLargerNarrow; + #endif + #if GDISP_INCLUDE_FONT_UI1 + extern const struct font fontUI1; + extern const struct font fontUI1Double; + extern const struct font fontUI1Narrow; + #endif + #if GDISP_INCLUDE_FONT_UI2 + extern const struct font fontUI2; + extern const struct font fontUI2Double; + extern const struct font fontUI2Narrow; + #endif + #if GDISP_INCLUDE_FONT_LARGENUMBERS + extern const struct font fontLargeNumbers; + extern const struct font fontLargeNumbersDouble; + extern const struct font fontLargeNumbersNarrow; + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC + /* 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 */ + bool_t gdispInit(void); + bool_t gdispIsBusy(void); + + /* Drawing Functions */ + void gdispClear(color_t color); + void gdispDrawPixel(coord_t x, coord_t y, color_t color); + void gdispDrawLine(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); + void gdispFillArea(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); + 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 + void gdispSetClip(coord_t x, coord_t y, coord_t cx, coord_t cy); + #endif + + /* Circle Functions */ + #if GDISP_NEED_CIRCLE + void gdispDrawCircle(coord_t x, coord_t y, coord_t radius, color_t color); + void gdispFillCircle(coord_t x, coord_t y, coord_t radius, color_t color); + #endif + + /* Ellipse Functions */ + #if GDISP_NEED_ELLIPSE + void gdispDrawEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + void gdispFillEllipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color); + #endif + + /* Arc Functions */ + #if GDISP_NEED_ARC + void gdispDrawArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + void gdispFillArc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color); + #endif + + /* Basic Text Rendering Functions */ + #if GDISP_NEED_TEXT + void gdispDrawChar(coord_t x, coord_t y, char c, font_t font, color_t color); + void gdispFillChar(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor); + #endif + + /* Read a pixel Function */ + #if GDISP_NEED_PIXELREAD + color_t gdispGetPixelColor(coord_t x, coord_t y); + #endif + + /* Scrolling Function - clears the area scrolled out */ + #if GDISP_NEED_SCROLL + 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 + void gdispControl(unsigned what, void *value); + #endif + + /* Query driver specific data */ + void *gdispQuery(unsigned what); + +#else + + /* The same as above but use the low level driver directly if no multi-thread support is needed */ + #define gdispInit(gdisp) gdisp_lld_init() + #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 gdispDrawChar(x, y, c, font, color) gdisp_lld_draw_char(x, y, c, font, color) + #define gdispFillChar(x, y, c, font, color, bgcolor) gdisp_lld_fill_char(x, y, c, font, color, bgcolor) + #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. + */ + +/* Extra drawing functions */ +void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color); + +/* Extra Text Functions */ +#if GDISP_NEED_TEXT + void gdispDrawString(coord_t x, coord_t y, const char *str, font_t font, color_t color); + void gdispFillString(coord_t x, coord_t y, const char *str, font_t font, color_t color, color_t bgcolor); + 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 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); + coord_t gdispGetFontMetric(font_t font, fontmetric_t metric); + coord_t gdispGetCharWidth(char c, font_t font); + coord_t gdispGetStringWidth(const char* str, font_t font); + font_t gdispOpenFont(const char *name); + void gdispCloseFont(font_t font); + const char *gdispGetFontName(font_t font); +#endif + +/* Extra Arc Functions */ +#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 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 */ +#ifndef gdispPackPixels + void gdispPackPixels(const pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color); +#endif + +/* + * Macro definitions + */ + +/* Now obsolete functions */ +#define gdispBlitArea(x, y, cx, cy, buffer) gdispBlitAreaEx(x, y, cx, cy, 0, 0, cx, buffer) + +/* Macro definitions for common gets and sets */ +#define gdispSetPowerMode(powerMode) gdispControl(GDISP_CONTROL_POWER, (void *)(unsigned)(powerMode)) +#define gdispSetOrientation(newOrientation) gdispControl(GDISP_CONTROL_ORIENTATION, (void *)(unsigned)(newOrientation)) +#define gdispSetBacklight(percent) gdispControl(GDISP_CONTROL_BACKLIGHT, (void *)(unsigned)(percent)) +#define gdispSetContrast(percent) gdispControl(GDISP_CONTROL_CONTRAST, (void *)(unsigned)(percent)) + +#define gdispGetWidth() ((coord_t)(unsigned)gdispQuery(GDISP_QUERY_WIDTH)) +#define gdispGetHeight() ((coord_t)(unsigned)gdispQuery(GDISP_QUERY_HEIGHT)) +#define gdispGetPowerMode() ((gdisp_powermode_t)(unsigned)gdispQuery(GDISP_QUERY_POWER)) +#define gdispGetOrientation() ((gdisp_orientation_t)(unsigned)gdispQuery(GDISP_QUERY_ORIENTATION)) +#define gdispGetBacklight() ((coord_t)(unsigned)gdispQuery(GDISP_QUERY_BACKLIGHT)) +#define gdispGetContrast() ((coord_t)(unsigned)gdispQuery(GDISP_QUERY_CONTRAST)) + +/* More interesting macro's */ +#define gdispUnsetClip() gdispSetClip(0,0,gdispGetWidth(),gdispGetHeight()) + + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_H */ +/** @} */ + diff --git a/include/gdisp/lld/emulation.c b/include/gdisp/lld/emulation.c index 86301ed5..ecabc3fd 100644 --- a/include/gdisp/lld/emulation.c +++ b/include/gdisp/lld/emulation.c @@ -1,772 +1,772 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @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 /*|| defined(__DOXYGEN__) */
-
-#ifndef GDISP_LLD_NO_STRUCT
- static struct GDISPDriver {
- 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
- } GDISP;
-#endif
-
-#if !GDISP_HARDWARE_CLEARS
- void lld_gdisp_clear(color_t color) {
- lld_gdisp_fill_area(0, 0, GDISP.Width, GDISP.Height, color);
- }
-#endif
-
-#if !GDISP_HARDWARE_LINES
- void lld_gdisp_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)
- lld_gdisp_fill_area(x0, y0, 1, y1-y0+1, color);
- else
- lld_gdisp_fill_area(x0, y1, 1, y0-y1+1, color);
- return;
- }
- if (y0 == y1) {
- if (x1 > x0)
- lld_gdisp_fill_area(x0, y0, x1-x0+1, 1, color);
- else
- lld_gdisp_fill_area(x0, y1, 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) {
- lld_gdisp_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) {
- lld_gdisp_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 lld_gdisp_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {
- #if GDISP_HARDWARE_SCROLL
- lld_gdisp_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++)
- lld_gdisp_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++)
- lld_gdisp_draw_pixel(x, y, color);
- #endif
- }
-#endif
-
-#if !GDISP_HARDWARE_BITFILLS
- void lld_gdisp_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++)
- lld_gdisp_draw_pixel(x, y, *buffer++);
- }
-#endif
-
-#if GDISP_NEED_CLIP && !GDISP_HARDWARE_CLIP
- void lld_gdisp_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 lld_gdisp_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 {
- lld_gdisp_draw_pixel(x+a, y+b, color);
- lld_gdisp_draw_pixel(x+b, y+a, color);
- lld_gdisp_draw_pixel(x-a, y+b, color);
- lld_gdisp_draw_pixel(x-b, y+a, color);
- lld_gdisp_draw_pixel(x+b, y-a, color);
- lld_gdisp_draw_pixel(x+a, y-b, color);
- lld_gdisp_draw_pixel(x-a, y-b, color);
- lld_gdisp_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 lld_gdisp_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 {
- lld_gdisp_draw_line(x-a, y+b, x+a, y+b, color);
- lld_gdisp_draw_line(x-a, y-b, x+a, y-b, color);
- lld_gdisp_draw_line(x-b, y+a, x+b, y+a, color);
- lld_gdisp_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 lld_gdisp_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 {
- lld_gdisp_draw_pixel(x+dx, y+dy, color); /* I. Quadrant */
- lld_gdisp_draw_pixel(x-dx, y+dy, color); /* II. Quadrant */
- lld_gdisp_draw_pixel(x-dx, y-dy, color); /* III. Quadrant */
- lld_gdisp_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) */
- lld_gdisp_draw_pixel(x+dx, y, color); /* -> Spitze der Ellipse vollenden */
- lld_gdisp_draw_pixel(x-dx, y, color);
- }
- }
-#endif
-
-#if GDISP_NEED_ELLIPSE && !GDISP_HARDWARE_ELLIPSEFILLS
- void lld_gdisp_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 {
- lld_gdisp_draw_line(x-dx,y+dy,x+dx,y+dy, color);
- lld_gdisp_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) */
- lld_gdisp_draw_pixel(x+dx, y, color); /* -> Spitze der Ellipse vollenden */
- lld_gdisp_draw_pixel(x-dx, y, color);
- }
- }
-#endif
-
-#if GDISP_NEED_ARC && !GDISP_HARDWARE_ARCS
-
- #include <math.h>
-
- /*
- * @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)
- lld_gdisp_draw_pixel(x-a, y-b, color);
- if(x+a <= x_maxI && x+a >= x_minI)
- lld_gdisp_draw_pixel(x+a, y-b, color);
- if(x-b <= x_maxI && x-b >= x_minI)
- lld_gdisp_draw_pixel(x-b, y-a, color);
- if(x+b <= x_maxI && x+b >= x_minI)
- lld_gdisp_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)
- lld_gdisp_draw_pixel(x-a, y+b, color);
- if(x+a <= x_maxII && x+a >= x_minII)
- lld_gdisp_draw_pixel(x+a, y+b, color);
- if(x-b <= x_maxII && x-b >= x_minII)
- lld_gdisp_draw_pixel(x-b, y+a, color);
- if(x+b <= x_maxII && x+b >= x_minII)
- lld_gdisp_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 lld_gdisp_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)
- lld_gdisp_draw_line(x, y, x-a, y-b, color);
- if(x+a <= x_maxI && x+a >= x_minI)
- lld_gdisp_draw_line(x, y, x+a, y-b, color);
- if(x-b <= x_maxI && x-b >= x_minI)
- lld_gdisp_draw_line(x, y, x-b, y-a, color);
- if(x+b <= x_maxI && x+b >= x_minI)
- lld_gdisp_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)
- lld_gdisp_draw_line(x, y, x-a, y+b, color);
- if(x+a <= x_maxII && x+a >= x_minII)
- lld_gdisp_draw_line(x, y, x+a, y+b, color);
- if(x-b <= x_maxII && x-b >= x_minII)
- lld_gdisp_draw_line(x, y, x-b, y+a, color);
- if(x+b <= x_maxII && x+b >= x_minII)
- lld_gdisp_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 lld_gdisp_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_TEXT && !GDISP_HARDWARE_TEXT
- #include "gdisp/fonts.h"
-#endif
-
-#if GDISP_NEED_TEXT && !GDISP_HARDWARE_TEXT
- void lld_gdisp_draw_char(coord_t x, coord_t y, char c, font_t font, color_t color) {
- const fontcolumn_t *ptr;
- fontcolumn_t column;
- coord_t width, height, xscale, yscale;
- coord_t i, j, xs, ys;
-
- /* Check we actually have something to print */
- width = _getCharWidth(font, c);
- if (!width) return;
-
- xscale = font->xscale;
- yscale = font->yscale;
- height = font->height * yscale;
- width *= xscale;
-
- ptr = _getCharData(font, c);
-
- /* Loop through the data and display. The font data is LSBit first, down the column */
- for(i=0; i < width; i+=xscale) {
- /* Get the font bitmap data for the column */
- column = *ptr++;
-
- /* Draw each pixel */
- for(j=0; j < height; j+=yscale, column >>= 1) {
- if (column & 0x01) {
- for(xs=0; xs < xscale; xs++)
- for(ys=0; ys < yscale; ys++)
- lld_gdisp_draw_pixel(x+i+xs, y+j+ys, color);
- }
- }
- }
- }
-#endif
-
-#if GDISP_NEED_TEXT && !GDISP_HARDWARE_TEXTFILLS
- void lld_gdisp_fill_char(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor) {
- coord_t width, height;
- coord_t xscale, yscale;
-
- /* Check we actually have something to print */
- width = _getCharWidth(font, c);
- if (!width) return;
-
- xscale = font->xscale;
- yscale = font->yscale;
- height = font->height * yscale;
- width *= xscale;
-
- /* Method 1: Use background fill and then draw the text */
- #if GDISP_HARDWARE_TEXT || GDISP_SOFTWARE_TEXTFILLDRAW
-
- /* Fill the area */
- lld_gdisp_fill_area(x, y, width, height, bgcolor);
-
- /* Draw the text */
- lld_gdisp_draw_char(x, y, c, font, color);
-
- /* Method 2: Create a single column bitmap and then blit it */
- #elif GDISP_HARDWARE_BITFILLS && GDISP_SOFTWARE_TEXTBLITCOLUMN
- {
- const fontcolumn_t *ptr;
- fontcolumn_t column;
- coord_t i, j, xs, ys;
-
- /* Working buffer for fast non-transparent text rendering [patch by Badger]
- This needs to be larger than the largest character we can print.
- Assume the max is double sized by one column.
- */
- static pixel_t buf[sizeof(fontcolumn_t)*8*2];
-
- #if GDISP_NEED_VALIDATION
- /* Check our buffer is big enough */
- if ((unsigned)height > sizeof(buf)/sizeof(buf[0])) return;
- #endif
-
- ptr = _getCharData(font, c);
-
- /* Loop through the data and display. The font data is LSBit first, down the column */
- for(i = 0; i < width; i+=xscale) {
- /* Get the font bitmap data for the column */
- column = *ptr++;
-
- /* Draw each pixel */
- for(j = 0; j < height; j+=yscale, column >>= 1) {
- if (column & 0x01) {
- for(ys=0; ys < yscale; ys++)
- gdispPackPixels(buf, 1, j+ys, 0, color);
- } else {
- for(ys=0; ys < yscale; ys++)
- gdispPackPixels(buf, 1, j+ys, 0, bgcolor);
- }
- }
-
- for(xs=0; xs < xscale; xs++)
- lld_gdisp_blit_area_ex(x+i+xs, y, 1, height, 0, 0, 1, buf);
- }
- }
-
- /* Method 3: Create a character bitmap and then blit it */
- #elif GDISP_HARDWARE_BITFILLS
- {
- const fontcolumn_t *ptr;
- fontcolumn_t column;
- coord_t i, j, xs, ys;
-
- /* Working buffer for fast non-transparent text rendering [patch by Badger]
- This needs to be larger than the largest character we can print.
- Assume the max is double sized.
- */
- static pixel_t buf[20*(sizeof(fontcolumn_t)*8)*2];
-
- #if GDISP_NEED_VALIDATION
- /* Check our buffer is big enough */
- if ((unsigned)(width * height) > sizeof(buf)/sizeof(buf[0])) return;
- #endif
-
- ptr = _getCharData(font, c);
-
- /* Loop through the data and display. The font data is LSBit first, down the column */
- for(i = 0; i < width; i+=xscale) {
- /* Get the font bitmap data for the column */
- column = *ptr++;
-
- /* Draw each pixel */
- for(j = 0; j < height; j+=yscale, column >>= 1) {
- if (column & 0x01) {
- for(xs=0; xs < xscale; xs++)
- for(ys=0; ys < yscale; ys++)
- gdispPackPixels(buf, width, i+xs, j+ys, color);
- } else {
- for(xs=0; xs < xscale; xs++)
- for(ys=0; ys < yscale; ys++)
- gdispPackPixels(buf, width, i+xs, j+ys, bgcolor);
- }
- }
- }
-
- /* [Patch by Badger] Write all in one stroke */
- lld_gdisp_blit_area_ex(x, y, width, height, 0, 0, width, buf);
- }
-
- /* Method 4: Draw pixel by pixel */
- #else
- {
- const fontcolumn_t *ptr;
- fontcolumn_t column;
- coord_t i, j, xs, ys;
-
- ptr = _getCharData(font, c);
-
- /* Loop through the data and display. The font data is LSBit first, down the column */
- for(i = 0; i < width; i+=xscale) {
- /* Get the font bitmap data for the column */
- column = *ptr++;
-
- /* Draw each pixel */
- for(j = 0; j < height; j+=yscale, column >>= 1) {
- if (column & 0x01) {
- for(xs=0; xs < xscale; xs++)
- for(ys=0; ys < yscale; ys++)
- lld_gdisp_draw_pixel(x+i+xs, y+j+ys, color);
- } else {
- for(xs=0; xs < xscale; xs++)
- for(ys=0; ys < yscale; ys++)
- lld_gdisp_draw_pixel(x+i+xs, y+j+ys, bgcolor);
- }
- }
- }
- }
- #endif
- }
-#endif
-
-
-#if GDISP_NEED_CONTROL && !GDISP_HARDWARE_CONTROL
- void lld_gdisp_control(unsigned what, void *value) {
- (void)what;
- (void)value;
- /* Ignore everything */
- }
-#endif
-
-#if !GDISP_HARDWARE_QUERY
-void *lld_gdisp_query(unsigned what) {
- switch(what) {
- case GDISP_QUERY_WIDTH: return (void *)(unsigned)GDISP.Width;
- case GDISP_QUERY_HEIGHT: return (void *)(unsigned)GDISP.Height;
- case GDISP_QUERY_POWER: return (void *)(unsigned)GDISP.Powermode;
- case GDISP_QUERY_ORIENTATION: return (void *)(unsigned)GDISP.Orientation;
- case GDISP_QUERY_BACKLIGHT: return (void *)(unsigned)GDISP.Backlight;
- case GDISP_QUERY_CONTRAST: return (void *)(unsigned)GDISP.Contrast;
- default: return (void *)-1;
- }
-}
-#endif
-
-#if GDISP_NEED_MSGAPI
- void lld_gdisp_msg_dispatch(gdisp_lld_msg_t *msg) {
- switch(msg->action) {
- case GDISP_LLD_MSG_NOP:
- break;
- case GDISP_LLD_MSG_INIT:
- lld_gdisp_init();
- break;
- case GDISP_LLD_MSG_CLEAR:
- lld_gdisp_clear(msg->clear.color);
- break;
- case GDISP_LLD_MSG_DRAWPIXEL:
- lld_gdisp_draw_pixel(msg->drawpixel.x, msg->drawpixel.y, msg->drawpixel.color);
- break;
- case GDISP_LLD_MSG_FILLAREA:
- lld_gdisp_fill_area(msg->fillarea.x, msg->fillarea.y, msg->fillarea.cx, msg->fillarea.cy, msg->fillarea.color);
- break;
- case GDISP_LLD_MSG_BLITAREA:
- lld_gdisp_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:
- lld_gdisp_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:
- lld_gdisp_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:
- lld_gdisp_draw_circle(msg->drawcircle.x, msg->drawcircle.y, msg->drawcircle.radius, msg->drawcircle.color);
- break;
- case GDISP_LLD_MSG_FILLCIRCLE:
- lld_gdisp_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:
- lld_gdisp_draw_ellipse(msg->drawellipse.x, msg->drawellipse.y, msg->drawellipse.a, msg->drawellipse.b, msg->drawellipse.color);
- break;
- case GDISP_LLD_MSG_FILLELLIPSE:
- lld_gdisp_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:
- lld_gdisp_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:
- lld_gdisp_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_TEXT
- case GDISP_LLD_MSG_DRAWCHAR:
- lld_gdisp_draw_char(msg->drawchar.x, msg->drawchar.y, msg->drawchar.c, msg->drawchar.font, msg->drawchar.color);
- break;
- case GDISP_LLD_MSG_FILLCHAR:
- lld_gdisp_fill_char(msg->fillchar.x, msg->fillchar.y, msg->fillchar.c, msg->fillchar.font, msg->fillchar.color, msg->fillchar.bgcolor);
- break;
- #endif
- #if GDISP_NEED_PIXELREAD
- case GDISP_LLD_MSG_GETPIXELCOLOR:
- msg->getpixelcolor.result = lld_gdisp_get_pixel_color(msg->getpixelcolor.x, msg->getpixelcolor.y);
- break;
- #endif
- #if GDISP_NEED_SCROLL
- case GDISP_LLD_MSG_VERTICALSCROLL:
- lld_gdisp_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:
- lld_gdisp_control(msg->control.what, msg->control.value);
- break;
- #endif
- case GDISP_LLD_MSG_QUERY:
- msg->query.result = lld_gdisp_query(msg->query.what);
- break;
- }
- }
-#endif
-
-#endif /* GFX_USE_GDISP */
-#endif /* GDISP_EMULATION_C */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @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 /*|| defined(__DOXYGEN__) */ + +#ifndef GDISP_LLD_NO_STRUCT + static struct GDISPDriver { + 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 + } GDISP; +#endif + +#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(x0, y1, 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 <math.h> + + /* + * @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_TEXT && !GDISP_HARDWARE_TEXT + #include "gdisp/fonts.h" +#endif + +#if GDISP_NEED_TEXT && !GDISP_HARDWARE_TEXT + void gdisp_lld_draw_char(coord_t x, coord_t y, char c, font_t font, color_t color) { + const fontcolumn_t *ptr; + fontcolumn_t column; + coord_t width, height, xscale, yscale; + coord_t i, j, xs, ys; + + /* Check we actually have something to print */ + width = _getCharWidth(font, c); + if (!width) return; + + xscale = font->xscale; + yscale = font->yscale; + height = font->height * yscale; + width *= xscale; + + ptr = _getCharData(font, c); + + /* Loop through the data and display. The font data is LSBit first, down the column */ + for(i=0; i < width; i+=xscale) { + /* Get the font bitmap data for the column */ + column = *ptr++; + + /* Draw each pixel */ + for(j=0; j < height; j+=yscale, column >>= 1) { + if (column & 0x01) { + for(xs=0; xs < xscale; xs++) + for(ys=0; ys < yscale; ys++) + gdisp_lld_draw_pixel(x+i+xs, y+j+ys, color); + } + } + } + } +#endif + +#if GDISP_NEED_TEXT && !GDISP_HARDWARE_TEXTFILLS + void gdisp_lld_fill_char(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor) { + coord_t width, height; + coord_t xscale, yscale; + + /* Check we actually have something to print */ + width = _getCharWidth(font, c); + if (!width) return; + + xscale = font->xscale; + yscale = font->yscale; + height = font->height * yscale; + width *= xscale; + + /* Method 1: Use background fill and then draw the text */ + #if GDISP_HARDWARE_TEXT || GDISP_SOFTWARE_TEXTFILLDRAW + + /* Fill the area */ + gdisp_lld_fill_area(x, y, width, height, bgcolor); + + /* Draw the text */ + gdisp_lld_draw_char(x, y, c, font, color); + + /* Method 2: Create a single column bitmap and then blit it */ + #elif GDISP_HARDWARE_BITFILLS && GDISP_SOFTWARE_TEXTBLITCOLUMN + { + const fontcolumn_t *ptr; + fontcolumn_t column; + coord_t i, j, xs, ys; + + /* Working buffer for fast non-transparent text rendering [patch by Badger] + This needs to be larger than the largest character we can print. + Assume the max is double sized by one column. + */ + static pixel_t buf[sizeof(fontcolumn_t)*8*2]; + + #if GDISP_NEED_VALIDATION + /* Check our buffer is big enough */ + if ((unsigned)height > sizeof(buf)/sizeof(buf[0])) return; + #endif + + ptr = _getCharData(font, c); + + /* Loop through the data and display. The font data is LSBit first, down the column */ + for(i = 0; i < width; i+=xscale) { + /* Get the font bitmap data for the column */ + column = *ptr++; + + /* Draw each pixel */ + for(j = 0; j < height; j+=yscale, column >>= 1) { + if (column & 0x01) { + for(ys=0; ys < yscale; ys++) + gdispPackPixels(buf, 1, j+ys, 0, color); + } else { + for(ys=0; ys < yscale; ys++) + gdispPackPixels(buf, 1, j+ys, 0, bgcolor); + } + } + + for(xs=0; xs < xscale; xs++) + gdisp_lld_blit_area_ex(x+i+xs, y, 1, height, 0, 0, 1, buf); + } + } + + /* Method 3: Create a character bitmap and then blit it */ + #elif GDISP_HARDWARE_BITFILLS + { + const fontcolumn_t *ptr; + fontcolumn_t column; + coord_t i, j, xs, ys; + + /* Working buffer for fast non-transparent text rendering [patch by Badger] + This needs to be larger than the largest character we can print. + Assume the max is double sized. + */ + static pixel_t buf[20*(sizeof(fontcolumn_t)*8)*2]; + + #if GDISP_NEED_VALIDATION + /* Check our buffer is big enough */ + if ((unsigned)(width * height) > sizeof(buf)/sizeof(buf[0])) return; + #endif + + ptr = _getCharData(font, c); + + /* Loop through the data and display. The font data is LSBit first, down the column */ + for(i = 0; i < width; i+=xscale) { + /* Get the font bitmap data for the column */ + column = *ptr++; + + /* Draw each pixel */ + for(j = 0; j < height; j+=yscale, column >>= 1) { + if (column & 0x01) { + for(xs=0; xs < xscale; xs++) + for(ys=0; ys < yscale; ys++) + gdispPackPixels(buf, width, i+xs, j+ys, color); + } else { + for(xs=0; xs < xscale; xs++) + for(ys=0; ys < yscale; ys++) + gdispPackPixels(buf, width, i+xs, j+ys, bgcolor); + } + } + } + + /* [Patch by Badger] Write all in one stroke */ + gdisp_lld_blit_area_ex(x, y, width, height, 0, 0, width, buf); + } + + /* Method 4: Draw pixel by pixel */ + #else + { + const fontcolumn_t *ptr; + fontcolumn_t column; + coord_t i, j, xs, ys; + + ptr = _getCharData(font, c); + + /* Loop through the data and display. The font data is LSBit first, down the column */ + for(i = 0; i < width; i+=xscale) { + /* Get the font bitmap data for the column */ + column = *ptr++; + + /* Draw each pixel */ + for(j = 0; j < height; j+=yscale, column >>= 1) { + if (column & 0x01) { + for(xs=0; xs < xscale; xs++) + for(ys=0; ys < yscale; ys++) + gdisp_lld_draw_pixel(x+i+xs, y+j+ys, color); + } else { + for(xs=0; xs < xscale; xs++) + for(ys=0; ys < yscale; ys++) + gdisp_lld_draw_pixel(x+i+xs, y+j+ys, bgcolor); + } + } + } + } + #endif + } +#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_HARDWARE_QUERY +void *gdisp_lld_query(unsigned what) { + switch(what) { + case GDISP_QUERY_WIDTH: return (void *)(unsigned)GDISP.Width; + case GDISP_QUERY_HEIGHT: return (void *)(unsigned)GDISP.Height; + case GDISP_QUERY_POWER: return (void *)(unsigned)GDISP.Powermode; + case GDISP_QUERY_ORIENTATION: return (void *)(unsigned)GDISP.Orientation; + case GDISP_QUERY_BACKLIGHT: return (void *)(unsigned)GDISP.Backlight; + case GDISP_QUERY_CONTRAST: return (void *)(unsigned)GDISP.Contrast; + default: 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_TEXT + case GDISP_LLD_MSG_DRAWCHAR: + gdisp_lld_draw_char(msg->drawchar.x, msg->drawchar.y, msg->drawchar.c, msg->drawchar.font, msg->drawchar.color); + break; + case GDISP_LLD_MSG_FILLCHAR: + gdisp_lld_fill_char(msg->fillchar.x, msg->fillchar.y, msg->fillchar.c, msg->fillchar.font, msg->fillchar.color, msg->fillchar.bgcolor); + 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 + case GDISP_LLD_MSG_QUERY: + msg->query.result = gdisp_lld_query(msg->query.what); + break; + } + } +#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 da1b29c6..04a0dcf4 100644 --- a/include/gdisp/lld/gdisp_lld.h +++ b/include/gdisp/lld/gdisp_lld.h @@ -1,539 +1,539 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file include/gdisp/lld/lld_gdisp.h
- * @brief GDISP Graphic Driver subsystem low level driver header.
- *
- * @addtogroup GDISP
- * @{
- */
-
-#ifndef _GDISP_LLD_H
-#define _GDISP_LLD_H
-
-#if GFX_USE_GDISP || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Low level driver configuration needs */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Include the low level driver configuration information */
-/*===========================================================================*/
-
-#include "gdisp_lld_config.h"
-
-/*===========================================================================*/
-/* Constants. */
-/*===========================================================================*/
-
-/**
- * @brief Driver Control Constants
- * @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.
- */
-#define GDISP_CONTROL_POWER 0
-#define GDISP_CONTROL_ORIENTATION 1
-#define GDISP_CONTROL_BACKLIGHT 2
-#define GDISP_CONTROL_CONTRAST 3
-#define GDISP_CONTROL_LLD 1000
-
-/**
- * @brief Driver Query Constants
- * @details Unsupported query codes return (void *)-1.
- * @note There are some predefined and some specific to the low level driver.
- * @note The result should be typecast the required type.
- * @note GDISP_QUERY_WIDTH - Gets the width of the screen
- * GDISP_QUERY_HEIGHT - Gets the height of the screen
- * GDISP_QUERY_POWER - Get the current powermode
- * GDISP_QUERY_ORIENTATION - Get the current orientation
- * GDISP_QUERY_BACKLIGHT - Get the backlight state (0 to 100)
- * GDISP_QUERY_CONTRAST - Get the contrast.
- * GDISP_QUERY_LLD - Low level driver control constants start at
- * this value.
- */
-#define GDISP_QUERY_WIDTH 0
-#define GDISP_QUERY_HEIGHT 1
-#define GDISP_QUERY_POWER 2
-#define GDISP_QUERY_ORIENTATION 3
-#define GDISP_QUERY_BACKLIGHT 4
-#define GDISP_QUERY_CONTRAST 5
-#define GDISP_QUERY_LLD 1000
-
-/**
- * @brief Driver Pixel Format Constants
- */
-#define GDISP_PIXELFORMAT_RGB565 565
-#define GDISP_PIXELFORMAT_RGB888 888
-#define GDISP_PIXELFORMAT_RGB444 444
-#define GDISP_PIXELFORMAT_RGB332 332
-#define GDISP_PIXELFORMAT_RGB666 666
-#define GDISP_PIXELFORMAT_CUSTOM 99999
-#define GDISP_PIXELFORMAT_ERROR 88888
-
-/*===========================================================================*/
-/* Error checks. */
-/*===========================================================================*/
-
-/**
- * @name GDISP hardware accelerated support
- * @{
- */
- /**
- * @brief Hardware accelerated line drawing.
- * @details If set to @p FALSE software emulation is used.
- */
- #ifndef GDISP_HARDWARE_LINES
- #define GDISP_HARDWARE_LINES FALSE
- #endif
-
- /**
- * @brief Hardware accelerated screen clears.
- * @details If set to @p FALSE software emulation is used.
- */
- #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 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 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 text drawing.
- * @details If set to @p FALSE software emulation is used.
- */
- #ifndef GDISP_HARDWARE_TEXT
- #define GDISP_HARDWARE_TEXT FALSE
- #endif
-
- /**
- * @brief Hardware accelerated text drawing with a filled background.
- * @details If set to @p FALSE software emulation is used.
- */
- #ifndef GDISP_HARDWARE_TEXTFILLS
- #define GDISP_HARDWARE_TEXTFILLS 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 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 clipping in hardware.
- * @details If set to @p FALSE there is no support for non-standard queries.
- */
- #ifndef GDISP_HARDWARE_CLIP
- #define GDISP_HARDWARE_CLIP FALSE
- #endif
-/** @} */
-
-/**
- * @name GDISP software algorithm choices
- * @{
- */
- /**
- * @brief For filled text drawing, use a background fill and then draw
- * the text instead of using a blit or direct pixel drawing.
- * @details If set to @p TRUE background fill and then text draw is used.
- * @note This is ignored if hardware accelerated text is supported.
- */
- #ifndef GDISP_SOFTWARE_TEXTFILLDRAW
- #define GDISP_SOFTWARE_TEXTFILLDRAW FALSE
- #endif
-
- /**
- * @brief For filled text drawing, when using a bitmap blit
- * use a column by column buffer rather than a full character
- * buffer to save memory at a small performance cost.
- * @details If set to @p TRUE background fill one character column at a time.
- * @note This is ignored if software text using blit is not being used.
- */
- #ifndef GDISP_SOFTWARE_TEXTBLITCOLUMN
- #define GDISP_SOFTWARE_TEXTBLITCOLUMN FALSE
- #endif
-/** @} */
-
-/**
- * @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_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
-/** @} */
-
-/*===========================================================================*/
-/* Define the macro's for the various pixel formats */
-/*===========================================================================*/
-
-#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_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_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
-
-/* 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
-
-/*===========================================================================*/
-/* Driver types. */
-/*===========================================================================*/
-
-/**
- * @brief The type of a pixel.
- */
-typedef color_t pixel_t;
-/**
- * @brief The type of a font.
- */
-typedef const struct font *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;
-/**
- * @brief Type for the available power modes for the screen.
- */
-typedef enum powermode {powerOff, powerSleep, powerDeepSleep, powerOn} gdisp_powermode_t;
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- /* Core functions */
- extern bool_t lld_gdisp_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 lld_gdisp_config.h.
- */
-
- /* Drawing functions */
- extern void lld_gdisp_clear(color_t color);
- extern void lld_gdisp_draw_pixel(coord_t x, coord_t y, color_t color);
- extern void lld_gdisp_fill_area(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color);
- extern void lld_gdisp_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 lld_gdisp_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 lld_gdisp_draw_circle(coord_t x, coord_t y, coord_t radius, color_t color);
- extern void lld_gdisp_fill_circle(coord_t x, coord_t y, coord_t radius, color_t color);
- #endif
-
- #if GDISP_NEED_ELLIPSE
- extern void lld_gdisp_draw_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
- extern void lld_gdisp_fill_ellipse(coord_t x, coord_t y, coord_t a, coord_t b, color_t color);
- #endif
-
- /* Arc Drawing Functions */
- #if GDISP_NEED_ARC
- extern void lld_gdisp_draw_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
- extern void lld_gdisp_fill_arc(coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle, color_t color);
- #endif
-
- /* Text Rendering Functions */
- #if GDISP_NEED_TEXT
- extern void lld_gdisp_draw_char(coord_t x, coord_t y, char c, font_t font, color_t color);
- extern void lld_gdisp_fill_char(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor);
- #endif
-
- /* Pixel readback */
- #if GDISP_NEED_PIXELREAD
- extern color_t lld_gdisp_get_pixel_color(coord_t x, coord_t y);
- #endif
-
- /* Scrolling Function - clears the area scrolled out */
- #if GDISP_NEED_SCROLL
- extern void lld_gdisp_vertical_scroll(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
- extern void lld_gdisp_control(unsigned what, void *value);
- #endif
-
- /* Query driver specific data */
- extern void *lld_gdisp_query(unsigned what);
-
- /* Clipping Functions */
- #if GDISP_NEED_CLIP
- extern void lld_gdisp_set_clip(coord_t x, coord_t y, coord_t cx, coord_t cy);
- #endif
-
- /* Messaging API */
- #if GDISP_NEED_MSGAPI
- #include "lld_gdisp_msgs.h"
- extern void lld_gdisp_msg_dispatch(lld_gdisp_msg_t *msg);
- #endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GFX_USE_GDISP */
-
-#endif /* _GDISP_LLD_H */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file include/gdisp/lld/gdisp_lld.h + * @brief GDISP Graphic Driver subsystem low level driver header. + * + * @addtogroup GDISP + * @{ + */ + +#ifndef _GDISP_LLD_H +#define _GDISP_LLD_H + +#if GFX_USE_GDISP || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Low level driver configuration needs */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Include the low level driver configuration information */ +/*===========================================================================*/ + +#include "gdisp_lld_config.h" + +/*===========================================================================*/ +/* Constants. */ +/*===========================================================================*/ + +/** + * @brief Driver Control Constants + * @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. + */ +#define GDISP_CONTROL_POWER 0 +#define GDISP_CONTROL_ORIENTATION 1 +#define GDISP_CONTROL_BACKLIGHT 2 +#define GDISP_CONTROL_CONTRAST 3 +#define GDISP_CONTROL_LLD 1000 + +/** + * @brief Driver Query Constants + * @details Unsupported query codes return (void *)-1. + * @note There are some predefined and some specific to the low level driver. + * @note The result should be typecast the required type. + * @note GDISP_QUERY_WIDTH - Gets the width of the screen + * GDISP_QUERY_HEIGHT - Gets the height of the screen + * GDISP_QUERY_POWER - Get the current powermode + * GDISP_QUERY_ORIENTATION - Get the current orientation + * GDISP_QUERY_BACKLIGHT - Get the backlight state (0 to 100) + * GDISP_QUERY_CONTRAST - Get the contrast. + * GDISP_QUERY_LLD - Low level driver control constants start at + * this value. + */ +#define GDISP_QUERY_WIDTH 0 +#define GDISP_QUERY_HEIGHT 1 +#define GDISP_QUERY_POWER 2 +#define GDISP_QUERY_ORIENTATION 3 +#define GDISP_QUERY_BACKLIGHT 4 +#define GDISP_QUERY_CONTRAST 5 +#define GDISP_QUERY_LLD 1000 + +/** + * @brief Driver Pixel Format Constants + */ +#define GDISP_PIXELFORMAT_RGB565 565 +#define GDISP_PIXELFORMAT_RGB888 888 +#define GDISP_PIXELFORMAT_RGB444 444 +#define GDISP_PIXELFORMAT_RGB332 332 +#define GDISP_PIXELFORMAT_RGB666 666 +#define GDISP_PIXELFORMAT_CUSTOM 99999 +#define GDISP_PIXELFORMAT_ERROR 88888 + +/*===========================================================================*/ +/* Error checks. */ +/*===========================================================================*/ + +/** + * @name GDISP hardware accelerated support + * @{ + */ + /** + * @brief Hardware accelerated line drawing. + * @details If set to @p FALSE software emulation is used. + */ + #ifndef GDISP_HARDWARE_LINES + #define GDISP_HARDWARE_LINES FALSE + #endif + + /** + * @brief Hardware accelerated screen clears. + * @details If set to @p FALSE software emulation is used. + */ + #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 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 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 text drawing. + * @details If set to @p FALSE software emulation is used. + */ + #ifndef GDISP_HARDWARE_TEXT + #define GDISP_HARDWARE_TEXT FALSE + #endif + + /** + * @brief Hardware accelerated text drawing with a filled background. + * @details If set to @p FALSE software emulation is used. + */ + #ifndef GDISP_HARDWARE_TEXTFILLS + #define GDISP_HARDWARE_TEXTFILLS 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 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 clipping in hardware. + * @details If set to @p FALSE there is no support for non-standard queries. + */ + #ifndef GDISP_HARDWARE_CLIP + #define GDISP_HARDWARE_CLIP FALSE + #endif +/** @} */ + +/** + * @name GDISP software algorithm choices + * @{ + */ + /** + * @brief For filled text drawing, use a background fill and then draw + * the text instead of using a blit or direct pixel drawing. + * @details If set to @p TRUE background fill and then text draw is used. + * @note This is ignored if hardware accelerated text is supported. + */ + #ifndef GDISP_SOFTWARE_TEXTFILLDRAW + #define GDISP_SOFTWARE_TEXTFILLDRAW FALSE + #endif + + /** + * @brief For filled text drawing, when using a bitmap blit + * use a column by column buffer rather than a full character + * buffer to save memory at a small performance cost. + * @details If set to @p TRUE background fill one character column at a time. + * @note This is ignored if software text using blit is not being used. + */ + #ifndef GDISP_SOFTWARE_TEXTBLITCOLUMN + #define GDISP_SOFTWARE_TEXTBLITCOLUMN FALSE + #endif +/** @} */ + +/** + * @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_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 +/** @} */ + +/*===========================================================================*/ +/* Define the macro's for the various pixel formats */ +/*===========================================================================*/ + +#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_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_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 + +/* 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 + +/*===========================================================================*/ +/* Driver types. */ +/*===========================================================================*/ + +/** + * @brief The type of a pixel. + */ +typedef color_t pixel_t; +/** + * @brief The type of a font. + */ +typedef const struct font *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; +/** + * @brief Type for the available power modes for the screen. + */ +typedef enum powermode {powerOff, powerSleep, powerDeepSleep, powerOn} gdisp_powermode_t; + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#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); + #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); + #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); + #endif + + /* Text Rendering Functions */ + #if GDISP_NEED_TEXT + extern void gdisp_lld_draw_char(coord_t x, coord_t y, char c, font_t font, color_t color); + extern void gdisp_lld_fill_char(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor); + #endif + + /* Pixel readback */ + #if GDISP_NEED_PIXELREAD + extern color_t gdisp_lld_get_pixel_color(coord_t x, coord_t y); + #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); + #endif + + /* Set driver specific control */ + #if GDISP_NEED_CONTROL + extern void gdisp_lld_control(unsigned what, void *value); + #endif + + /* Query driver specific data */ + extern void *gdisp_lld_query(unsigned what); + + /* Clipping Functions */ + #if GDISP_NEED_CLIP + extern void gdisp_lld_set_clip(coord_t x, coord_t y, coord_t cx, coord_t cy); + #endif + + /* Messaging API */ + #if GDISP_NEED_MSGAPI + #include "gdisp_lld_msgs.h" + extern void gdisp_lld_msg_dispatch(gdisp_lld_msg_t *msg); + #endif + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_GDISP */ + +#endif /* _GDISP_LLD_H */ +/** @} */ + diff --git a/include/gdisp/lld/gdisp_lld_msgs.h b/include/gdisp/lld/gdisp_lld_msgs.h index 6fe78567..f6055fd5 100644 --- a/include/gdisp/lld/gdisp_lld_msgs.h +++ b/include/gdisp/lld/gdisp_lld_msgs.h @@ -1,193 +1,193 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @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_TEXT
- GDISP_LLD_MSG_DRAWCHAR,
- GDISP_LLD_MSG_FILLCHAR,
- #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 {
- gdisp_msgaction_t action;
- struct gdisp_lld_msg_init {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_INIT
- } init;
- struct gdisp_lld_msg_clear {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_CLEAR
- color_t color;
- } clear;
- struct gdisp_lld_msg_drawpixel {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWPIXEL
- coord_t x, y;
- color_t color;
- } drawpixel;
- struct gdisp_lld_msg_fillarea {
- 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 {
- 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 {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_SETCLIP
- coord_t x, y;
- coord_t cx, cy;
- } setclip;
- struct gdisp_lld_msg_drawline {
- 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 {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWCIRCLE
- coord_t x, y;
- coord_t radius;
- color_t color;
- } drawcircle;
- struct gdisp_lld_msg_fillcircle {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_FILLCIRCLE
- coord_t x, y;
- coord_t radius;
- color_t color;
- } fillcircle;
- struct gdisp_lld_msg_drawellipse {
- 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 {
- 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 {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWARC
- coord_t x, y;
- coord_t radius;
- coord_t startangle, endangle;
- color_t color;
- } drawcircle;
- struct gdisp_lld_msg_fillarc {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_FILLARC
- coord_t x, y;
- coord_t radius;
- coord_t startangle, endangle;
- color_t color;
- } fillcircle;
- struct gdisp_lld_msg_drawchar {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWCHAR
- coord_t x, y;
- char c;
- font_t font;
- color_t color;
- } drawchar;
- struct gdisp_lld_msg_fillchar {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_FILLCHAR
- coord_t x, y;
- char c;
- font_t font;
- color_t color;
- color_t bgcolor;
- } fillchar;
- struct gdisp_lld_msg_getpixelcolor {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_GETPIXELCOLOR
- coord_t x, y;
- color_t result;
- } getpixelcolor;
- struct gdisp_lld_msg_verticalscroll {
- 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 {
- gdisp_msgaction_t action; // GDISP_LLD_MSG_CONTROL
- int what;
- void * value;
- } control;
- struct gdisp_lld_msg_query {
- 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 */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @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_TEXT + GDISP_LLD_MSG_DRAWCHAR, + GDISP_LLD_MSG_FILLCHAR, + #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 { + gdisp_msgaction_t action; + struct gdisp_lld_msg_init { + gdisp_msgaction_t action; // GDISP_LLD_MSG_INIT + } init; + struct gdisp_lld_msg_clear { + gdisp_msgaction_t action; // GDISP_LLD_MSG_CLEAR + color_t color; + } clear; + struct gdisp_lld_msg_drawpixel { + gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWPIXEL + coord_t x, y; + color_t color; + } drawpixel; + struct gdisp_lld_msg_fillarea { + 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 { + 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 { + gdisp_msgaction_t action; // GDISP_LLD_MSG_SETCLIP + coord_t x, y; + coord_t cx, cy; + } setclip; + struct gdisp_lld_msg_drawline { + 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 { + gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWCIRCLE + coord_t x, y; + coord_t radius; + color_t color; + } drawcircle; + struct gdisp_lld_msg_fillcircle { + gdisp_msgaction_t action; // GDISP_LLD_MSG_FILLCIRCLE + coord_t x, y; + coord_t radius; + color_t color; + } fillcircle; + struct gdisp_lld_msg_drawellipse { + 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 { + 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 { + 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 { + 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_drawchar { + gdisp_msgaction_t action; // GDISP_LLD_MSG_DRAWCHAR + coord_t x, y; + char c; + font_t font; + color_t color; + } drawchar; + struct gdisp_lld_msg_fillchar { + gdisp_msgaction_t action; // GDISP_LLD_MSG_FILLCHAR + coord_t x, y; + char c; + font_t font; + color_t color; + color_t bgcolor; + } fillchar; + struct gdisp_lld_msg_getpixelcolor { + gdisp_msgaction_t action; // GDISP_LLD_MSG_GETPIXELCOLOR + coord_t x, y; + color_t result; + } getpixelcolor; + struct gdisp_lld_msg_verticalscroll { + 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 { + gdisp_msgaction_t action; // GDISP_LLD_MSG_CONTROL + int what; + void * value; + } control; + struct gdisp_lld_msg_query { + 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 */ +/** @} */ + diff --git a/include/gfx_rules.h b/include/gfx_rules.h index c132de54..ce6bea50 100644 --- a/include/gfx_rules.h +++ b/include/gfx_rules.h @@ -1,128 +1,136 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file include/gfx_rules.h
- * @brief GFX system safety rules header file.
- *
- * @addtogroup GFX
- * @{
- */
-
-#ifndef _GFX_RULES_H
-#define _GFX_RULES_H
-
-/**
- * Safety checks on all the defines.
- *
- * These are defined in the order of their inter-dependancies.
- */
-
-#if GFX_USE_GWIN
- #if !GFX_USE_GDISP
- #error "GWIN: GFX_USE_GDISP must be TRUE when using GWIN"
- #endif
- #if !GDISP_NEED_CLIP
- #warning "GWIN: Drawing can occur outside the defined windows as GDISP_NEED_CLIP is FALSE"
- #endif
- #if GWIN_NEED_BUTTON
- #if !GDISP_NEED_TEXT
- #error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_BUTTON is TRUE."
- #endif
- #if !GFX_USE_GEVENT
- #warning "GWIN: GFX_USE_GEVENT is required if GWIN_NEED_BUTTON is TRUE. It has been turned on for you."
- #undef GFX_USE_GEVENT
- #define GFX_USE_GEVENT TRUE
- #endif
- #if !GFX_USE_GINPUT || !(GINPUT_NEED_MOUSE || GINPUT_NEED_TOGGLE)
- #warning "GWIN: You have set GWIN_NEED_BUTTON to TRUE but no supported GINPUT (mouse/toggle) devices have been included"
- #endif
- #if !GDISP_NEED_MULTITHREAD && !GDISP_NEED_ASYNC
- #warning "GWIN: Either GDISP_NEED_MULTITHREAD or GDISP_NEED_ASYNC is required if GWIN_NEED_BUTTON is TRUE."
- #warning "GWIN: GDISP_NEED_MULTITHREAD has been turned on for you."
- #undef GDISP_NEED_MULTITHREAD
- #define GDISP_NEED_MULTITHREAD TRUE
- #endif
- #endif
- #if GWIN_NEED_CONSOLE
- #if !GDISP_NEED_TEXT
- #error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_CONSOLE is TRUE."
- #endif
- #endif
- #if GWIN_NEED_GRAPH
- #endif
-#endif
-
-#if GFX_USE_GINPUT
- #if !GFX_USE_GEVENT
- #warning "GINPUT: GFX_USE_GEVENT is required if GFX_USE_GINPUT is TRUE. It has been turned on for you."
- #undef GFX_USE_GEVENT
- #define GFX_USE_GEVENT TRUE
- #endif
- #if !GFX_USE_GTIMER
- #warning "GINPUT: GFX_USE_GTIMER is required if GFX_USE_GINPUT is TRUE. It has been turned on for you."
- #undef GFX_USE_GTIMER
- #define GFX_USE_GTIMER TRUE
- #endif
-#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
- #if !GDISP_NEED_MSGAPI
- #warning "GDISP: Messaging API is required for Async Multi-Thread. It has been turned on for you."
- #undef GDISP_NEED_MSGAPI
- #define GDISP_NEED_MSGAPI TRUE
- #endif
- #endif
-#endif
-
-#if GFX_USE_TDISP
-#endif
-
-#if GFX_USE_GEVENT
- #if !CH_USE_MUTEXES || !CH_USE_SEMAPHORES
- #error "GEVENT: CH_USE_MUTEXES and CH_USE_SEMAPHORES must be defined in chconf.h"
- #endif
-#endif
-
-#if GFX_USE_GTIMER
- #if GFX_USE_GDISP && !GDISP_NEED_MULTITHREAD && !GDISP_NEED_ASYNC
- #warning "GTIMER: Neither GDISP_NEED_MULTITHREAD nor GDISP_NEED_ASYNC has been specified."
- #warning "GTIMER: Make sure you are not performing any GDISP/GWIN drawing operations in the timer callback!"
- #endif
-#endif
-
-#if GFX_USE_GAUDIN
-#endif
-
-#if GFX_USE_GAUDOUT
-#endif
-
-#if GFX_USE_GADC
-#endif
-
-#if GFX_USE_GMISC
-#endif
-
-#endif /* _GFX_H */
-/** @} */
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file include/gfx_rules.h + * @brief GFX system safety rules header file. + * + * @addtogroup GFX + * @{ + */ + +#ifndef _GFX_RULES_H +#define _GFX_RULES_H + +/** + * Safety checks on all the defines. + * + * These are defined in the order of their inter-dependancies. + */ + +#if GFX_USE_GWIN + #if !GFX_USE_GDISP + #error "GWIN: GFX_USE_GDISP must be TRUE when using GWIN" + #endif + #if !GDISP_NEED_CLIP + #warning "GWIN: Drawing can occur outside the defined windows as GDISP_NEED_CLIP is FALSE" + #endif + #if GWIN_NEED_BUTTON + #if !GDISP_NEED_TEXT + #error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_BUTTON is TRUE." + #endif + #if !GFX_USE_GEVENT + #warning "GWIN: GFX_USE_GEVENT is required if GWIN_NEED_BUTTON is TRUE. It has been turned on for you." + #undef GFX_USE_GEVENT + #define GFX_USE_GEVENT TRUE + #endif + #if !GFX_USE_GINPUT || !(GINPUT_NEED_MOUSE || GINPUT_NEED_TOGGLE) + #warning "GWIN: You have set GWIN_NEED_BUTTON to TRUE but no supported GINPUT (mouse/toggle) devices have been included" + #endif + #if !GDISP_NEED_MULTITHREAD && !GDISP_NEED_ASYNC + #warning "GWIN: Either GDISP_NEED_MULTITHREAD or GDISP_NEED_ASYNC is required if GWIN_NEED_BUTTON is TRUE." + #warning "GWIN: GDISP_NEED_MULTITHREAD has been turned on for you." + #undef GDISP_NEED_MULTITHREAD + #define GDISP_NEED_MULTITHREAD TRUE + #endif + #endif + #if GWIN_NEED_CONSOLE + #if !GDISP_NEED_TEXT + #error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_CONSOLE is TRUE." + #endif + #endif + #if GWIN_NEED_GRAPH + #endif +#endif + +#if GFX_USE_GINPUT + #if !GFX_USE_GEVENT + #warning "GINPUT: GFX_USE_GEVENT is required if GFX_USE_GINPUT is TRUE. It has been turned on for you." + #undef GFX_USE_GEVENT + #define GFX_USE_GEVENT TRUE + #endif + #if !GFX_USE_GTIMER + #warning "GINPUT: GFX_USE_GTIMER is required if GFX_USE_GINPUT is TRUE. It has been turned on for you." + #undef GFX_USE_GTIMER + #define GFX_USE_GTIMER TRUE + #endif +#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 + #if !GDISP_NEED_MSGAPI + #warning "GDISP: Messaging API is required for Async Multi-Thread. It has been turned on for you." + #undef GDISP_NEED_MSGAPI + #define GDISP_NEED_MSGAPI TRUE + #endif + #endif +#endif + +#if GFX_USE_TDISP +#endif + +#if GFX_USE_GADC + #if !CH_USE_MUTEXES || !CH_USE_SEMAPHORES + #error "GADC: CH_USE_MUTEXES and CH_USE_SEMAPHORES must be defined in chconf.h" + #endif + #if !GFX_USE_GTIMER + #warning "GADC: GFX_USE_GTIMER is required if GFX_USE_GADC is TRUE. It has been turned on for you." + #undef GFX_USE_GTIMER + #define GFX_USE_GTIMER TRUE + #endif +#endif + +#if GFX_USE_GEVENT + #if !CH_USE_MUTEXES || !CH_USE_SEMAPHORES + #error "GEVENT: CH_USE_MUTEXES and CH_USE_SEMAPHORES must be defined in chconf.h" + #endif +#endif + +#if GFX_USE_GTIMER + #if GFX_USE_GDISP && !GDISP_NEED_MULTITHREAD && !GDISP_NEED_ASYNC + #warning "GTIMER: Neither GDISP_NEED_MULTITHREAD nor GDISP_NEED_ASYNC has been specified." + #warning "GTIMER: Make sure you are not performing any GDISP/GWIN drawing operations in the timer callback!" + #endif +#endif + +#if GFX_USE_GAUDIN +#endif + +#if GFX_USE_GAUDOUT +#endif + +#if GFX_USE_GMISC +#endif + +#endif /* _GFX_H */ +/** @} */ diff --git a/src/gadc/gadc.c b/src/gadc/gadc.c index 5533bb49..509557d3 100644 --- a/src/gadc/gadc.c +++ b/src/gadc/gadc.c @@ -1,38 +1,465 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file src/gadc/gadc.c
- * @brief GADC sub-system code.
- *
- * @addtogroup GADC
- * @{
- */
-#include "ch.h"
-#include "hal.h"
-#include "gfx.h"
-
-#if GFX_USE_GADC || defined(__DOXYGEN__)
-
- #error "GADC: Not implemented yet"
-
-#endif /* GFX_USE_GADC */
-/** @} */
-
+/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file src/gadc/gadc.c + * @brief GADC sub-system code. + * + * @addtogroup GADC + * @{ + */ +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if GFX_USE_GADC + +/* Include the driver defines */ +#include "gadc/lld/gadc_lld.h" + +#if GADC_MAX_HIGH_SPEED_SAMPLERATE > GADC_MAX_SAMPLE_FREQUENCY/2 + #error "GADC: GADC_MAX_HIGH_SPEED_SAMPLERATE has been set too high. It must be less than half the maximum CPU rate" +#endif + +#define GADC_MAX_LOWSPEED_DEVICES ((GADC_MAX_SAMPLE_FREQUENCY/GADC_MAX_HIGH_SPEED_SAMPLERATE)-1) +#if GADC_MAX_LOWSPEED_DEVICES > 4 + #undef GADC_MAX_LOWSPEED_DEVICES + #define GADC_MAX_LOWSPEED_DEVICES 4 +#endif + +volatile bool_t GADC_Timer_Missed; + +static SEMAPHORE_DECL(gadcsem, GADC_MAX_LOWSPEED_DEVICES); +static MUTEX_DECL(gadcmutex); +static GTIMER_DECL(LowSpeedGTimer); +#if GFX_USE_GEVENT + static GTIMER_DECL(HighSpeedGTimer); +#endif + +static volatile uint16_t gflags = 0; + #define GADC_GFLG_INITDONE 0x0001 + #define GADC_GFLG_ISACTIVE 0x0002 + +#define GADC_FLG_ISACTIVE 0x0001 +#define GADC_FLG_ISDONE 0x0002 +#define GADC_FLG_ERROR 0x0004 +#define GADC_FLG_GTIMER 0x0008 + +static struct hsdev { + // Our status flags + uint16_t flags; + + // What we started with + uint32_t frequency; + adcsample_t *buffer; + size_t bufcount; + size_t samplesPerEvent; + + // The last set of results + size_t lastcount; + adcsample_t *lastbuffer; + uint16_t lastflags; + + // Other stuff we need to track progress and for signalling + GadcLldTimerData lld; + size_t samplesPerConversion; + size_t remaining; + BinarySemaphore *bsem; + GEventADC *pEvent; + } hs; + +static struct lsdev { + // Our status flags + uint16_t flags; + + // What we started with + GadcLldNonTimerData lld; + GADCCallbackFunction fn; + void *param; + } ls[GADC_MAX_LOWSPEED_DEVICES]; + +static struct lsdev *curlsdev; + +/* Find the next conversion to activate */ +static __inline void FindNextConversionI(void) { + if (curlsdev) { + /** + * Now we have done a low speed conversion - start looking for the next conversion + * We only look forward to ensure we get a high speed conversion at least once + * every GADC_MAX_LOWSPEED_DEVICES conversions. + */ + curlsdev++; + + } else { + + /* Now we have done a high speed conversion - start looking for low speed conversions */ + curlsdev = ls; + } + + /** + * Look for the next thing to do. + */ + while(curlsdev < &ls[GADC_MAX_LOWSPEED_DEVICES]) { + if ((curlsdev->flags & (GADC_FLG_ISACTIVE|GADC_FLG_ISDONE)) == GADC_FLG_ISACTIVE) { + gadc_lld_adc_nontimerI(&curlsdev->lld); + return; + } + curlsdev++; + } + curlsdev = 0; + + /* No more low speed devices - do a high speed conversion */ + if (hs.flags & GADC_FLG_ISACTIVE) { + hs.lld.now = GADC_Timer_Missed ? TRUE : FALSE; + GADC_Timer_Missed = 0; + gadc_lld_adc_timerI(&hs.lld); + return; + } + + /* Nothing more to do */ + gflags &= ~GADC_GFLG_ISACTIVE; +} + +void GADC_ISR_CompleteI(ADCDriver *adcp, adcsample_t *buffer, size_t n) { + (void) adcp; + + if (curlsdev) { + /* This interrupt must be in relation to the low speed device */ + + if (curlsdev->flags & GADC_FLG_ISACTIVE) { + /** + * As we only handle a single low speed conversion at a time, we know + * we know we won't get any half completion interrupts. + */ + curlsdev->flags |= GADC_FLG_ISDONE; + gtimerJabI(&LowSpeedGTimer); + } + + #if ADC_ISR_FULL_CODE_BUG + /** + * Oops - We have just finished a low speed conversion but a bug prevents us + * restarting the ADC here. Other code will restart it in the thread based + * ADC handler. + */ + gflags &= ~GADC_GFLG_ISACTIVE; + return; + + #endif + + } else { + /* This interrupt must be in relation to the high speed device */ + + if (hs.flags & GADC_FLG_ISACTIVE) { + /* Save the details */ + hs.lastcount = n; + hs.lastbuffer = buffer; + hs.lastflags = GADC_Timer_Missed ? GADC_HSADC_LOSTEVENT : 0; + + /* Signal the user with the data */ + if (hs.pEvent) { + #if GFX_USE_GEVENT + hs.pEvent->type = GEVENT_ADC; + #endif + hs.pEvent->count = hs.lastcount; + hs.pEvent->buffer = hs.lastbuffer; + hs.pEvent->flags = hs.lastflags; + } + if (hs.bsem) + chBSemSignalI(hs.bsem); + + #if GFX_USE_GEVENT + if (hs.flags & GADC_FLG_GTIMER) + gtimerJabI(&HighSpeedGTimer); + #endif + + /* Adjust what we have left to do */ + hs.lld.count -= n; + hs.remaining -= n; + + /* Half completion - We have done all we can for now - wait for the next interrupt */ + if (hs.lld.count) + return; + + /* Our buffer is cyclic - set up the new buffer pointers */ + if (hs.remaining) { + hs.lld.buffer = buffer + (n * hs.samplesPerConversion); + } else { + hs.remaining = hs.bufcount; + hs.lld.buffer = hs.buffer; + } + hs.lld.count = hs.remaining < hs.samplesPerEvent ? hs.remaining : hs.samplesPerEvent; + } + } + + /** + * Look for the next thing to do. + */ + FindNextConversionI(); +} + +void GADC_ISR_ErrorI(ADCDriver *adcp, adcerror_t err) { + (void) adcp; + (void) err; + + if (curlsdev) { + if ((curlsdev->flags & (GADC_FLG_ISACTIVE|GADC_FLG_ISDONE)) == GADC_FLG_ISACTIVE) + /* Mark the error then try to repeat it */ + curlsdev->flags |= GADC_FLG_ERROR; + + #if ADC_ISR_FULL_CODE_BUG + /** + * Oops - We have just finished a low speed conversion but a bug prevents us + * restarting the ADC here. Other code will restart it in the thread based + * ADC handler. + */ + gflags &= ~GADC_GFLG_ISACTIVE; + gtimerJabI(&LowSpeedGTimer); + return; + + #endif + + } else { + if (hs.flags & GADC_FLG_ISACTIVE) + /* Mark the error and then try to repeat it */ + hs.flags |= GADC_FLG_ERROR; + } + + /* Start the next conversion */ + FindNextConversionI(); +} + +static __inline void DoInit(void) { + if (!(gflags & GADC_GFLG_INITDONE)) { + gflags |= GADC_GFLG_INITDONE; + gadc_lld_init(); + } +} + +static __inline void StartADC(bool_t onNoHS) { + chSysLock(); + if (!(gflags & GADC_GFLG_ISACTIVE) || (onNoHS && !curlsdev)) + FindNextConversionI(); + chSysUnlock(); +} + +static void BSemSignalCallback(adcsample_t *buffer, void *param) { + (void) buffer; + + /* Signal the BinarySemaphore parameter */ + chBSemSignal((BinarySemaphore *)param); +} + +#if GFX_USE_GEVENT + static void HighSpeedGTimerCallback(void *param) { + (void) param; + GSourceListener *psl; + GEventADC *pe; + + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)(&HighSpeedGTimer), psl))) { + if (!(pe = (GEventADC *)geventGetEventBuffer(psl))) { + // This listener is missing - save this. + psl->srcflags |= GADC_HSADC_LOSTEVENT; + continue; + } + + pe->type = GEVENT_ADC; + pe->count = hs.lastcount; + pe->buffer = hs.lastbuffer; + pe->flags = hs.lastflags | psl->srcflags; + psl->srcflags = 0; + geventSendEvent(psl); + } + } +#endif + +static void LowSpeedGTimerCallback(void *param) { + (void) param; + GADCCallbackFunction fn; + void *prm; + adcsample_t *buffer; + struct lsdev *p; + + #if ADC_ISR_FULL_CODE_BUG + /* Ensure the ADC is running if it needs to be - Bugfix HACK */ + StartADC(FALSE); + #endif + + /** + * Look for completed low speed timers. + * We don't need to take the mutex as we are the only place that things are freed and we + * do that atomically. + */ + for(p=ls; p < &ls[GADC_MAX_LOWSPEED_DEVICES]; p++) { + if ((p->flags & (GADC_FLG_ISACTIVE|GADC_FLG_ISDONE)) == (GADC_FLG_ISACTIVE|GADC_FLG_ISDONE)) { + /* This item is done - perform its callback */ + fn = p->fn; // Save the callback details + prm = p->param; + buffer = p->lld.buffer; + p->fn = 0; // Needed to prevent the compiler removing the local variables + p->param = 0; // Needed to prevent the compiler removing the local variables + p->lld.buffer = 0; // Needed to prevent the compiler removing the local variables + p->flags = 0; // The slot is available (indivisible operation) + chSemSignal(&gadcsem); // Tell everyone + fn(buffer, prm); // Perform the callback + } + } + +} + +void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency, adcsample_t *buffer, size_t bufcount, size_t samplesPerEvent) +{ + gadcHighSpeedStop(); /* This does the init for us */ + + /* Just save the details and reset everything for now */ + hs.frequency = frequency; + hs.buffer = buffer; + hs.bufcount = bufcount; + hs.samplesPerEvent = samplesPerEvent; + hs.lastcount = 0; + hs.lastbuffer = 0; + hs.lastflags = 0; + hs.lld.physdev = physdev; + hs.lld.buffer = buffer; + hs.lld.count = samplesPerEvent; + hs.lld.now = FALSE; + hs.samplesPerConversion = gadc_lld_samples_per_conversion(physdev); + hs.remaining = bufcount; + hs.bsem = 0; + hs.pEvent = 0; +} + +#if GFX_USE_GEVENT + GSourceHandle gadcHighSpeedGetSource(void) { + DoInit(); + if (!gtimerIsActive(&HighSpeedGTimer)) + gtimerStart(&HighSpeedGTimer, HighSpeedGTimerCallback, NULL, TRUE, TIME_INFINITE); + hs.flags |= GADC_FLG_GTIMER; + return (GSourceHandle)&HighSpeedGTimer; + } +#endif + +void gadcHighSpeedSetBSem(BinarySemaphore *pbsem, GEventADC *pEvent) { + DoInit(); + + /* Use the system lock to ensure they occur atomically */ + chSysLock(); + hs.pEvent = pEvent; + hs.bsem = pbsem; + chSysUnlock(); +} + +void gadcHighSpeedStart(void) { + DoInit(); + + /* If its already going we don't need to do anything */ + if (hs.flags & GADC_FLG_ISACTIVE) + return; + + gadc_lld_start_timer(hs.lld.physdev, hs.frequency); + hs.flags = GADC_FLG_ISACTIVE; + StartADC(FALSE); +} + +void gadcHighSpeedStop(void) { + DoInit(); + + if (hs.flags & GADC_FLG_ISACTIVE) { + /* No more from us */ + hs.flags = 0; + gadc_lld_stop_timer(hs.lld.physdev); + /* + * We have to pass TRUE to StartADC() as we might have the ADC marked as active when it isn't + * due to stopping the timer while it was converting. + */ + StartADC(TRUE); + } +} + +void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer) { + struct lsdev *p; + BSEMAPHORE_DECL(mysem, TRUE); + + /* Start the Low Speed Timer */ + chMtxLock(&gadcmutex); + if (!gtimerIsActive(&LowSpeedGTimer)) + gtimerStart(&LowSpeedGTimer, LowSpeedGTimerCallback, NULL, TRUE, TIME_INFINITE); + chMtxUnlock(); + + while(1) { + /* Wait for an available slot */ + chSemWait(&gadcsem); + + /* Find a slot */ + chMtxLock(&gadcmutex); + for(p = ls; p < &ls[GADC_MAX_LOWSPEED_DEVICES]; p++) { + if (!(p->flags & GADC_FLG_ISACTIVE)) { + p->lld.physdev = physdev; + p->lld.buffer = buffer; + p->fn = BSemSignalCallback; + p->param = &mysem; + p->flags = GADC_FLG_ISACTIVE; + chMtxUnlock(); + StartADC(FALSE); + chBSemWait(&mysem); + return; + } + } + chMtxUnlock(); + + /** + * We should never get here - the count semaphore must be wrong. + * Decrement it and try again. + */ + } +} + +bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param) { + struct lsdev *p; + + DoInit(); + + /* Start the Low Speed Timer */ + chMtxLock(&gadcmutex); + if (!gtimerIsActive(&LowSpeedGTimer)) + gtimerStart(&LowSpeedGTimer, LowSpeedGTimerCallback, NULL, TRUE, TIME_INFINITE); + + /* Find a slot */ + for(p = ls; p < &ls[GADC_MAX_LOWSPEED_DEVICES]; p++) { + if (!(p->flags & GADC_FLG_ISACTIVE)) { + /* We know we have a slot - this should never wait anyway */ + chSemWaitTimeout(&gadcsem, TIME_IMMEDIATE); + p->lld.physdev = physdev; + p->lld.buffer = buffer; + p->fn = fn; + p->param = param; + p->flags = GADC_FLG_ISACTIVE; + chMtxUnlock(); + StartADC(FALSE); + return TRUE; + } + } + chMtxUnlock(); + return FALSE; +} + +#endif /* GFX_USE_GADC */ +/** @} */ + diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c index c8383ff3..620b3c0b 100644 --- a/src/gdisp/gdisp.c +++ b/src/gdisp/gdisp.c @@ -1,1268 +1,1268 @@ -/*
- ChibiOS/GFX - Copyright (C) 2012
- Joel Bodenmann aka Tectu <joel@unormal.org>
-
- This file is part of ChibiOS/GFX.
-
- ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @file src/gdisp/gdisp.c
- * @brief GDISP Driver code.
- *
- * @addtogroup GDISP
- * @{
- */
-#include "ch.h"
-#include "hal.h"
-#include "gfx.h"
-
-#if GFX_USE_GDISP || defined(__DOXYGEN__)
-
-#ifdef GDISP_NEED_TEXT
- #include "gdisp/fonts.h"
-#endif
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#if GDISP_NEED_MULTITHREAD
- #if !CH_USE_MUTEXES
- #error "GDISP: CH_USE_MUTEXES must be defined in chconf.h because GDISP_NEED_MULTITHREAD is defined"
- #endif
-#endif
-
-#if GDISP_NEED_ASYNC
- #if !CH_USE_MAILBOXES || !CH_USE_MUTEXES || !CH_USE_SEMAPHORES
- #error "GDISP: CH_USE_MAILBOXES, CH_USE_SEMAPHORES and CH_USE_MUTEXES must be defined in chconf.h because GDISP_NEED_ASYNC is defined"
- #endif
-#endif
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables. */
-/*===========================================================================*/
-
-#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC
- static Mutex gdispMutex;
-#endif
-
-#if GDISP_NEED_ASYNC
- #define GDISP_THREAD_STACK_SIZE 512 /* Just a number - not yet a reflection of actual use */
- #define GDISP_QUEUE_SIZE 8 /* We only allow a short queue */
-
- static Thread * lldThread;
- static Mailbox gdispMailbox;
- static msg_t gdispMailboxQueue[GDISP_QUEUE_SIZE];
- static Semaphore gdispMsgsSem;
- static Mutex gdispMsgsMutex;
- static gdisp_lld_msg_t gdispMsgs[GDISP_QUEUE_SIZE];
- static WORKING_AREA(waGDISPThread, GDISP_THREAD_STACK_SIZE);
-#endif
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-#if GDISP_NEED_ASYNC
- static msg_t GDISPThreadHandler(void *arg) {
- (void)arg;
- gdisp_lld_msg_t *pmsg;
-
- #if CH_USE_REGISTRY
- chRegSetThreadName("GDISPAsyncAPI");
- #endif
-
- while(1) {
- /* Wait for msg with work to do. */
- chMBFetch(&gdispMailbox, (msg_t *)&pmsg, TIME_INFINITE);
-
- /* OK - we need to obtain the mutex in case a synchronous operation is occurring */
- chMtxLock(&gdispMutex);
- lld_gdisp_msg_dispatch(pmsg);
- chMtxUnlock();
-
- /* Mark the message as free */
- pmsg->action = GDISP_LLD_MSG_NOP;
- chSemSignal(&gdispMsgsSem);
- }
- return 0;
- }
-
- static gdisp_lld_msg_t *gdispAllocMsg(gdisp_msgaction_t action) {
- gdisp_lld_msg_t *p;
-
- while(1) { /* To be sure, to be sure */
-
- /* Wait for a slot */
- chSemWait(&gdispMsgsSem);
-
- /* Find the slot */
- chMtxLock(&gdispMsgsMutex);
- for(p=gdispMsgs; p < &gdispMsgs[GDISP_QUEUE_SIZE]; p++) {
- if (p->action == GDISP_LLD_MSG_NOP) {
- /* Allocate it */
- p->action = action;
- chMtxUnlock();
- return p;
- }
- }
- chMtxUnlock();
-
- /* Oops - none found, try again */
- chSemSignal(&gdispMsgsSem);
- }
- }
-#endif
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__)
- /**
- * @brief GDISP Driver initialization.
- * @note This function is NOT currently implicitly invoked by @p halInit().
- * It must be called manually.
- *
- * @return True if succeeded, False otherwise
- *
- * @init
- */
- bool_t gdispInit(void) {
- bool_t res;
-
- /* Initialise Mutex */
- chMtxInit(&gdispMutex);
-
- /* Initialise driver */
- chMtxLock(&gdispMutex);
- res = lld_gdisp_init();
- chMtxUnlock();
-
- return res;
- }
-#elif GDISP_NEED_ASYNC
- bool_t gdispInit(void) {
- bool_t res;
- unsigned i;
-
- /* Mark all the Messages as free */
- for(i=0; i < GDISP_QUEUE_SIZE; i++)
- gdispMsgs[i].action = GDISP_LLD_MSG_NOP;
-
- /* Initialise our Mailbox, Mutex's and Counting Semaphore.
- * A Mutex is required as well as the Mailbox and Thread because some calls have to be synchronous.
- * Synchronous calls get handled by the calling thread, asynchronous by our worker thread.
- */
- chMBInit(&gdispMailbox, gdispMailboxQueue, sizeof(gdispMailboxQueue)/sizeof(gdispMailboxQueue[0]));
- chMtxInit(&gdispMutex);
- chMtxInit(&gdispMsgsMutex);
- chSemInit(&gdispMsgsSem, GDISP_QUEUE_SIZE);
-
- lldThread = chThdCreateStatic(waGDISPThread, sizeof(waGDISPThread), NORMALPRIO, GDISPThreadHandler, NULL);
-
- /* Initialise driver - synchronous */
- chMtxLock(&gdispMutex);
- res = lld_gdisp_init();
- chMtxUnlock();
-
- return res;
- }
-#endif
-
-#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__)
- /**
- * @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
- *
- * @init
- */
- bool_t gdispIsBusy(void) {
- return FALSE;
- }
-#elif GDISP_NEED_ASYNC
- bool_t gdispIsBusy(void) {
- return chMBGetUsedCountI(&gdispMailbox) != FALSE;
- }
-#endif
-
-#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__)
- /**
- * @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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_clear(color);
- chMtxUnlock();
- }
-#elif GDISP_NEED_ASYNC
- void gdispClear(color_t color) {
- gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_CLEAR);
- p->clear.color = color;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__)
- /**
- * @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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_draw_pixel(x, y, color);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__)
- /**
- * @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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_draw_line(x0, y0, x1, y1, color);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__)
- /**
- * @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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_fill_area(x, y, cx, cy, color);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__)
- /**
- * @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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_blit_area_ex(x, y, cx, cy, srcx, srcy, srccx, buffer);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_CLIP && GDISP_NEED_MULTITHREAD) || 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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_set_clip(x, y, cx, cy);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD) || 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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_draw_circle(x, y, radius, color);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__)
- /**
- * @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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_fill_circle(x, y, radius, color);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD) || 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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_draw_ellipse(x, y, a, b, color);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__)
- /**
- * @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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_fill_ellipse(x, y, a, b, color);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) || 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 start, coord_t end, color_t color) {
- chMtxLock(&gdispMutex);
- lld_gdisp_draw_arc(x, y, radius, start, end, color);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__)
- /*
- * @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 start, coord_t end, color_t color) {
- chMtxLock(&gdispMutex);
- lld_gdisp_fill_arc(x, y, radius, start, end, color);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if GDISP_NEED_ARC || defined(__DOXYGEN__)
-/**
- * @brief Draw a rectangular box with rounded corners
- *
- * @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
- * @param[in] color The color to use
- *
- * @api
- */
-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 || defined(__DOXYGEN__)
-/**
- * @brief Draw a filled rectangular box with rounded corners
- *
- * @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
- * @param[in] color The color to use
- *
- * @api
- */
-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_TEXT && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__)
- /**
- * @brief Draw a text character.
- *
- * @param[in] x,y The position for the text
- * @param[in] c The character to draw
- * @param[in] font The font to use
- * @param[in] color The color to use
- *
- * @api
- */
- void gdispDrawChar(coord_t x, coord_t y, char c, font_t font, color_t color) {
- chMtxLock(&gdispMutex);
- lld_gdisp_draw_char(x, y, c, font, color);
- chMtxUnlock();
- }
-#elif GDISP_NEED_TEXT && GDISP_NEED_ASYNC
- void gdispDrawChar(coord_t x, coord_t y, char c, font_t font, color_t color) {
- gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWCHAR);
- p->drawchar.x = x;
- p->drawchar.y = y;
- p->drawchar.c = c;
- p->drawchar.font = font;
- p->drawchar.color = color;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_TEXT && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__)
- /**
- * @brief Draw a text character with a filled background.
- *
- * @param[in] x,y The position for the text
- * @param[in] c The character to draw
- * @param[in] font The font to use
- * @param[in] color The color to use
- * @param[in] bgcolor The background color to use
- *
- * @api
- */
- void gdispFillChar(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor) {
- chMtxLock(&gdispMutex);
- lld_gdisp_fill_char(x, y, c, font, color, bgcolor);
- chMtxUnlock();
- }
-#elif GDISP_NEED_TEXT && GDISP_NEED_ASYNC
- void gdispFillChar(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor) {
- gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLCHAR);
- p->fillchar.x = x;
- p->fillchar.y = y;
- p->fillchar.c = c;
- p->fillchar.font = font;
- p->fillchar.color = color;
- p->fillchar.bgcolor = bgcolor;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_PIXELREAD && (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC)) || 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) {
- color_t c;
-
- /* Always synchronous as it must return a value */
- chMtxLock(&gdispMutex);
- c = lld_gdisp_get_pixel_color(x, y);
- chMtxUnlock();
-
- return c;
- }
-#endif
-
-#if (GDISP_NEED_SCROLL && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__)
- /**
- * @brief Scroll vertically a section of the screen.
- * @pre GDISP_NEED_SCROLL must be set to TRUE in halconf.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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_vertical_scroll(x, y, cx, cy, lines, bgcolor);
- chMtxUnlock();
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- }
-#endif
-
-#if (GDISP_NEED_CONTROL && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__)
- /**
- * @brief Set the power mode for the display.
- * @pre The GDISP unit must have been initialised using @p gdispInit().
- * @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) {
- chMtxLock(&gdispMutex);
- lld_gdisp_control(what, value);
- chMtxUnlock();
- chThdSleepMilliseconds(100);
- }
-#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;
- chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
- chThdSleepMilliseconds(100);
- }
-#endif
-
-#if (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC) || defined(__DOXYGEN__)
- /**
- * @brief Query a property of the display.
- * @pre The GDISP unit must have been initialised using @p gdispInit().
- * @note The result must be typecast to the correct type.
- * @note An uunsupported query will return (void *)-1.
- *
- * @param[in] what What to query
- *
- * @api
- */
- void *gdispQuery(unsigned what) {
- void *res;
-
- chMtxLock(&gdispMutex);
- res = lld_gdisp_query(what);
- chMtxUnlock();
- return res;
- }
-#endif
-
-/*===========================================================================*/
-/* High Level Driver Routines. */
-/*===========================================================================*/
-
-/**
- * @brief Draw a rectangular box.
- *
- * @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) {
- /* No mutex required as we only call high level functions which have their own mutex */
- coord_t x1, y1;
-
- x1 = x+cx-1;
- y1 = y+cy-1;
-
- 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);
- }
- }
- }
- } 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);
- }
-}
-
-
-#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
- /**
- * @brief Draw a text string.
- *
- * @param[in] x,y The position for the text
- * @param[in] font The font to use
- * @param[in] str The string to draw
- * @param[in] color The color to use
- *
- * @api
- */
- 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 */
- coord_t w, p;
- char c;
- int first;
-
- if (!str) return;
-
- first = 1;
- p = font->charPadding * font->xscale;
- while(*str) {
- /* Get the next printable character */
- c = *str++;
- w = _getCharWidth(font, c) * font->xscale;
- if (!w) continue;
-
- /* Handle inter-character padding */
- if (p) {
- if (!first)
- x += p;
- else
- first = 0;
- }
-
- /* Print the character */
- gdispDrawChar(x, y, c, font, color);
- x += w;
- }
- }
-#endif
-
-#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
- /**
- * @brief Draw a text string.
- *
- * @param[in] x,y The position for the text
- * @param[in] str The string to draw
- * @param[in] font The font to use
- * @param[in] color The color to use
- * @param[in] bgcolor The background color to use
- *
- * @api
- */
- 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 */
- coord_t w, h, p;
- char c;
- int first;
-
- if (!str) return;
-
- first = 1;
- h = font->height * font->yscale;
- p = font->charPadding * font->xscale;
- while(*str) {
- /* Get the next printable character */
- c = *str++;
- w = _getCharWidth(font, c) * font->xscale;
- if (!w) continue;
-
- /* Handle inter-character padding */
- if (p) {
- if (!first) {
- gdispFillArea(x, y, p, h, bgcolor);
- x += p;
- } else
- first = 0;
- }
-
- /* Print the character */
- gdispFillChar(x, y, c, font, color, bgcolor);
- x += w;
- }
- }
-#endif
-
-#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
- /**
- * @brief Draw a text string verticly centered within the specified box.
- *
- * @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
- * @param[in] font The font to use
- * @param[in] color The color to use
- * @param[in] justify Justify the text left, center or right within the box
- *
- * @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) {
- /* No mutex required as we only call high level functions which have their own mutex */
- coord_t w, h, p, ypos, xpos;
- char c;
- int first;
- const char *rstr;
-
- if (!str) str = "";
-
- h = font->height * font->yscale;
- p = font->charPadding * font->xscale;
-
- /* Oops - font too large for the area */
- if (h > cy) return;
-
- /* See if we need to fill above the font */
- ypos = (cy - h + 1)/2;
- if (ypos > 0) {
- y += ypos;
- cy -= ypos;
- }
-
- /* See if we need to fill below the font */
- ypos = cy - h;
- if (ypos > 0)
- cy -= ypos;
-
- /* get the start of the printable string and the xpos */
- switch(justify) {
- case justifyCenter:
- /* Get the length of the entire string */
- w = gdispGetStringWidth(str, font);
- if (w <= cx)
- xpos = x + (cx - w)/2;
- else {
- /* Calculate how much of the string we need to get rid of */
- ypos = (w - cx)/2;
- xpos = 0;
- first = 1;
- while(*str) {
- /* Get the next printable character */
- c = *str++;
- w = _getCharWidth(font, c) * font->xscale;
- if (!w) continue;
-
- /* Handle inter-character padding */
- if (p) {
- if (!first) {
- xpos += p;
- if (xpos > ypos) break;
- } else
- first = 0;
- }
-
- /* Print the character */
- xpos += w;
- if (xpos > ypos) break;
- }
- xpos = ypos - xpos + x;
- }
- break;
- case justifyRight:
- /* Find the end of the string */
- for(rstr = str; *str; str++);
- xpos = x+cx - 2;
- first = 1;
- for(str--; str >= rstr; str--) {
- /* Get the next printable character */
- c = *str;
- w = _getCharWidth(font, c) * font->xscale;
- if (!w) continue;
-
- /* Handle inter-character padding */
- if (p) {
- if (!first) {
- if (xpos - p < x) break;
- xpos -= p;
- } else
- first = 0;
- }
-
- /* Print the character */
- if (xpos - w < x) break;
- xpos -= w;
- }
- str++;
- break;
- case justifyLeft:
- /* Fall through */
- default:
- xpos = x+1;
- break;
- }
-
- /* Print characters until we run out of room */
- first = 1;
- while(*str) {
- /* Get the next printable character */
- c = *str++;
- w = _getCharWidth(font, c) * font->xscale;
- if (!w) continue;
-
- /* Handle inter-character padding */
- if (p) {
- if (!first) {
- if (xpos + p > x+cx) break;
- xpos += p;
- } else
- first = 0;
- }
-
- /* Print the character */
- if (xpos + w > x+cx) break;
- gdispDrawChar(xpos, y, c, font, color);
- xpos += w;
- }
- }
-#endif
-
-#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
- /**
- * @brief Draw a text string verticly centered within the specified box. The box background is filled with the specified background color.
- * @note The entire box is filled
- *
- * @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
- * @param[in] font The font to use
- * @param[in] color The color to use
- * @param[in] bgcolor The background color to use
- * @param[in] justify Justify the text left, center or right within the box
- *
- * @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) {
- /* No mutex required as we only call high level functions which have their own mutex */
- coord_t w, h, p, ypos, xpos;
- char c;
- int first;
- const char *rstr;
-
- if (!str) str = "";
-
- h = font->height * font->yscale;
- p = font->charPadding * font->xscale;
-
- /* Oops - font too large for the area */
- if (h > cy) return;
-
- /* See if we need to fill above the font */
- ypos = (cy - h + 1)/2;
- if (ypos > 0) {
- gdispFillArea(x, y, cx, ypos, bgcolor);
- y += ypos;
- cy -= ypos;
- }
-
- /* See if we need to fill below the font */
- ypos = cy - h;
- if (ypos > 0) {
- gdispFillArea(x, y+cy-ypos, cx, ypos, bgcolor);
- cy -= ypos;
- }
-
- /* get the start of the printable string and the xpos */
- switch(justify) {
- case justifyCenter:
- /* Get the length of the entire string */
- w = gdispGetStringWidth(str, font);
- if (w <= cx)
- xpos = x + (cx - w)/2;
- else {
- /* Calculate how much of the string we need to get rid of */
- ypos = (w - cx)/2;
- xpos = 0;
- first = 1;
- while(*str) {
- /* Get the next printable character */
- c = *str++;
- w = _getCharWidth(font, c) * font->xscale;
- if (!w) continue;
-
- /* Handle inter-character padding */
- if (p) {
- if (!first) {
- xpos += p;
- if (xpos > ypos) break;
- } else
- first = 0;
- }
-
- /* Print the character */
- xpos += w;
- if (xpos > ypos) break;
- }
- xpos = ypos - xpos + x;
- }
- break;
- case justifyRight:
- /* Find the end of the string */
- for(rstr = str; *str; str++);
- xpos = x+cx - 2;
- first = 1;
- for(str--; str >= rstr; str--) {
- /* Get the next printable character */
- c = *str;
- w = _getCharWidth(font, c) * font->xscale;
- if (!w) continue;
-
- /* Handle inter-character padding */
- if (p) {
- if (!first) {
- if (xpos - p < x) break;
- xpos -= p;
- } else
- first = 0;
- }
-
- /* Print the character */
- if (xpos - w < x) break;
- xpos -= w;
- }
- str++;
- break;
- case justifyLeft:
- /* Fall through */
- default:
- xpos = x+1;
- break;
- }
-
- /* Fill any space to the left */
- if (x < xpos)
- gdispFillArea(x, y, xpos-x, cy, bgcolor);
-
- /* Print characters until we run out of room */
- first = 1;
- while(*str) {
- /* Get the next printable character */
- c = *str++;
- w = _getCharWidth(font, c) * font->xscale;
- if (!w) continue;
-
- /* Handle inter-character padding */
- if (p) {
- if (!first) {
- if (xpos + p > x+cx) break;
- gdispFillArea(xpos, y, p, cy, bgcolor);
- xpos += p;
- } else
- first = 0;
- }
-
- /* Print the character */
- if (xpos + w > x+cx) break;
- gdispFillChar(xpos, y, c, font, color, bgcolor);
- xpos += w;
- }
-
- /* Fill any space to the right */
- if (xpos < x+cx)
- gdispFillArea(xpos, y, x+cx-xpos, cy, bgcolor);
- }
-#endif
-
-#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
- /**
- * @brief Get a metric of a font.
- * @return The metric requested in pixels.
- *
- * @param[in] font The font to test
- * @param[in] metric The metric to measure
- *
- * @api
- */
- coord_t gdispGetFontMetric(font_t font, fontmetric_t metric) {
- /* No mutex required as we only read static data */
- switch(metric) {
- case fontHeight: return font->height * font->yscale;
- case fontDescendersHeight: return font->descenderHeight * font->yscale;
- case fontLineSpacing: return font->lineSpacing * font->yscale;
- case fontCharPadding: return font->charPadding * font->xscale;
- case fontMinWidth: return font->minWidth * font->xscale;
- case fontMaxWidth: return font->maxWidth * font->xscale;
- }
- return 0;
- }
-#endif
-
-#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
- /**
- * @brief Get the pixel width of a character.
- * @return The width of the character in pixels. Does not include any between character padding.
- *
- * @param[in] c The character to draw
- * @param[in] font The font to use
- *
- * @api
- */
- coord_t gdispGetCharWidth(char c, font_t font) {
- /* No mutex required as we only read static data */
- return _getCharWidth(font, c) * font->xscale;
- }
-#endif
-
-#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
- /**
- * @brief Get the pixel width of a string.
- * @return The width of the string in pixels.
- *
- * @param[in] str The string to measure
- * @param[in] font The font to use
- *
- * @api
- */
- coord_t gdispGetStringWidth(const char* str, font_t font) {
- /* No mutex required as we only read static data */
- coord_t w, p, x;
- char c;
- int first;
-
- first = 1;
- x = 0;
- p = font->charPadding * font->xscale;
- while(*str) {
- /* Get the next printable character */
- c = *str++;
- w = _getCharWidth(font, c) * font->xscale;
- if (!w) continue;
-
- /* Handle inter-character padding */
- if (p) {
- if (!first)
- x += p;
- else
- first = 0;
- }
-
- /* Add the character width */
- x += w;
- }
- return x;
- }
-#endif
-
-#if (!defined(gdispPackPixels) && !defined(GDISP_PIXELFORMAT_CUSTOM)) || 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(pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color) {
- /* No mutex required as we only read static data */
- #if defined(GDISP_PIXELFORMAT_RGB888)
- #error "GDISP: Packed pixels not supported yet"
- #elif defined(GDISP_PIXELFORMAT_RGB444)
- #error "GDISP: Packed pixels not supported yet"
- #elif defined(GDISP_PIXELFORMAT_RGB666)
- #error "GDISP: Packed pixels not supported yet"
- #elif
- #error "GDISP: Unsupported packed pixel format"
- #endif
- }
-#endif
-
-#endif /* GFX_USE_GDISP */
-/** @} */
+/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu <joel@unormal.org> + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX 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/GFX 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 <http://www.gnu.org/licenses/>. +*/ + +/** + * @file src/gdisp/gdisp.c + * @brief GDISP Driver code. + * + * @addtogroup GDISP + * @{ + */ +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if GFX_USE_GDISP || defined(__DOXYGEN__) + +#ifdef GDISP_NEED_TEXT + #include "gdisp/fonts.h" +#endif + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if GDISP_NEED_MULTITHREAD + #if !CH_USE_MUTEXES + #error "GDISP: CH_USE_MUTEXES must be defined in chconf.h because GDISP_NEED_MULTITHREAD is defined" + #endif +#endif + +#if GDISP_NEED_ASYNC + #if !CH_USE_MAILBOXES || !CH_USE_MUTEXES || !CH_USE_SEMAPHORES + #error "GDISP: CH_USE_MAILBOXES, CH_USE_SEMAPHORES and CH_USE_MUTEXES must be defined in chconf.h because GDISP_NEED_ASYNC is defined" + #endif +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +#if GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC + static Mutex gdispMutex; +#endif + +#if GDISP_NEED_ASYNC + #define GDISP_THREAD_STACK_SIZE 512 /* Just a number - not yet a reflection of actual use */ + #define GDISP_QUEUE_SIZE 8 /* We only allow a short queue */ + + static Thread * lldThread; + static Mailbox gdispMailbox; + static msg_t gdispMailboxQueue[GDISP_QUEUE_SIZE]; + static Semaphore gdispMsgsSem; + static Mutex gdispMsgsMutex; + static gdisp_lld_msg_t gdispMsgs[GDISP_QUEUE_SIZE]; + static WORKING_AREA(waGDISPThread, GDISP_THREAD_STACK_SIZE); +#endif + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if GDISP_NEED_ASYNC + static msg_t GDISPThreadHandler(void *arg) { + (void)arg; + gdisp_lld_msg_t *pmsg; + + #if CH_USE_REGISTRY + chRegSetThreadName("GDISPAsyncAPI"); + #endif + + while(1) { + /* Wait for msg with work to do. */ + chMBFetch(&gdispMailbox, (msg_t *)&pmsg, TIME_INFINITE); + + /* OK - we need to obtain the mutex in case a synchronous operation is occurring */ + chMtxLock(&gdispMutex); + gdisp_lld_msg_dispatch(pmsg); + chMtxUnlock(); + + /* Mark the message as free */ + pmsg->action = GDISP_LLD_MSG_NOP; + chSemSignal(&gdispMsgsSem); + } + return 0; + } + + static gdisp_lld_msg_t *gdispAllocMsg(gdisp_msgaction_t action) { + gdisp_lld_msg_t *p; + + while(1) { /* To be sure, to be sure */ + + /* Wait for a slot */ + chSemWait(&gdispMsgsSem); + + /* Find the slot */ + chMtxLock(&gdispMsgsMutex); + for(p=gdispMsgs; p < &gdispMsgs[GDISP_QUEUE_SIZE]; p++) { + if (p->action == GDISP_LLD_MSG_NOP) { + /* Allocate it */ + p->action = action; + chMtxUnlock(); + return p; + } + } + chMtxUnlock(); + + /* Oops - none found, try again */ + chSemSignal(&gdispMsgsSem); + } + } +#endif + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__) + /** + * @brief GDISP Driver initialization. + * @note This function is NOT currently implicitly invoked by @p halInit(). + * It must be called manually. + * + * @return True if succeeded, False otherwise + * + * @init + */ + bool_t gdispInit(void) { + bool_t res; + + /* Initialise Mutex */ + chMtxInit(&gdispMutex); + + /* Initialise driver */ + chMtxLock(&gdispMutex); + res = gdisp_lld_init(); + chMtxUnlock(); + + return res; + } +#elif GDISP_NEED_ASYNC + bool_t gdispInit(void) { + bool_t res; + unsigned i; + + /* Mark all the Messages as free */ + for(i=0; i < GDISP_QUEUE_SIZE; i++) + gdispMsgs[i].action = GDISP_LLD_MSG_NOP; + + /* Initialise our Mailbox, Mutex's and Counting Semaphore. + * A Mutex is required as well as the Mailbox and Thread because some calls have to be synchronous. + * Synchronous calls get handled by the calling thread, asynchronous by our worker thread. + */ + chMBInit(&gdispMailbox, gdispMailboxQueue, sizeof(gdispMailboxQueue)/sizeof(gdispMailboxQueue[0])); + chMtxInit(&gdispMutex); + chMtxInit(&gdispMsgsMutex); + chSemInit(&gdispMsgsSem, GDISP_QUEUE_SIZE); + + lldThread = chThdCreateStatic(waGDISPThread, sizeof(waGDISPThread), NORMALPRIO, GDISPThreadHandler, NULL); + + /* Initialise driver - synchronous */ + chMtxLock(&gdispMutex); + res = gdisp_lld_init(); + chMtxUnlock(); + + return res; + } +#endif + +#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__) + /** + * @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 + * + * @init + */ + bool_t gdispIsBusy(void) { + return FALSE; + } +#elif GDISP_NEED_ASYNC + bool_t gdispIsBusy(void) { + return chMBGetUsedCountI(&gdispMailbox) != FALSE; + } +#endif + +#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__) + /** + * @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) { + chMtxLock(&gdispMutex); + gdisp_lld_clear(color); + chMtxUnlock(); + } +#elif GDISP_NEED_ASYNC + void gdispClear(color_t color) { + gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_CLEAR); + p->clear.color = color; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__) + /** + * @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) { + chMtxLock(&gdispMutex); + gdisp_lld_draw_pixel(x, y, color); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__) + /** + * @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) { + chMtxLock(&gdispMutex); + gdisp_lld_draw_line(x0, y0, x1, y1, color); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__) + /** + * @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) { + chMtxLock(&gdispMutex); + gdisp_lld_fill_area(x, y, cx, cy, color); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if GDISP_NEED_MULTITHREAD || defined(__DOXYGEN__) + /** + * @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) { + chMtxLock(&gdispMutex); + gdisp_lld_blit_area_ex(x, y, cx, cy, srcx, srcy, srccx, buffer); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_CLIP && GDISP_NEED_MULTITHREAD) || 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) { + chMtxLock(&gdispMutex); + gdisp_lld_set_clip(x, y, cx, cy); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD) || 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) { + chMtxLock(&gdispMutex); + gdisp_lld_draw_circle(x, y, radius, color); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_CIRCLE && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__) + /** + * @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) { + chMtxLock(&gdispMutex); + gdisp_lld_fill_circle(x, y, radius, color); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD) || 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) { + chMtxLock(&gdispMutex); + gdisp_lld_draw_ellipse(x, y, a, b, color); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_ELLIPSE && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__) + /** + * @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) { + chMtxLock(&gdispMutex); + gdisp_lld_fill_ellipse(x, y, a, b, color); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) || 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 start, coord_t end, color_t color) { + chMtxLock(&gdispMutex); + gdisp_lld_draw_arc(x, y, radius, start, end, color); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__) + /* + * @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 start, coord_t end, color_t color) { + chMtxLock(&gdispMutex); + gdisp_lld_fill_arc(x, y, radius, start, end, color); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if GDISP_NEED_ARC || defined(__DOXYGEN__) +/** + * @brief Draw a rectangular box with rounded corners + * + * @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 + * @param[in] color The color to use + * + * @api + */ +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 || defined(__DOXYGEN__) +/** + * @brief Draw a filled rectangular box with rounded corners + * + * @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 + * @param[in] color The color to use + * + * @api + */ +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_TEXT && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__) + /** + * @brief Draw a text character. + * + * @param[in] x,y The position for the text + * @param[in] c The character to draw + * @param[in] font The font to use + * @param[in] color The color to use + * + * @api + */ + void gdispDrawChar(coord_t x, coord_t y, char c, font_t font, color_t color) { + chMtxLock(&gdispMutex); + gdisp_lld_draw_char(x, y, c, font, color); + chMtxUnlock(); + } +#elif GDISP_NEED_TEXT && GDISP_NEED_ASYNC + void gdispDrawChar(coord_t x, coord_t y, char c, font_t font, color_t color) { + gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWCHAR); + p->drawchar.x = x; + p->drawchar.y = y; + p->drawchar.c = c; + p->drawchar.font = font; + p->drawchar.color = color; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_TEXT && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__) + /** + * @brief Draw a text character with a filled background. + * + * @param[in] x,y The position for the text + * @param[in] c The character to draw + * @param[in] font The font to use + * @param[in] color The color to use + * @param[in] bgcolor The background color to use + * + * @api + */ + void gdispFillChar(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor) { + chMtxLock(&gdispMutex); + gdisp_lld_fill_char(x, y, c, font, color, bgcolor); + chMtxUnlock(); + } +#elif GDISP_NEED_TEXT && GDISP_NEED_ASYNC + void gdispFillChar(coord_t x, coord_t y, char c, font_t font, color_t color, color_t bgcolor) { + gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLCHAR); + p->fillchar.x = x; + p->fillchar.y = y; + p->fillchar.c = c; + p->fillchar.font = font; + p->fillchar.color = color; + p->fillchar.bgcolor = bgcolor; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_PIXELREAD && (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC)) || 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) { + color_t c; + + /* Always synchronous as it must return a value */ + chMtxLock(&gdispMutex); + c = gdisp_lld_get_pixel_color(x, y); + chMtxUnlock(); + + return c; + } +#endif + +#if (GDISP_NEED_SCROLL && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__) + /** + * @brief Scroll vertically a section of the screen. + * @pre GDISP_NEED_SCROLL must be set to TRUE in halconf.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) { + chMtxLock(&gdispMutex); + gdisp_lld_vertical_scroll(x, y, cx, cy, lines, bgcolor); + chMtxUnlock(); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + } +#endif + +#if (GDISP_NEED_CONTROL && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__) + /** + * @brief Set the power mode for the display. + * @pre The GDISP unit must have been initialised using @p gdispInit(). + * @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) { + chMtxLock(&gdispMutex); + gdisp_lld_control(what, value); + chMtxUnlock(); + chThdSleepMilliseconds(100); + } +#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; + chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE); + chThdSleepMilliseconds(100); + } +#endif + +#if (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC) || defined(__DOXYGEN__) + /** + * @brief Query a property of the display. + * @pre The GDISP unit must have been initialised using @p gdispInit(). + * @note The result must be typecast to the correct type. + * @note An uunsupported query will return (void *)-1. + * + * @param[in] what What to query + * + * @api + */ + void *gdispQuery(unsigned what) { + void *res; + + chMtxLock(&gdispMutex); + res = gdisp_lld_query(what); + chMtxUnlock(); + return res; + } +#endif + +/*===========================================================================*/ +/* High Level Driver Routines. */ +/*===========================================================================*/ + +/** + * @brief Draw a rectangular box. + * + * @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) { + /* No mutex required as we only call high level functions which have their own mutex */ + coord_t x1, y1; + + x1 = x+cx-1; + y1 = y+cy-1; + + 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); + } + } + } + } 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); + } +} + + +#if GDISP_NEED_TEXT || defined(__DOXYGEN__) + /** + * @brief Draw a text string. + * + * @param[in] x,y The position for the text + * @param[in] font The font to use + * @param[in] str The string to draw + * @param[in] color The color to use + * + * @api + */ + 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 */ + coord_t w, p; + char c; + int first; + + if (!str) return; + + first = 1; + p = font->charPadding * font->xscale; + while(*str) { + /* Get the next printable character */ + c = *str++; + w = _getCharWidth(font, c) * font->xscale; + if (!w) continue; + + /* Handle inter-character padding */ + if (p) { + if (!first) + x += p; + else + first = 0; + } + + /* Print the character */ + gdispDrawChar(x, y, c, font, color); + x += w; + } + } +#endif + +#if GDISP_NEED_TEXT || defined(__DOXYGEN__) + /** + * @brief Draw a text string. + * + * @param[in] x,y The position for the text + * @param[in] str The string to draw + * @param[in] font The font to use + * @param[in] color The color to use + * @param[in] bgcolor The background color to use + * + * @api + */ + 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 */ + coord_t w, h, p; + char c; + int first; + + if (!str) return; + + first = 1; + h = font->height * font->yscale; + p = font->charPadding * font->xscale; + while(*str) { + /* Get the next printable character */ + c = *str++; + w = _getCharWidth(font, c) * font->xscale; + if (!w) continue; + + /* Handle inter-character padding */ + if (p) { + if (!first) { + gdispFillArea(x, y, p, h, bgcolor); + x += p; + } else + first = 0; + } + + /* Print the character */ + gdispFillChar(x, y, c, font, color, bgcolor); + x += w; + } + } +#endif + +#if GDISP_NEED_TEXT || defined(__DOXYGEN__) + /** + * @brief Draw a text string verticly centered within the specified box. + * + * @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 + * @param[in] font The font to use + * @param[in] color The color to use + * @param[in] justify Justify the text left, center or right within the box + * + * @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) { + /* No mutex required as we only call high level functions which have their own mutex */ + coord_t w, h, p, ypos, xpos; + char c; + int first; + const char *rstr; + + if (!str) str = ""; + + h = font->height * font->yscale; + p = font->charPadding * font->xscale; + + /* Oops - font too large for the area */ + if (h > cy) return; + + /* See if we need to fill above the font */ + ypos = (cy - h + 1)/2; + if (ypos > 0) { + y += ypos; + cy -= ypos; + } + + /* See if we need to fill below the font */ + ypos = cy - h; + if (ypos > 0) + cy -= ypos; + + /* get the start of the printable string and the xpos */ + switch(justify) { + case justifyCenter: + /* Get the length of the entire string */ + w = gdispGetStringWidth(str, font); + if (w <= cx) + xpos = x + (cx - w)/2; + else { + /* Calculate how much of the string we need to get rid of */ + ypos = (w - cx)/2; + xpos = 0; + first = 1; + while(*str) { + /* Get the next printable character */ + c = *str++; + w = _getCharWidth(font, c) * font->xscale; + if (!w) continue; + + /* Handle inter-character padding */ + if (p) { + if (!first) { + xpos += p; + if (xpos > ypos) break; + } else + first = 0; + } + + /* Print the character */ + xpos += w; + if (xpos > ypos) break; + } + xpos = ypos - xpos + x; + } + break; + case justifyRight: + /* Find the end of the string */ + for(rstr = str; *str; str++); + xpos = x+cx - 2; + first = 1; + for(str--; str >= rstr; str--) { + /* Get the next printable character */ + c = *str; + w = _getCharWidth(font, c) * font->xscale; + if (!w) continue; + + /* Handle inter-character padding */ + if (p) { + if (!first) { + if (xpos - p < x) break; + xpos -= p; + } else + first = 0; + } + + /* Print the character */ + if (xpos - w < x) break; + xpos -= w; + } + str++; + break; + case justifyLeft: + /* Fall through */ + default: + xpos = x+1; + break; + } + + /* Print characters until we run out of room */ + first = 1; + while(*str) { + /* Get the next printable character */ + c = *str++; + w = _getCharWidth(font, c) * font->xscale; + if (!w) continue; + + /* Handle inter-character padding */ + if (p) { + if (!first) { + if (xpos + p > x+cx) break; + xpos += p; + } else + first = 0; + } + + /* Print the character */ + if (xpos + w > x+cx) break; + gdispDrawChar(xpos, y, c, font, color); + xpos += w; + } + } +#endif + +#if GDISP_NEED_TEXT || defined(__DOXYGEN__) + /** + * @brief Draw a text string verticly centered within the specified box. The box background is filled with the specified background color. + * @note The entire box is filled + * + * @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 + * @param[in] font The font to use + * @param[in] color The color to use + * @param[in] bgcolor The background color to use + * @param[in] justify Justify the text left, center or right within the box + * + * @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) { + /* No mutex required as we only call high level functions which have their own mutex */ + coord_t w, h, p, ypos, xpos; + char c; + int first; + const char *rstr; + + if (!str) str = ""; + + h = font->height * font->yscale; + p = font->charPadding * font->xscale; + + /* Oops - font too large for the area */ + if (h > cy) return; + + /* See if we need to fill above the font */ + ypos = (cy - h + 1)/2; + if (ypos > 0) { + gdispFillArea(x, y, cx, ypos, bgcolor); + y += ypos; + cy -= ypos; + } + + /* See if we need to fill below the font */ + ypos = cy - h; + if (ypos > 0) { + gdispFillArea(x, y+cy-ypos, cx, ypos, bgcolor); + cy -= ypos; + } + + /* get the start of the printable string and the xpos */ + switch(justify) { + case justifyCenter: + /* Get the length of the entire string */ + w = gdispGetStringWidth(str, font); + if (w <= cx) + xpos = x + (cx - w)/2; + else { + /* Calculate how much of the string we need to get rid of */ + ypos = (w - cx)/2; + xpos = 0; + first = 1; + while(*str) { + /* Get the next printable character */ + c = *str++; + w = _getCharWidth(font, c) * font->xscale; + if (!w) continue; + + /* Handle inter-character padding */ + if (p) { + if (!first) { + xpos += p; + if (xpos > ypos) break; + } else + first = 0; + } + + /* Print the character */ + xpos += w; + if (xpos > ypos) break; + } + xpos = ypos - xpos + x; + } + break; + case justifyRight: + /* Find the end of the string */ + for(rstr = str; *str; str++); + xpos = x+cx - 2; + first = 1; + for(str--; str >= rstr; str--) { + /* Get the next printable character */ + c = *str; + w = _getCharWidth(font, c) * font->xscale; + if (!w) continue; + + /* Handle inter-character padding */ + if (p) { + if (!first) { + if (xpos - p < x) break; + xpos -= p; + } else + first = 0; + } + + /* Print the character */ + if (xpos - w < x) break; + xpos -= w; + } + str++; + break; + case justifyLeft: + /* Fall through */ + default: + xpos = x+1; + break; + } + + /* Fill any space to the left */ + if (x < xpos) + gdispFillArea(x, y, xpos-x, cy, bgcolor); + + /* Print characters until we run out of room */ + first = 1; + while(*str) { + /* Get the next printable character */ + c = *str++; + w = _getCharWidth(font, c) * font->xscale; + if (!w) continue; + + /* Handle inter-character padding */ + if (p) { + if (!first) { + if (xpos + p > x+cx) break; + gdispFillArea(xpos, y, p, cy, bgcolor); + xpos += p; + } else + first = 0; + } + + /* Print the character */ + if (xpos + w > x+cx) break; + gdispFillChar(xpos, y, c, font, color, bgcolor); + xpos += w; + } + + /* Fill any space to the right */ + if (xpos < x+cx) + gdispFillArea(xpos, y, x+cx-xpos, cy, bgcolor); + } +#endif + +#if GDISP_NEED_TEXT || defined(__DOXYGEN__) + /** + * @brief Get a metric of a font. + * @return The metric requested in pixels. + * + * @param[in] font The font to test + * @param[in] metric The metric to measure + * + * @api + */ + coord_t gdispGetFontMetric(font_t font, fontmetric_t metric) { + /* No mutex required as we only read static data */ + switch(metric) { + case fontHeight: return font->height * font->yscale; + case fontDescendersHeight: return font->descenderHeight * font->yscale; + case fontLineSpacing: return font->lineSpacing * font->yscale; + case fontCharPadding: return font->charPadding * font->xscale; + case fontMinWidth: return font->minWidth * font->xscale; + case fontMaxWidth: return font->maxWidth * font->xscale; + } + return 0; + } +#endif + +#if GDISP_NEED_TEXT || defined(__DOXYGEN__) + /** + * @brief Get the pixel width of a character. + * @return The width of the character in pixels. Does not include any between character padding. + * + * @param[in] c The character to draw + * @param[in] font The font to use + * + * @api + */ + coord_t gdispGetCharWidth(char c, font_t font) { + /* No mutex required as we only read static data */ + return _getCharWidth(font, c) * font->xscale; + } +#endif + +#if GDISP_NEED_TEXT || defined(__DOXYGEN__) + /** + * @brief Get the pixel width of a string. + * @return The width of the string in pixels. + * + * @param[in] str The string to measure + * @param[in] font The font to use + * + * @api + */ + coord_t gdispGetStringWidth(const char* str, font_t font) { + /* No mutex required as we only read static data */ + coord_t w, p, x; + char c; + int first; + + first = 1; + x = 0; + p = font->charPadding * font->xscale; + while(*str) { + /* Get the next printable character */ + c = *str++; + w = _getCharWidth(font, c) * font->xscale; + if (!w) continue; + + /* Handle inter-character padding */ + if (p) { + if (!first) + x += p; + else + first = 0; + } + + /* Add the character width */ + x += w; + } + return x; + } +#endif + +#if (!defined(gdispPackPixels) && !defined(GDISP_PIXELFORMAT_CUSTOM)) || 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(pixel_t *buf, coord_t cx, coord_t x, coord_t y, color_t color) { + /* No mutex required as we only read static data */ + #if defined(GDISP_PIXELFORMAT_RGB888) + #error "GDISP: Packed pixels not supported yet" + #elif defined(GDISP_PIXELFORMAT_RGB444) + #error "GDISP: Packed pixels not supported yet" + #elif defined(GDISP_PIXELFORMAT_RGB666) + #error "GDISP: Packed pixels not supported yet" + #elif + #error "GDISP: Unsupported packed pixel format" + #endif + } +#endif + +#endif /* GFX_USE_GDISP */ +/** @} */ diff --git a/src/gwin/gwin.mk b/src/gwin/gwin.mk index 3c560f43..34a57c91 100644 --- a/src/gwin/gwin.mk +++ b/src/gwin/gwin.mk @@ -1,5 +1,5 @@ -GFXSRC += $(GFXLIB)/src/gwin/gwin.c \
- $(GFXLIB)/src/gwin/console.c \
- $(GFXLIB)/src/gwin/button.c \
- $(GFXLIB)/src/gwin/graph.c
+GFXSRC += $(GFXLIB)/src/gwin/gwin.c \ + $(GFXLIB)/src/gwin/console.c \ + $(GFXLIB)/src/gwin/button.c \ + $(GFXLIB)/src/gwin/graph.c |