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 + + 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 . +*/ + +/** + * --------------------------- 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<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 + + 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 . +*/ + +#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 + + 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 . +*/ + +/** + * 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 new file mode 100644 index 00000000..25aadf81 Binary files /dev/null and b/demos/modules/gadc/results_264x264.jpg differ 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 + + 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 . +*/ +/** + * @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/tdisp/HD44780/tdisp_lld_config.h b/drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h similarity index 64% rename from drivers/tdisp/HD44780/tdisp_lld_config.h rename to drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h index 3b37cd70..6f23db17 100644 --- a/drivers/tdisp/HD44780/tdisp_lld_config.h +++ b/drivers/gadc/AT91SAM7/gadc_lld_board_olimexsam7ex256.h @@ -1,45 +1,46 @@ -/* - ChibiOS/GFX - Copyright (C) 2012 - Joel Bodenmann aka Tectu - - 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 . -*/ - -/** - * @file drivers/tdisp/HD44780/tdisp_lld_config.h - * @brief TDISP Driver subsystem low level driver header for the HD44780 display. - * - * @addtogroup TDISP - * @{ - */ - -#ifndef _TDISP_LLD_CONFIG_H -#define _TDISP_LLD_CONFIG_H - -#if GFX_USE_TDISP - -/*===========================================================================*/ -/* Driver hardware support. */ -/*===========================================================================*/ - -#define TDISP_DRIVER_NAME "HD44780" - -#define TDISP_MAX_CUSTOM_CHARS 0x07 - -#endif /* GFX_USE_TDISP */ - -#endif /* _TDISP_LLD_CONFIG_H */ -/** @} */ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + 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 . +*/ + +/** + * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/* - 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 + + 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 . +*/ + +/* + 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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 -#include -#include -#include -#include -#include - -#ifndef GDISP_SCREEN_WIDTH - #define GDISP_SCREEN_WIDTH 640 -#endif -#ifndef GDISP_SCREEN_HEIGHT - #define GDISP_SCREEN_HEIGHT 480 -#endif - -#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 + + 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 . +*/ + +/** + * @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 +#include +#include +#include +#include +#include + +#ifndef GDISP_SCREEN_WIDTH + #define GDISP_SCREEN_WIDTH 640 +#endif +#ifndef GDISP_SCREEN_HEIGHT + #define GDISP_SCREEN_HEIGHT 480 +#endif + +#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 d0f4af0d..32b2b8c9 100644 --- a/drivers/tdisp/HD44780/tdisp_lld.c +++ b/drivers/tdisp/HD44780/tdisp_lld.c @@ -32,120 +32,131 @@ #if GFX_USE_TDISP /*|| defined(__DOXYGEN__)*/ -#include "tdisp_lld_board_example.h" +/* 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 -static void _writeData(uint8_t data) { - write_bus(data); - - setpin_e(TRUE); - chThdSleepMicroseconds(1); - setpin_e(FALSE); - chThdSleepMicroseconds(5); -} +/* The user may override the default display size */ +#ifndef TDISP_COLUMNS + #define TDISP_COLUMNS 16 +#endif +#ifndef TDISP_ROWS + #define TDISP_ROWS 2 +#endif -void tdisp_lld_write_cmd(uint8_t data) { - setpin_rs(FALSE); - setpin_rw(FALSE); +/* Controller Specific Properties */ +#define CUSTOM_CHAR_COUNT 8 +#define CUSTOM_CHAR_XBITS 5 +#define CUSTOM_CHAR_YBITS 8 - #if TDISP_NEED_4BIT_MODE - _writeData(data>>4); - #endif - _writeData(data); -} +/* 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 */ + }; -void tdisp_lld_write_data(uint8_t data) { - setpin_rs(TRUE); - setpin_rw(FALSE); +/* Our display control */ +#define DISPLAY_ON 0x04 +#define CURSOR_ON 0x02 +#define CURSOR_BLINK 0x01 + +static uint8_t displaycontrol; - #if TDISP_NEED_4BIT_MODE - _writeData(data>>4); - #endif - _writeData(data); -} bool_t tdisp_lld_init(void) { - /* initialise MCU hardware */ + /* initialise hardware */ init_board(); /* wait some time */ chThdSleepMilliseconds(50); - tdisp_lld_write_cmd(0x38); + write_cmd(0x38); chThdSleepMilliseconds(64); - tdisp_lld_write_cmd(0x0f); + displaycontrol = DISPLAY_ON | CURSOR_ON | CURSOR_BLINK; // The default displaycontrol + write_cmd(0x08 | displaycontrol); chThdSleepMicroseconds(50); - tdisp_lld_write_cmd(0x01); + write_cmd(0x01); // Clear the screen chThdSleepMilliseconds(5); - tdisp_lld_write_cmd(0x06); + write_cmd(0x06); chThdSleepMicroseconds(50); return TRUE; } -void tdisp_lld_set_cursor(coord_t col, coord_t row) { - uint8_t row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; - - if(row >= TDISP_ROWS) - row = TDISP_ROWS - 1; - - tdisp_lld_write_cmd(0x80 | (col + row_offsets[row])); -} - -void tdisp_lld_create_char(uint8_t address, char *charmap) { - uint8_t i; - - /* make sure we don't write somewhere we're not supposed to */ - address &= TDISP_MAX_CUSTOM_CHARS; - - tdisp_lld_write_cmd(0x40 | (address << 3)); - - for(i = 0; i < 8; i++) { - tdisp_lld_write_data(charmap[i]); - } -} - void tdisp_lld_clear(void) { - tdisp_lld_write_cmd(0x01); + write_cmd(0x01); } -void tdisp_lld_home(void) { - tdisp_lld_write_cmd(0x02); +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) { - (void)what; - (void)value; -/* - switch(attributes) { - case TDISP_ON: - _displaycontrol |= 0x04; - tdisp_lld_write_cmd(0x08 | _displaycontrol); + switch(what) { + case TDISP_CTRL_BACKLIGHT: + if ((uint8_t)value) + displaycontrol |= DISPLAY_ON; + else + displaycontrol &= ~DISPLAY_ON; + write_cmd(0x08 | displaycontrol); break; - case TDISP_OFF: - _displaycontrol &=~ 0x04; - tdisp_lld_write_cmd(0x08 | _displaycontrol); - break; - case TDISP_CURSOR_ON: - _displaycontrol |= 0x02; - tdisp_lld_write_cmd(0x08 | _displaycontrol); - break; - case TDISP_CURSOR_OFF: - _displaycontrol &=~ 0x02; - tdisp_lld_write_cmd(0x08 | _displaycontrol); - break; - case TDISP_CURSOR_BLINK_ON: - _displaycontrol |= 0x00; - tdisp_lld_write_cmd(0x08 | _displaycontrol); - break; - case TDISP_CURSOR_BLINK_OFF: - _displaycontrol &=~ 0x00; - tdisp_lld_write_cmd(0x08 | _displaycontrol); + 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 3f5c47d7..1b41f0c3 100644 --- a/drivers/tdisp/HD44780/tdisp_lld_board_example.h +++ b/drivers/tdisp/HD44780/tdisp_lld_board_example.h @@ -29,36 +29,33 @@ #ifndef _TDISP_LLD_BOARD_H #define _TDISP_LLD_BOARD_H -void init_board(void) { - palSetGroupMode(GPIOE, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); - palSetGroupMode(GPIOG, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); +/** + * 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" } -void setpin_e(bool_t state) { - if(state) - palSetPad(GPIOE, 2); - else - palClearPad(GPIOE, 2); +static void write_cmd(uint8_t data) { + /* Code here */ + #error "tdispHD44780: You must supply a definition for write_cmd for your board" } -void setpin_rs(bool_t state) { - if(state) - palSetPad(GPIOE, 0); - else - palClearPad(GPIOE, 0); -} - -void setpin_rw(bool_t state) { - if(state) - palSetPad(GPIOE, 1); - else - palClearPad(GPIOE, 1); -} - -void write_bus(uint8_t data) { - palWritePort(GPIOG, data); +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/drivers/tdisp/HD44780/tdisp_lld_board_unknown.h b/drivers/tdisp/HD44780/tdisp_lld_board_unknown.h new file mode 100644 index 00000000..381dc52b --- /dev/null +++ b/drivers/tdisp/HD44780/tdisp_lld_board_unknown.h @@ -0,0 +1,71 @@ +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + 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 . +*/ + +/** + * @file drivers/tdisp/HD44780/tdisp_lld_board_unknown.h + * @brief TDISP driver subsystem board interface for the HD44780 display + * + * @addtogroup TDISP + * @{ + */ + +#ifndef _TDISP_LLD_BOARD_H +#define _TDISP_LLD_BOARD_H + +/* Configure these to match the hardware connections on your board */ +#define BUS_4BITS FALSE +#define PORT_DATA GPIOG +#define PORT_CTRL GPIOE +#define PIN_RS 0 +#define PIN_RW 1 +#define PIN_EN 2 + +static void init_board(void) { + palSetGroupMode(PORT_CTRL, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); + palSetGroupMode(PORT_DATA, PAL_WHOLE_PORT, 0, PAL_MODE_OUTPUT_PUSHPULL); + palClearPad(PORT_CTRL, PIN_RW); +} + +static void writeToLCD(uint8_t data) { + palWritePort(PORT_DATA, data); + palSetPad(PORT_CTRL, PIN_EN); + chThdSleepMicroseconds(1); + palClearPad(PORT_CTRL, PIN_EN); + chThdSleepMicroseconds(5); +} + +static void write_cmd(uint8_t data) { + palClearPad(PORT_CTRL, PIN_RS); + #if BUS_4BITS + writeToLCD(data>>4); + #endif + writeToLCD(data); +} + +static void write_data(uint8_t data) { + palSetPad(PORT_CTRL, PIN_RS); + #if BUS_4BITS + writeToLCD(data>>4); + #endif + writeToLCD(data); +} + +#endif /* _TDISP_LLD_BOARD_H */ +/** @} */ diff --git a/gfxconf.example.h b/gfxconf.example.h index d9f1603e..389d4db5 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -1,105 +1,103 @@ -/** - * 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 subsystems to turn on */ -#define GFX_USE_GDISP FALSE -#define GFX_USE_TDISP FALSE -#define GFX_USE_GWIN FALSE -#define GFX_USE_GEVENT FALSE -#define GFX_USE_GTIMER FALSE -#define GFX_USE_GINPUT FALSE -#define GFX_USE_GADC FALSE -#define GFX_USE_GAUDIN FALSE -#define GFX_USE_GAUDOUT FALSE -#define GFX_USE_GMISC FALSE - -/* Features for the GDISP subsystem */ -#define GDISP_NEED_VALIDATION TRUE -#define GDISP_NEED_CLIP TRUE -#define GDISP_NEED_TEXT TRUE -#define GDISP_NEED_CIRCLE TRUE -#define GDISP_NEED_ELLIPSE TRUE -#define GDISP_NEED_ARC FALSE -#define GDISP_NEED_SCROLL FALSE -#define GDISP_NEED_PIXELREAD FALSE -#define GDISP_NEED_CONTROL FALSE -#define GDISP_NEED_MULTITHREAD FALSE -#define GDISP_NEED_ASYNC FALSE -#define GDISP_NEED_MSGAPI FALSE - -/* GDISP - builtin fonts */ -#define GDISP_OLD_FONT_DEFINITIONS FALSE -#define GDISP_INCLUDE_FONT_SMALL TRUE -#define GDISP_INCLUDE_FONT_LARGER TRUE -#define GDISP_INCLUDE_FONT_UI1 TRUE -#define GDISP_INCLUDE_FONT_UI2 TRUE -#define GDISP_INCLUDE_FONT_LARGENUMBERS TRUE - -/* TDISP options */ -#define TDISP_COLUMNS 16 -#define TDISP_ROWS 2 -#define TDISP_NEED_4BIT_MODE FALSE -#define TDISP_NEED_8BIT_MODE FALSE - -/* Features for the GWIN subsystem. */ -#define GWIN_NEED_BUTTON FALSE -#define GWIN_NEED_CONSOLE FALSE -#define GWIN_NEED_GRAPH FALSE - -/* Features for the GEVENT subsystem. */ -#define GEVENT_ASSERT_NO_RESOURCE FALSE - -/* Features for the GTIMER subsystem. */ -/* NONE */ - -/* Features for the GINPUT subsystem. */ -#define GINPUT_NEED_MOUSE FALSE -#define GINPUT_NEED_KEYBOARD FALSE -#define GINPUT_NEED_TOGGLE FALSE -#define GINPUT_NEED_DIAL FALSE - -/* Features for the GADC subsystem. */ -/* NONE */ - -/* Features for the GAUDIN subsystem. */ -/* NONE */ - -/* Features for the GAUDOUT subsystem. */ -/* NONE */ - -/* Features for the GMISC subsystem. */ -#define GMISC_NEED_ARRAYOPS FALSE - -/* Optional Parameters for various subsystems */ -/* - #define GDISP_MAX_FONT_HEIGHT 16 - #define GEVENT_MAXIMUM_SIZE 32 - #define GEVENT_MAX_SOURCE_LISTENERS 32 - #define GTIMER_THREAD_WORKAREA_SIZE 512 - #define GADC_MAX_LOWSPEED_DEVICES 4 -*/ - -/* 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 -*/ - -#endif /* _GFXCONF_H */ - +/** + * 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 subsystems to turn on */ +#define GFX_USE_GDISP FALSE +#define GFX_USE_TDISP FALSE +#define GFX_USE_GWIN FALSE +#define GFX_USE_GEVENT FALSE +#define GFX_USE_GTIMER FALSE +#define GFX_USE_GINPUT FALSE +#define GFX_USE_GADC FALSE +#define GFX_USE_GAUDIN FALSE +#define GFX_USE_GAUDOUT FALSE +#define GFX_USE_GMISC FALSE + +/* Features for the GDISP subsystem */ +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_TEXT TRUE +#define GDISP_NEED_CIRCLE TRUE +#define GDISP_NEED_ELLIPSE TRUE +#define GDISP_NEED_ARC FALSE +#define GDISP_NEED_SCROLL FALSE +#define GDISP_NEED_PIXELREAD FALSE +#define GDISP_NEED_CONTROL FALSE +#define GDISP_NEED_MULTITHREAD FALSE +#define GDISP_NEED_ASYNC FALSE +#define GDISP_NEED_MSGAPI FALSE + +/* GDISP - builtin fonts */ +#define GDISP_OLD_FONT_DEFINITIONS FALSE +#define GDISP_INCLUDE_FONT_SMALL TRUE +#define GDISP_INCLUDE_FONT_LARGER TRUE +#define GDISP_INCLUDE_FONT_UI1 TRUE +#define GDISP_INCLUDE_FONT_UI2 TRUE +#define GDISP_INCLUDE_FONT_LARGENUMBERS TRUE + +/* Features for the TDISP subsystem. */ +#define TDISP_NEED_MULTITHREAD FALSE + +/* Features for the GWIN subsystem. */ +#define GWIN_NEED_BUTTON FALSE +#define GWIN_NEED_CONSOLE FALSE +#define GWIN_NEED_GRAPH FALSE + +/* Features for the GEVENT subsystem. */ +#define GEVENT_ASSERT_NO_RESOURCE FALSE + +/* Features for the GTIMER subsystem. */ +/* NONE */ + +/* Features for the GINPUT subsystem. */ +#define GINPUT_NEED_MOUSE FALSE +#define GINPUT_NEED_KEYBOARD FALSE +#define GINPUT_NEED_TOGGLE FALSE +#define GINPUT_NEED_DIAL FALSE + +/* Features for the GADC subsystem. */ +/* NONE */ + +/* Features for the GAUDIN subsystem. */ +/* NONE */ + +/* Features for the GAUDOUT subsystem. */ +/* NONE */ + +/* Features for the GMISC subsystem. */ +#define GMISC_NEED_ARRAYOPS FALSE + +/* Optional Parameters for various subsystems */ +/* + #define GDISP_MAX_FONT_HEIGHT 16 + #define GEVENT_MAXIMUM_SIZE 32 + #define GEVENT_MAX_SOURCE_LISTENERS 32 + #define GTIMER_THREAD_WORKAREA_SIZE 512 + #define GADC_MAX_LOWSPEED_DEVICES 4 +*/ + +/* Optional Low Level Driver Definitions */ +/* + #define GDISP_USE_CUSTOM_BOARD FALSE + #define GDISP_SCREEN_WIDTH 320 + #define GDISP_SCREEN_HEIGHT 240 + #define GDISP_USE_FSMC + #define GDISP_USE_GPIO + #define TDISP_COLUMNS 16 + #define TDISP_ROWS 2 +*/ + +#endif /* _GFXCONF_H */ diff --git a/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 - - 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 . -*/ -/** - * @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 + + 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 . +*/ +/** + * @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 + + 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 . +*/ +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 - - /* - * @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 + + 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 . +*/ + +/** + * @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 + + /* + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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/include/tdisp/lld/tdisp_lld.h b/include/tdisp/lld/tdisp_lld.h index de6266f3..4efc3579 100644 --- a/include/tdisp/lld/tdisp_lld.h +++ b/include/tdisp/lld/tdisp_lld.h @@ -1,57 +1,53 @@ -/* - ChibiOS/GFX - Copyright (C) 2012 - Joel Bodenmann aka Tectu - - 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 . -*/ - -/** - * @file include/tdisp/lld/tdisp_lld.h - * @brief TDISP driver subsystem low level driver header. - * - * @addtogroup TDISP - * @{ - */ - -#ifndef _TDISP_LLD_H -#define _TDISP_LLD_H - -#if GFX_USE_TDISP || defined(__DOXYGEN__) - -#include "tdisp_lld_config.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern void tdisp_lld_write_cmd(uint8_t data); -extern void tdisp_lld_write_data(uint8_t data); -extern bool_t tdisp_lld_init(void); -extern void tdisp_lld_set_cursor(coord_t col, coord_t row); -extern void tdisp_lld_create_char(uint8_t address, char *charmap); -extern void tdisp_lld_clear(void); -extern void tdisp_lld_home(void); -extern void tdisp_lld_control(uint16_t what, void *value); - -#ifdef __cplusplus -} -#endif - -#endif /* GFX_USE_TDISP */ - -#endif /* _TDISP_LLD_H */ -/** @} */ - +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + 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 . +*/ + +/** + * @file include/tdisp/lld/tdisp_lld.h + * @brief TDISP driver subsystem low level driver header. + * + * @addtogroup TDISP + * @{ + */ + +#ifndef _TDISP_LLD_H +#define _TDISP_LLD_H + +#if GFX_USE_TDISP || defined(__DOXYGEN__) + +#ifdef __cplusplus +extern "C" { +#endif + + bool_t tdisp_lld_init(void); + void tdisp_lld_clear(void); + void tdisp_lld_draw_char(char c); + void tdisp_lld_set_cursor(coord_t col, coord_t row); + void tdisp_lld_create_char(uint8_t address, uint8_t *charmap); + void tdisp_lld_control(uint16_t what, void *value); + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_TDISP */ + +#endif /* _TDISP_LLD_H */ +/** @} */ + diff --git a/include/tdisp/options.h b/include/tdisp/options.h index 69d24b64..77d562af 100644 --- a/include/tdisp/options.h +++ b/include/tdisp/options.h @@ -31,53 +31,44 @@ #if GFX_USE_TDISP /** - * @name TDISP configuration + * @name TDISP Functionality to be included * @{ */ - - /** - * @brief How many rows of characters the TDISP provides - */ - #ifndef TDISP_ROWS - #define TDISP_ROWS 2 - #endif - - /** - * @brief How many columns of characters the TDISP provides - */ - #ifndef TDISP_COLUMNS - #define TDISP_COLUMNS 16 - #endif - -/** @} */ - /** - * @name TDISP interface configuration - * @note Only one of these interfaces can be selected at a time! + * @} + * + * @name TDISP Multi-Threading Options * @{ */ /** - * @brief Use the 4-bit paralle interface + * @brief Do the display functions need to be thread-safe. + * @details Defaults to FALSE */ - #ifndef TDISP_NEED_4BIT_MODE - #define TDISP_NEED_4BIT_MODE FALSE + #ifndef TDISP_NEED_MULTITHREAD + #define TDISP_NEED_MULTITHREAD FALSE #endif - +/** + * @} + * + * @name TDISP Optional Low Level Driver Defines + * @{ + */ /** - * @brief Use the 8-bit parallel interface + * @brief Use a custom board definition even if a board definition exists. + * @details Defaults to FALSE + * @details If TRUE, add tdisp_lld_board.h to your project directory and customise it. + * @note Not all TDISP low level drivers currently use board definition files. */ - #ifndef TDISP_NEED_8BIT_MODE - #define TDISP_NEED_8BIT_MODE FALSE + #ifndef TDISP_USE_CUSTOM_BOARD + #define TDISP_USE_CUSTOM_BOARD FALSE #endif - - #if (!TDISP_NEED_4BIT_MODE && !TDISP_NEED_8BIT_MODE) - #error "Either TDISP_NEED_4BIT_MODE or TDISP_NEED_8BIT_MODE needs to be set to TRUE in your gfxconf.h!" - #endif - - #if (TDISP_NEED_4BIT_MODE && TDISP_NEED_8BIT_MODE) - #error "Only TDISP_NEED_4BIT_MODE or TDISP_NEED_8BIT_MODE can be set to TRUE, not both at one!" - #endif - + /** + * @brief Set the screen height and width. + * @note Ignored by some low level GDISP drivers, optional for others. + * @note Where these values are allowed, a default is always provided by the low level driver. + */ + /* #define TDISP_COLUMNS 16 */ + /* #define TDISP_ROWS 2 */ /** @} */ #endif /* GFX_USE_TDISP */ diff --git a/include/tdisp/tdisp.h b/include/tdisp/tdisp.h index 01cb76a0..fcb1fc5f 100644 --- a/include/tdisp/tdisp.h +++ b/include/tdisp/tdisp.h @@ -1,147 +1,206 @@ -/* - ChibiOS/GFX - Copyright (C) 2012 - Joel Bodenmann aka Tectu - - 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 . -*/ - -/** - * @file include/tdisp/tdisp.h - * @brief TDISP Graphic Driver subsystem header file. - * - * @addtogroup TDISP - * - * @details The TDISP module provides high level abstraction to interface pixel oriented graphic displays. - * Due the TDISP module is completely encapsulated from the other modules, it's very fast and lightweight. - * - * @pre GFX_USE_TDISP must be set to TRUE in gfxconf.h - * - * @{ - */ - -#ifndef _TDISP_H -#define _TDISP_H - -#include "gfx.h" - -#if GFX_USE_TDISP || defined(__DOXYGEN__) - -/* Include the low level driver information */ -#include "tdisp/lld/tdisp_lld.h" - -/** - * @name TDISP display attributes - * @{ - */ -#define TDISP_ON 0x01 -#define TDISP_OFF 0x02 -#define TDISP_CURSOR_ON 0x03 -#define TDISP_CURSOR_OFF 0x04 -#define TDISP_CURSOR_BLINK_ON 0x05 -#define TDISP_CURSOR_BLINK_OFF 0x06 -/** @} */ - -/** - * @brief TDISP driver initialisation - * @note This function is not implicitly invoked by @p halInit(). - * It must be called manually. - * - * @return TRUE if success, FALSE otherwise - * - * @init - */ -bool_t tdispInit(void); - -/** - * @brief Control different display properties - * @note A wrapper macro exists for each option, please use them - * instead of this function manually. - * - * @param[in] what What you want to control - * @param[in] value The value to be assigned - */ -void tdispControl(uint16_t what, void *value); - -/** - * @brief Clears the display - */ -void tdispClear(void); - -/** - * @brief Sets the cursor to it's home position ( 0/0 ) - */ -void tdispHome(void); - -/** - * @brief Set cursor to a certain position - * - * @param[in] col The column - * @param[in] row The row - */ -void tdispSetCursor(coord_t col, coord_t row); - -/** - * @brief Store a custom character in RAM - * - * @note This usually must be done after each power-up since most - * LCDs lose their RAM content. - * - * @param[in] address On which address to store the character (from 0 up to max) - * @param[in] charmap The character to be stored. - */ -void tdispCreateChar(uint8_t address, char *charmap); - -/** - * @brief Draws a single character at the current cursor position - * - * @param[in] c The character to be drawn - */ -void tdispDrawChar(char c); - -/** - * @brief Draws a string at the current cursor position - * - * @param[in] s The string to be drawn - */ -void tdispDrawString(char *s); - -/** - * @brief Draws a single character at a given position - * @note This function manipulates the cursor position and it will not be - * reset to it's original state - * - * @param[in] col The column - * @param[in] row The row - * @param[in] c The character to be drawn - */ -void tdispDrawCharLocation(coord_t col, coord_t row, char c); - -/** - * @brief Draws a string at a given position - * @note This function manipulates the cursor position and it will not be - * reset to it's original state - * - * @param[in] col The column - * @param[in] row The row - * @param[in] s The string to be drawn - */ -void tdispDrawStringLocation(coord_t col, coord_t row, char *s); - -#endif /* GFX_USE_TDISP */ - -#endif /* _TDISP_H */ -/** @} */ - +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + 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 . +*/ + +/** + * @file include/tdisp/tdisp.h + * @brief TDISP Graphic Driver subsystem header file. + * + * @addtogroup TDISP + * + * @details The TDISP module provides high level abstraction to interface pixel oriented graphic displays. + * Due the TDISP module is completely encapsulated from the other modules, it's very fast and lightweight. + * + * @pre GFX_USE_TDISP must be set to TRUE in gfxconf.h + * + * @{ + */ + +#ifndef _TDISP_H +#define _TDISP_H + +#include "gfx.h" + +#if GFX_USE_TDISP || defined(__DOXYGEN__) + +/** + * @brief TDISP cursor shape definitions + */ +typedef enum cursorshape_e { + cursorOff, + cursorBlock, + cursorBlinkingBlock, + cursorUnderline, + cursorBlinkingUnderline, + cursorBar, + cursorBlinkingBar, + } cursorshape; + +/** + * @name TDISP control values + * @note The low level driver may define extra control values + * @{ + */ +#define TDISP_CTRL_BACKLIGHT 0x0000 +#define TDISP_CTRL_CURSOR 0x0001 +/** @} */ + +/** + * @brief The TDISP structure definition + */ +typedef struct tdispStruct_t { + coord_t columns, rows; + coord_t charBitsX, charBitsY; + uint16_t maxCustomChars; + } tdispStruct; + +/** + * @brief The TDISP structure + */ +extern tdispStruct TDISP; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief TDISP driver initialisation + * @note This function is not implicitly invoked by @p halInit(). + * It must be called manually. + * + * @return TRUE if success, FALSE otherwise + * + * @init + */ +bool_t tdispInit(void); + +/** + * @brief Clears the display + */ +void tdispClear(void); + +/** + * @brief Sets the cursor to it's home position ( 0, 0 ) + */ +void tdispHome(void); + +/** + * @brief Set cursor to a specified position + * + * @param[in] col The column (x) + * @param[in] row The row (y) + */ +void tdispSetCursor(coord_t col, coord_t row); + +/** + * @brief Store a custom character into the display + * + * @note This usually must be done after each power-up since most + * LCDs lose their RAM content. + * + * @param[in] address On which address to store the character from 0 up to (@p tdispGetNumCustomChars() - 1) + * @param[in] charmap The character to be stored. + * + * @note The charmap is made up of @p tdispGetCharBitHieght() data values. Each data value is + * made up of @p tdispGetCharBitWidth() bits of data. Note that bits in multiple rows are not + * packed. + */ +void tdispCreateChar(uint8_t address, uint8_t *charmap); + +/** + * @brief Draws a single character at the current cursor position and advances the cursor + * + * @param[in] c The character to be drawn + * + * @note Writing past the end of a row leaves the cursor in an undefined position. + */ +void tdispDrawChar(char c); + +/** + * @brief Draws a string at the current cursor position and advances the cursor + * + * @param[in] s The string to be drawn + * + * @note Any characters written past the end of a row may or may not be displayed on + * the next row. The cursor is also left in an undefined position. + */ +void tdispDrawString(char *s); + +/** + * @brief Control different display properties + * @note A wrapper macro exists for each option, please use them + * instead of this function manually unless calling a low + * level driver specific value. + * + * @param[in] what What you want to control + * @param[in] value The value to be assigned + */ +void tdispControl(uint16_t what, void *value); + +/** + * @brief Set the backlight level + * + * @param[in] percent A percentage from 0 to 100%. 0% will turn off the display + */ +#define tdispSetBacklight(percent) tdispControl(TDISP_CTRL_BACKLIGHT, (void *)((uint8_t)(percent))) + +/** + * @brief Set the cursor shape + * + * @param[in] shape The shape to set the cursor. + * + * @note Not all shapes are necessarily supported. The driver will make a similar + * choice if the one specified is not available. + */ +#define tdispSetCursorShape(shape) tdispControl(TDISP_CTRL_CURSOR, (void *)((cursorshape)(shape))) + +/** + * @brief Get the number of columns (width) in the display + */ +#define tdispGetColumns() (TDISP.columns) + +/** + * @brief Get the number of rows (height) in the display + */ +#define tdispGetRows() (TDISP.columns) + +/** + * @brief Get the number of bits in width of a character + */ +#define tdispGetCharBitWidth() (TDISP.charBitsX) + +/** + * @brief Get the number of bits in height of a character + */ +#define tdispGetCharBitHeight() (TDISP.charBitsY) + +/** + * @brief Get the number of custom characters + */ +#define tdispGetNumCustomChars() (TDISP.maxCustomChars) + +#ifdef __cplusplus +} +#endif + +#endif /* GFX_USE_TDISP */ + +#endif /* _TDISP_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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 - - 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 . -*/ - -/** - * @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 + + 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 . +*/ + +/** + * @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 diff --git a/src/tdisp/tdisp.c b/src/tdisp/tdisp.c index 3556e031..8ef7e5c4 100644 --- a/src/tdisp/tdisp.c +++ b/src/tdisp/tdisp.c @@ -1,85 +1,117 @@ -/* - ChibiOS/GFX - Copyright (C) 2012 - Joel Bodenmann aka Tectu - - 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 . -*/ - -/** - * @file src/tdisp/tdisp.c - * @brief TDISP Driver code. - * - * @addtogroup TDISP - * @{ - */ -#include "ch.h" -#include "hal.h" -#include "gfx.h" - -#if GFX_USE_TDISP || defined(__DOXYGEN__) - -static uint8_t _displaycontrol; - -bool_t tdispInit(void) { - bool_t ret; - - ret = tdisp_lld_init(); - - return ret; -} - -void tdispControl(uint16_t what, void *value) { - tdisp_lld_control(what, value); -} - -void tdispClear(void) { - tdisp_lld_clear(); -} - -void tdispHome(void) { - tdisp_lld_home(); -} - -void tdispCreateChar(uint8_t address, char *charmap) { - tdisp_lld_create_char(address, charmap); -} - -void tdispSetCursor(coord_t col, coord_t row) { - tdisp_lld_set_cursor(col, row); -} - -void tdispDrawChar(char c) { - tdisp_lld_write_data(c); -} - -void tdispDrawString(char *s) { - while(*s) - tdispDrawChar(*s++); -} - -void tdispDrawCharLocation(coord_t col, coord_t row, char c) { - tdispSetCursor(col, row); - tdispDrawChar(c); -} - -void tdispDrawStringLocation(coord_t col, coord_t row, char *s) { - tdispSetCursor(col, row); - tdispDrawString(s); -} - -#endif /* GFX_USE_TDISP */ -/** @} */ - +/* + ChibiOS/GFX - Copyright (C) 2012 + Joel Bodenmann aka Tectu + + 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 . +*/ + +/** + * @file src/tdisp/tdisp.c + * @brief TDISP Driver code. + * + * @addtogroup TDISP + * @{ + */ +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if GFX_USE_TDISP || defined(__DOXYGEN__) + +#include "tdisp/lld/tdisp_lld.h" + +#if TDISP_NEED_MULTITHREAD + #if !CH_USE_MUTEXES + #error "TDISP: CH_USE_MUTEXES must be defined in chconf.h because TDISP_NEED_MULTITHREAD is defined" + #endif + + static Mutex tdispMutex; + + #define MUTEX_INIT() chMtxInit(&tdispMutex) + #define MUTEX_ENTER() chMtxLock(&tdispMutex) + #define MUTEX_LEAVE() chMtxUnlock() + +#else + + #define MUTEX_INIT() + #define MUTEX_ENTER() + #define MUTEX_LEAVE() + +#endif + +bool_t tdispInit(void) { + bool_t res; + + MUTEX_INIT(); + + MUTEX_ENTER(); + res = tdisp_lld_init(); + MUTEX_LEAVE(); + + return res; +} + +void tdispClear(void) { + MUTEX_ENTER(); + tdisp_lld_clear(); + MUTEX_LEAVE(); +} + +void tdispHome(void) { + MUTEX_ENTER(); + tdisp_lld_set_cursor(0, 0); + MUTEX_LEAVE(); +} + +void tdispSetCursor(coord_t col, coord_t row) { + /* Keep the input range valid */ + if (row >= TDISP.rows) + row = TDISP.rows - 1; + MUTEX_ENTER(); + tdisp_lld_set_cursor(col, row); + MUTEX_LEAVE(); +} + +void tdispCreateChar(uint8_t address, uint8_t *charmap) { + /* make sure we don't write somewhere we're not supposed to */ + if (address < TDISP.maxCustomChars) { + MUTEX_ENTER(); + tdisp_lld_create_char(address, charmap); + MUTEX_LEAVE(); + } +} + +void tdispDrawChar(char c) { + MUTEX_ENTER(); + tdisp_lld_draw_char(c); + MUTEX_LEAVE(); +} + +void tdispDrawString(char *s) { + MUTEX_ENTER(); + while(*s) + tdisp_lld_draw_char(*s++); + MUTEX_LEAVE(); +} + +void tdispControl(uint16_t what, void *value) { + MUTEX_ENTER(); + tdisp_lld_control(what, value); + MUTEX_LEAVE(); +} + +#endif /* GFX_USE_TDISP */ +/** @} */