?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

/*****************************************************************************
 *  Module for Microchip Graphics Library
 *  Custom display controller driver template
 *****************************************************************************
 * FileName:            MicrochipGraphicsModule.c
 * Dependencies:    Graphics.h
 * Processor:           PIC24
 * Compiler:            MPLAB C30
 * Linker:                MPLAB LINK30
 * Company:            Microchip Technology Incorporated
 *
 * Software License Agreement
 *
 * Copyright © 2008 Microchip Technology Inc.  All rights reserved.
 * Microchip licenses to you the right to use, modify, copy and distribute
 * Software only when embedded on a Microchip microcontroller or digital
 * signal controller, which is integrated into your product or third party
 * product (pursuant to the sublicense terms in the accompanying license
 * agreement).  
 *
 * You should refer to the license agreement accompanying this Software
 * for additional information regarding your rights and obligations.
 *
 * SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY
 * OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR
 * PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR
 * OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION,
 * BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT
 * DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL,
 * INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA,
 * COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY
 * CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF),
 * OR OTHER SIMILAR COSTS.
 *
 * Author                                    Date                               Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Pradeep Budagutta                20 Aug 2009                 Initial Version
 * Pradeep Budagutta                03 Dec 2009                 Added Double Buffering Support
 * PAT                                          29 Mar 2010                 Fixed EPMP base address programming
 *****************************************************************************/
#include "Graphics\Graphics.h"

#if (DISPLAY_PANEL == TFT_G240320LTSW_118W_E)

    #include "TCON_SSD1289.c"

#elif (DISPLAY_PANEL == TFT_G320240DTSW_69W_TP_E)

    #include "TCON_HX8238.c"

#elif (DISPLAY_PANEL == PH480272T_005_I06Q)

    #include "TCON_HX8257.c"

#else

    #include "TCON_Custom.c"

#endif

#ifdef USE_PALETTE

    #include "Graphics\Palette.h"

    extern void *_palette;
    extern BYTE PaletteBpp;
    extern BYTE blPaletteChangeError;
    extern void *pPendingPalette;
    extern WORD PendingStartEntry;
    extern WORD PendingLength;

#endif

// Color
WORD_VAL    _color;
WORD_VAL    _chrcolor;

// Clipping region control
SHORT       _clipRgn;

// Clipping region borders
SHORT       _clipLeft;
SHORT       _clipTop;
SHORT       _clipRight;
SHORT       _clipBottom;

// work areas base addresses
volatile DWORD          _workArea1BaseAddr;
volatile DWORD          _workArea2BaseAddr;

// display buffer base address
volatile DWORD          _displayAreaBaseAddr;

#ifdef USE_DOUBLE_BUFFERING

    volatile DWORD  _drawbuffer;
    volatile BYTE   blDisplayUpdatePending;

#endif //USE_DOUBLE_BUFFERING

#define GFX_FLIP(a,b) { SHORT t=a; a=b; b=t; }

#if defined (GFX_EPMP_CS1_BASE_ADDRESS) || defined (GFX_EPMP_CS2_BASE_ADDRESS)

void EPMP_Init(void)
{
        /* Note: When using the EPMP to access external RAM or Flash, PMA0-PMA16 will only access a range of 
                 256K RAM. To increase this range enable higher Address lines.
        */
        ANSDbits.ANSD7 = 0;   // PMD15
        ANSDbits.ANSD6 = 0;   // PMD14
        ANSFbits.ANSF0 = 0;   // PMD11

        ANSBbits.ANSB15 = 0;  // PMA0
        ANSBbits.ANSB14 = 0;  // PMA1
        ANSGbits.ANSG9  = 0;  // PMA2
        ANSBbits.ANSB13 = 0;  // PMA10
        ANSBbits.ANSB12 = 0;  // PMA11
        ANSBbits.ANSB11 = 0;  // PMA12
        ANSBbits.ANSB10 = 0;  // PMA13
        ANSAbits.ANSA7 = 0;   // PMA17
        ANSGbits.ANSG6 = 0;   // PMA18

        PMCON1bits.ADRMUX = 0;                                                                  // address is not multiplexed
        PMCON1bits.MODE = 3;                                                                    // master mode
        PMCON1bits.CSF = 0;                                                                     // PMCS1 pin used for chip select 1, PMCS2 pin used for chip select 2
        PMCON1bits.ALP = 1;                                                                     // set address latch strobes to high active level (for sn74lvc16373)
        PMCON1bits.ALMODE = 1;                                                                  // "smart" address strobes are not used
        PMCON1bits.BUSKEEP = 0;                                                                 // bus keeper is not used

        #if defined (GFX_EPMP_CS1_BASE_ADDRESS)
                #ifdef USE_DOUBLE_BUFFERING
                        PMCS1BS = ((DWORD)GFX_BUFFER1>>8);                                      // CS1 start address
                        PMCON3 |= 0x0003;                                                       // PMA16 - PMA17 address lines are enabled 
                #else
                        PMCS1BS = (GFX_EPMP_CS1_BASE_ADDRESS>>8);                       // CS1 start address
                        PMCON3 |= 0x0001;                                                       // PMA16 address line is enabled 
                #endif //USE_DOUBLE_BUFFERING

                PMCS1CFbits.CSDIS = 0;                                                          // enable CS
                PMCS1CFbits.CSP = EPMPCS1_CS_POLARITY;                          // CS1 polarity 
                PMCS1CFbits.BEP = EPMPCS1_BE_POLARITY;                          // byte enable polarity
                PMCS1CFbits.WRSP = EPMPCS1_WR_POLARITY;                         // write strobe polarity
                PMCS1CFbits.RDSP = EPMPCS1_RD_POLARITY;                         // read strobe polarity
                PMCS1CFbits.CSPTEN = 1;                                                         // enable CS port
                PMCS1CFbits.SM = 0;                                                             // read and write strobes on separate lines 
                PMCS1CFbits.PTSZ = 2;                                                           // data bus width is 16-bit 
        
                PMCS1MDbits.ACKM = 0;                                                           // PMACK is not used

                // The device timing parameters. Set the proper timing
                // according to the device used (the timing macros are defined in the hardware profile)
                PMCS1MDbits.DWAITB = EPMPCS1_DWAITB;                                    // access time 1 Tcy
                PMCS1MDbits.DWAITM = EPMPCS1_DWAITM;
                PMCS1MDbits.DWAITE = EPMPCS1_DWAITE;
                PMCS1MDbits.AMWAIT = EPMPCS1_AMWAIT;                                    // Note: adjust this delay for slower devices 

        #else
                        PMCS1CFbits.CSDIS = 1;                                                  // disable CS1 functionality  
        #endif //#if defined (GFX_EPMP_CS1_BASE_ADDRESS)

        #if defined (GFX_EPMP_CS2_BASE_ADDRESS)

                PMCS2BS = (GFX_EPMP_CS2_BASE_ADDRESS>>8);                               // CS2 start address

                PMCS2CFbits.CSDIS = 0;                                                          // enable CS

                PMCS2CFbits.CSP = EPMPCS2_CS_POLARITY;                          // CS2 polarity 
                PMCS2CFbits.BEP = EPMPCS2_BE_POLARITY;                          // byte enable polarity
                PMCS2CFbits.WRSP = EPMPCS2_WR_POLARITY;                         // write strobe polarity
                PMCS2CFbits.RDSP = EPMPCS2_RD_POLARITY;                         // read strobe polarity
                PMCS2CFbits.CSPTEN = 1;                                                         // enable CS port
                PMCS2CFbits.SM = 0;                                                             // read and write strobes on separate lines 
                PMCS2CFbits.PTSZ = 2;                                                           // data bus width is 16-bit 
        
                PMCS2MDbits.ACKM = 0;                                                           // PMACK is not used
                
                // The device timing parameters. Set the proper timing
                // according to the device used (the timing macros are defined in the hardware profile)
                PMCS2MDbits.DWAITB = EPMPCS2_DWAITB;                                    // access time 1 Tcy
                PMCS2MDbits.DWAITM = EPMPCS2_DWAITM;
                PMCS2MDbits.DWAITE = EPMPCS2_DWAITE;
                PMCS2MDbits.AMWAIT = EPMPCS2_AMWAIT;                                    // Note: adjust this delay for slower devices 


        #else   
                PMCS2CFbits.CSDIS = 1;                                                          // disable CS2 functionality  
        #endif //#if defined (GFX_EPMP_CS2_BASE_ADDRESS)
        
        PMCON2bits.RADDR = 0xFF;                                                                        // set CS2 end address
        PMCON4 = 0xFFFF;                                                                        // PMA0 - PMA15 address lines are enabled
        

        PMCON3bits.PTWREN = 1;                                                                  // enable write strobe port
        PMCON3bits.PTRDEN = 1;                                                                  // enable read strobe port
        PMCON3bits.PTBE0EN = 1;                                                                 // enable byte enable port
        PMCON3bits.PTBE1EN = 1;                                                                 // enable byte enable port
        PMCON3bits.AWAITM = 0;                                                                  // set address latch pulses width to 1/2 Tcy
        PMCON3bits.AWAITE = 0;                                                                  // set address hold time to 1/4 Tcy
        
        DelayMs(100);

        PMCON2bits.MSTSEL = 3;                                                                          // select EPMP bypass mode (for Graphics operation)
        PMCON1bits.PMPEN = 1;                                                                           // enable the module

        DelayMs(100);

}

#endif //#if defined (GFX_EPMP_CS1_BASE_ADDRESS) || defined (GFX_EPMP_CS2_BASE_ADDRESS)

/*********************************************************************
* Function:  void ResetDevice()
*
* PreCondition: none
*
* Input: none
*
* Output: none
*
* Side Effects: none
*
* Overview: Resets LCD, initializes PMP. FRM Section 43. Graphics 
*                       Controller Module (GFX) (Document #:DS39731) for details.
*
* Note: none
*
********************************************************************/
void ResetDevice(void)
{
#ifdef USE_DOUBLE_BUFFERING

    blInvalidateAll = 1;
    blDisplayUpdatePending = 0;
    NoOfInvalidatedRectangleAreas = 0;
    _drawbuffer = GFX_BUFFER1;
    SwitchOnDoubleBuffering();

#endif //USE_DOUBLE_BUFFERING


#if defined (POWERON_LAT_BIT)

        /* Switch On display if IO controlled; if controlled 
           by the Graphics Module, hook up the power-on signal of the display to
           GPWR pin of the Graphics Module and this code should not compile */
           
    POWERON_LAT_BIT = 1;
    POWERON_TRIS_BIT = 0;

#endif

#if defined (GFX_EPMP_CS1_BASE_ADDRESS) || defined (GFX_EPMP_CS2_BASE_ADDRESS)

    EPMP_Init();
        
#endif

/************ End - Project Specific Code - Relocate ************/


    G1CON1   = 0; /* Switch off the module */
    G1CON2   = 0;
    G1CON3   = 0;
    G1IE     = 0;
    G1IR     = 0;
    G1CLUT   = 0;
    G1MRGN   = 0;
    G1CLUTWR = 0;
    G1CHRX   = 0;
    G1CHRY   = 0;
    G1CMDL   = 0;
    G1CMDH   = 0;
    
    // set the  processing unit bit per pixel
    _PUBPP   = GFX_BITS_PER_PIXEL;
    // set the  display controller bit per pixel
    _DPBPP   = GFX_BITS_PER_PIXEL;
    // set the LCD type used (TFT, MSTN or CSTN)
    _DPMODE  = GFX_LCD_TYPE;

    #if (GFX_LCD_TYPE == GFX_LCD_MSTN) || (GFX_LCD_TYPE == GFX_LCD_CSTN)
                // set the display width
        _DPGWDTH = STN_DISPLAY_WIDTH;

    #endif

    /* Port configurations */
    #ifdef GFX_DISPLAYENABLE_ENABLE
        // set the display enable polarity
        _DPENPOL = GFX_DISPLAYENABLE_POLARITY;
        _DPENOE = 1;

    #endif
    
    #ifdef GFX_HSYNC_ENABLE
                // set the HSYNC signal polarity
        _DPHSPOL = GFX_HSYNC_POLARITY;
        _DPHSOE = 1;

    #endif
    
    #ifdef GFX_VSYNC_ENABLE
                // set the VSYNC signal polarity
        _DPVSPOL = GFX_VSYNC_POLARITY;
        _DPVSOE = 1;
    
    #endif
    
    #ifdef GFX_DISPLAYPOWER_ENABLE
        // set the display power (GPWR) signal polarity 
        _DPPOWER = GFX_DISPLAYPOWER_POLARITY;
        _DPPWROE = 1;
    
    #endif
    
    /* Display timing signal configurations */
    // set the clock polarity   
    _DPCLKPOL = GFX_CLOCK_POLARITY;
    
    // set the display buffer dimension
    G1DPW = DISP_HOR_RESOLUTION;
    G1DPH = DISP_VER_RESOLUTION;
    
    // set the work area dimension
    G1PUW = DISP_HOR_RESOLUTION;
    G1PUH = DISP_VER_RESOLUTION;
    
    /* Note:
        In some display panel the definition of porches (front and back porches) varies.
        Example TFT display definitions (for horizontal timing):
                1. Horizontal Cycle = horizontal front porch + horizontal back porch + horizontal display period
                2. Horizontal Cycle = horizontal front porch + horizontal back porch + horizontal display period + horizontal sync pulse width
                In example (1) the horizontal sync pulse width must not exceed the horizontal back porch.
                For the vertical timing, the equations are the same (replace horizontal with vertical).
                
                For the Microchip graphics controller: the definition follows example (2). To accomodate displays like
                example (1), adjust the back porches and pulse widths accordingly. Refer to 
                FRM Section 43. Graphics Controller Module (GFX) (Document #:DS39731).
    */
    #define HT  (DISP_HOR_PULSE_WIDTH + DISP_HOR_BACK_PORCH + DISP_HOR_FRONT_PORCH + DISP_HOR_RESOLUTION)
    #define VT  (DISP_VER_PULSE_WIDTH + DISP_VER_BACK_PORCH + DISP_VER_FRONT_PORCH + DISP_VER_RESOLUTION)

    G1DPWT = HT;
    G1DPHT = VT;

        // set the horizontal pulse width
    _HSLEN = DISP_HOR_PULSE_WIDTH;
    _HSST  = 0; 
    
        // set the verrizontal pulse width
    _VSLEN = DISP_VER_PULSE_WIDTH;
    _VSST  = 0; 

        // set the horizontal & vertical start position
    _HENST = _HSST + DISP_HOR_PULSE_WIDTH + DISP_HOR_BACK_PORCH;
    _VENST = _VSST + DISP_VER_PULSE_WIDTH + DISP_VER_BACK_PORCH;

        // set the active pixel and active line start position
        _ACTPIX  = _HENST;
        _ACTLINE = _VENST;
        
        // initialize the work areas and display buffer base addresses global variables
    _workArea1BaseAddr   = GFX_DISPLAY_BUFFER_START_ADDRESS;
        _workArea2BaseAddr   = GFX_DISPLAY_BUFFER_START_ADDRESS;
        _displayAreaBaseAddr = GFX_DISPLAY_BUFFER_START_ADDRESS;

    // Set the display buffer base address (SFR) (or the start addresses in RAM) 
    GFX_SetDisplayArea(_displayAreaBaseAddr);   

    /* Switch On the Graphics Module */
    _GDBEN = 0xFFFF;
    _DPPINOE = 1;

    #ifdef USE_PALETTE
        // initialize the color look up table (CLUT) if enabled
        PaletteInit();
    
    #endif
        
    _G1CLKSEL = 1;                              // 96MHz Enable
    _GCLKDIV = GFX_GCLK_DIVIDER;        // value used is dependent on the display panel specification
    _DPSTGER = 0;                                       // display data stagger (set to none)
    _GFX1IF = 0;                                        // clear graphics interrupt flag 
    _GFX1IE = 0;                                        // graphics interrupt are not enabled
    _G1EN = 1;                                          // turn on the graphics module

    DelayMs(100);
    
    _DPPWROE = 1;                                       // enable the display power sequencer port to function as GPWR
    _DPPOWER = 1;                                       // turn on the display power sequencer  

        // clear the screen to all black first to remove the noise screen
        SetColor(0);
        Bar(0,0,GetMaxX(),GetMaxY());

    TCON_Init();                                // Panel Timing Controller (TCON) Programming

    DelayMs(100);

        // disable clipping (default setting)    
    SetClip(0);
}

/*********************************************************************
* Function: SetClip(control)
*
* Overview: Enables/disables clipping.
*
* PreCondition: none
*
* Input: control - Enables or disables the clipping.
*                       - 0: Disable clipping
*                       - 1: Enable clipping
*
* Output: none
*
* Side Effects: none
*
********************************************************************/
void SetClip(BYTE control)
{
    _clipRgn=control;
    
    if(_clipRgn)
    {
        GFX_WaitForCommandQueue(2);
        GFX_SetStartXY(_clipLeft, _clipTop);
        GFX_SetEndXY(_clipRight, _clipBottom) ;
    }
    else
    {
        GFX_WaitForCommandQueue(2);
        GFX_SetStartXY(0, 0);
        GFX_SetEndXY(GetMaxX(), GetMaxY());
    }
}

/*********************************************************************
* Function: SetClipRgn(left, top, right, bottom)
*
* Overview: Sets clipping region.
*
* PreCondition: none
*
* Input: left - Defines the left clipping region border.
*                top - Defines the top clipping region border.
*                right - Defines the right clipping region border.
*            bottom - Defines the bottom clipping region border.
*
* Output: none
*
* Side Effects: none
*
********************************************************************/
void SetClipRgn(SHORT left, SHORT top, SHORT right, SHORT bottom)
{
    _clipLeft=left;
    _clipTop=top;
    _clipRight=right;
    _clipBottom=bottom;

    if(_clipRgn)
    {
        SetClip(_clipRgn);
    }
}

/*********************************************************************
* Function: WORD MoveBlock(DWORD srcAddr, DWORD dstAddr, 
*                                                  DWORD srcOffset, DWORD dstOffset, 
*                                      WORD srcType, WORD dstType, 
*                          WORD width, WORD height)
*
* PreCondition: none
*
* Input: srcAddr - the base address of the data to be moved
*        dstAddr - the base address of the new location of the moved data 
*        srcOffset - offset of the data to be moved with respect to the 
*                                        source base address.
*        dstOffset - offset of the new location of the moved data respect 
*                                        to the source base address.
*        srcType - sets the source type (1 - continuous or 0 - discontinuous)
*        dstType - sets the source type (1 - continuous or 0 - discontinuous) 
*        width - width of the block of data to be moved
*        height - height of the block of data to be moved
*
* Output: none
*
* Side Effects: none
*
* Overview: puts pixel
*
* Note: none
*
********************************************************************/
WORD MoveBlock(DWORD srcAddr, DWORD dstAddr, DWORD srcOffset, DWORD dstOffset, 
                           WORD srcType, WORD dstType, WORD width, WORD height)
{
        // make sure there are no pending RCC GPU commands
    if(GFX_GetFreeCommandSpace() < 16)
    {
        #ifndef USE_NONBLOCKING_CONFIG
            GFX_WaitForCommandQueue(16);
        #else
            return (0);
        #endif
    } 

        // make sure the GPUs are not operating since changing the base addresses
        // will break the currently executing GPU command.
    #ifndef USE_NONBLOCKING_CONFIG
        GFX_WaitForGpu();
    #else    
        if (GFX_IsPuGpuBusy() == 1)
            return (0);
    #endif

        GFX_SetWorkArea1(srcAddr);
        GFX_SetWorkArea2(dstAddr);
        
        GFX_SetSrcAddress(srcOffset);
        GFX_SetDestAddress(dstOffset);

        GFX_SetRectSize(width, height);

        GFX_StartCopy(RCC_COPY, RCC_ROP_C, srcType, dstType);

        return (1);
        
}       

/*********************************************************************
* Function: WORD ScrollLeft(SHORT left, SHORT top,  
*                                                       SHORT right, SHORT bottom, SHORT delta)
*
* PreCondition: none
*
* Input: left - left position of the scrolled rectangle
*        top - top position of the scrolled rectangle
*        right - right position of the scrolled rectangle
*        bottom - bottom position of the scrolled rectangle
*        delta - defines the scroll delta
*
* Output: none
*
* Side Effects: none
*
* Overview: Scrolls the rectangular area defined by left, top, right, bottom by delta pixels.
*
* Note: none
*
********************************************************************/
WORD ScrollLeft(SHORT left, SHORT top, SHORT right, SHORT bottom, SHORT delta)
{
        DWORD address;
    SHORT width, height;

        // make sure there are no pending RCC GPU commands
    if(GFX_GetFreeCommandSpace() < 16)
    {
        #ifndef USE_NONBLOCKING_CONFIG
            GFX_WaitForCommandQueue(16);
        #else
            return (0);
        #endif
    }


        #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)

        width   =   right - left + 1;
        height  =   bottom - top + 1;

    #elif (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)

        height  =   right - left + 1;
        width   =   bottom - top + 1;
        #endif
        
        GFX_SetWorkArea1(_workArea1BaseAddr);
        GFX_SetWorkArea2(_workArea2BaseAddr); 

        address = (top * (DWORD)_PUW) + left;
        GFX_SetSrcAddress(address);

        address = (top * (DWORD)_PUW) + left - delta;
        GFX_SetDestAddress(address);

        GFX_SetRectSize(width, height);
        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_DEST_ADDR_DISCONTINUOUS,RCC_DEST_ADDR_DISCONTINUOUS);
        
        return (1);
}       


/*********************************************************************
* Function: void PutPixel(SHORT x, SHORT y)
*
* PreCondition: none
*
* Input: x,y - pixel coordinates
*
* Output: none
*
* Side Effects: none
*
* Overview: puts pixel
*
* Note: none
*
********************************************************************/
void PutPixel(SHORT x, SHORT y)
{

    if(_clipRgn)
    {
        if(x < _clipLeft)
            return;
        if(x > _clipRight)
            return;
        if(y < _clipTop)
            return;
        if(y > _clipBottom)
            return;
    }

    #if (DISP_ORIENTATION == 90)
    {
        SHORT t = x;
        x = y;
        y = GetMaxX() - t;
    }
    #elif (DISP_ORIENTATION == 180)
    {
        x = GetMaxX() - x;
        y = GetMaxY() - y;
    }
    #elif (DISP_ORIENTATION == 270)
    {
        SHORT t = x;
        x = GetMaxY() - y;
        y = t;
    }
    #endif

    #ifndef USE_DOUBLE_BUFFERING
        GFX_SetWorkArea2(_workArea2BaseAddr);
    #else
        GFX_SetWorkArea2(_drawbuffer);
    #endif

    GFX_WaitForCommandQueue(4);

    GFX_SetColor(_color.Val);
    GFX_SetDestAddress((y * (DWORD)DISP_HOR_RESOLUTION) + x);
    GFX_SetRectSize(1, 1);
    GFX_StartCopy(RCC_SOLID_FILL, RCC_ROP_C, RCC_SRC_ADDR_DISCONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);

    /* Note: No need to wait for  complete execution of the command even for Blocking Mode. The next commands will be in the queue & hence will execute only after the completion of this command. */
}

/*********************************************************************
* Function: WORD GetPixel(SHORT x, SHORT y)
*
* PreCondition: none
*
* Input: x,y - pixel coordinates 
*
* Output: pixel color
*
* Side Effects: none
*
* Overview: returns pixel color at x,y position
*
* Note: none
*
********************************************************************/
WORD GetPixel(SHORT x, SHORT y)
{
    volatile WORD getcolor = 0;
    
    if(x < 0 || y < 0 || x > GetMaxX() || y > GetMaxY())
    {
        return 1; /* Don't draw but return 1 */
    }

    #if (DISP_ORIENTATION == 90)
    {
        SHORT t = x;
        x = y;
        y = GetMaxX() - t;
    }
    #elif (DISP_ORIENTATION == 180)
    {
        x = GetMaxX() - x;
        y = GetMaxY() - y;
    }
    #elif (DISP_ORIENTATION == 270)
    {
        SHORT t = x;
        x = GetMaxY() - y;
        y = t;
    }
    #endif

    /* Wait till previous commands are fully executed */
    GFX_WaitForCommandQueue(GFX_COMMAND_QUEUE_LENGTH);
    GFX_WaitForGpu();

    #ifndef USE_DOUBLE_BUFFERING
        GFX_SetWorkArea1(_workArea1BaseAddr);
    #else
        GFX_SetWorkArea1(_drawbuffer);
    #endif    

    GFX_SetWorkArea2((WORD)&getcolor);

    GFX_WaitForCommandQueue(4);
    
    GFX_SetSrcAddress((y * (DWORD)DISP_HOR_RESOLUTION) + x);
    GFX_SetDestAddress(0);
    GFX_SetRectSize(1, 1);
    GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_DISCONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);

    /* Wait till the command is fully executed */
    GFX_WaitForCommandQueue(GFX_COMMAND_QUEUE_LENGTH);
    GFX_WaitForGpu();

    return (getcolor);
}

#ifdef USE_DRV_BAR
/*********************************************************************
* Function: WORD Bar(SHORT left, SHORT top, SHORT right, SHORT bottom)
*
* PreCondition: none
*
* Input: left,top - top left corner coordinates,
*        right,bottom - bottom right corner coordinates
*
* Output: For NON-Blocking configuration:
*         - Returns 0 when device is busy and the shape is not yet completely drawn.
*         - Returns 1 when the shape is completely drawn.
*         For Blocking configuration:
*         - Always return 1.
*
* Side Effects: none
*
* Overview: draws rectangle filled with current color
*
* Note: none
*
********************************************************************/
WORD Bar(SHORT left, SHORT top, SHORT right, SHORT bottom)
{
    DWORD address;
    SHORT width, height;

    if(left > right)
    {
        return (1); /* Don't draw but return 1 */
    }

    if(top > bottom)
    {
        return (1); /* Don't draw but return 1 */
    }
    
    if(_clipRgn)
    {
        if(left<_clipLeft)
           left = _clipLeft;
        if(right>_clipRight)
           right= _clipRight;
        if(top<_clipTop)
           top = _clipTop;
        if(bottom>_clipBottom)
           bottom = _clipBottom;
    }
    else
    {
            left    = (left < 0)    ? 0: (left > GetMaxX())  ? GetMaxX(): left;
            top     = (top < 0)     ? 0: (top > GetMaxY())   ? GetMaxY(): top;
            right   = (right < 0)   ? 0: (right > GetMaxX()) ? GetMaxX(): right;
            bottom  = (bottom < 0)  ? 0: (bottom > GetMaxY())? GetMaxY(): bottom;
    }

    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)

        width   =   right - left + 1;
        height  =   bottom - top + 1;

    #elif (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)

        height  =   right - left + 1;
        width   =   bottom - top + 1;

    #endif

    #if (DISP_ORIENTATION == 90)

        bottom  =   DISP_VER_RESOLUTION - left;
        left    =   top;
        right   =   left + width;
        top     =   bottom - height;

    #elif (DISP_ORIENTATION == 180)

        right   =   DISP_HOR_RESOLUTION - left;
        bottom  =   DISP_VER_RESOLUTION - top;
        left    =   right - width;
        top     =   bottom - height;

    #elif (DISP_ORIENTATION == 270)

        right   =   DISP_HOR_RESOLUTION - top;
        top     =   left;
        bottom  =   top + height;
        left    =   right - width;

    #endif

    if(GFX_GetFreeCommandSpace() < 4)
    {
        #ifndef USE_NONBLOCKING_CONFIG
            GFX_WaitForCommandQueue(4);
        #else
            return (0);
        #endif
    }

    address = (top * (DWORD)DISP_HOR_RESOLUTION) + left;

    #ifndef USE_DOUBLE_BUFFERING
        GFX_SetWorkArea2(_workArea2BaseAddr);
    #else
        GFX_SetWorkArea2(_drawbuffer);
    #endif

    GFX_SetColor(_color.Val);
    GFX_SetDestAddress(address);
    GFX_SetRectSize(width, height);
    GFX_StartCopy(RCC_SOLID_FILL, RCC_ROP_C, RCC_SRC_ADDR_DISCONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
    
    /* Note: No need to wait for  complete execution of the command even for Blocking Mode. The next commands will be in the queue & hence will execute only after the completion of this command. */
    return (1);
}
#endif

#ifdef USE_DRV_CLEARDEVICE
/*********************************************************************
* Function: void ClearDevice(void)
*
* PreCondition: none
*
* Input: none
*
* Output: none
*
* Side Effects: none
*
* Overview: clears screen with current color 
*
* Note: none
*
********************************************************************/
void ClearDevice(void)
{
    GFX_WaitForCommandQueue(4);

    #ifndef USE_DOUBLE_BUFFERING
        GFX_SetWorkArea2(_workArea2BaseAddr);
    #else
        GFX_SetWorkArea2(_drawbuffer);
    #endif

    GFX_SetColor(_color.Val);
    GFX_SetDestAddress(0);
    GFX_SetRectSize(DISP_HOR_RESOLUTION, DISP_VER_RESOLUTION);
    GFX_StartCopy(RCC_SOLID_FILL, RCC_ROP_C, RCC_SRC_ADDR_DISCONTINUOUS, RCC_DEST_ADDR_CONTINUOUS);

    /* Note: No need to wait for  complete execution of the command even for Blocking Mode. The next commands will be in the queue & hence will execute only after the completion of this command. */
}
#endif

#ifdef USE_DRV_LINE
/*********************************************************************
* Function: WORD Line(SHORT x1, SHORT y1, SHORT x2, SHORT y2)
*
* PreCondition: none
*
* Input: x1,y1 - starting coordinates, x2,y2 - ending coordinates
*
* Output: For NON-Blocking configuration:
*         - Returns 0 when device is busy and the shape is not yet completely drawn.
*         - Returns 1 when the shape is completely drawn.
*         For Blocking configuration:
*         - Always return 1.
*
* Side Effects: none
*
* Overview: draws line
*
* Note: none
*
********************************************************************/

WORD Line(SHORT x1, SHORT y1, SHORT x2, SHORT y2)
{
    SHORT   deltaX, deltaY;
    SHORT   error, stepErrorLT, stepErrorGE;
    SHORT   stepX, stepY;
    SHORT   steep;
    SHORT   temp;
    SHORT   style, type;

    if((_lineType == 0) && ((x1 == x2) || (y1 == y2)))
    {
        if(x1 > x2)
        {
            temp = x1;
            x1 = x2;
            x2 = temp;
        }
        else if(y1 > y2)
        {
            temp = y1;
            y1 = y2;
            y2 = temp;
        }

        if(_lineThickness)
        {
            if(x1 == x2)
            {
                if(!Bar(x1 - 1, y1, x2 + 1, y2)) return (0);
            }
            else
            {
                if(!Bar(x1, y1 - 1, x2, y2 + 1)) return (0);
            }
        }
        else
        {
            if(!Bar(x1, y1, x2, y2)) return (0);
        }

        return (1);
    }

    // Move cursor
    MoveTo(x2, y2);

    if(x1 == x2)
    {
        if(y1 > y2)
        {
            temp = y1;
            y1 = y2;
            y2 = temp;
        }

        style = 0;
        type = 1;
        for(temp = y1; temp < y2 + 1; temp++)
        {
            if((++style) == _lineType)
            {
                type ^= 1;
                style = 0;
            }

            if(type)
            {
                PutPixel(x1, temp);
                if(_lineThickness)
                {
                    PutPixel(x1 + 1, temp);
                    PutPixel(x1 - 1, temp);
                }
            }
        }

        return (1);
    }

    if(y1 == y2)
    {
        if(x1 > x2)
        {
            temp = x1;
            x1 = x2;
            x2 = temp;
        }

        style = 0;
        type = 1;
        for(temp = x1; temp < x2 + 1; temp++)
        {
            if((++style) == _lineType)
            {
                type ^= 1;
                style = 0;
            }

            if(type)
            {
                PutPixel(temp, y1);
                if(_lineThickness)
                {
                    PutPixel(temp, y1 + 1);
                    PutPixel(temp, y1 - 1);
                }
            }
        }

        return (1);
    }

    stepX = 0;
    deltaX = x2 - x1;
    if(deltaX < 0)
    {
        deltaX = -deltaX;
        --stepX;
    }
    else
    {
        ++stepX;
    }

    stepY = 0;
    deltaY = y2 - y1;
    if(deltaY < 0)
    {
        deltaY = -deltaY;
        --stepY;
    }
    else
    {
        ++stepY;
    }

    steep = 0;
    if(deltaX < deltaY)
    {
        ++steep;
        temp = deltaX;
        deltaX = deltaY;
        deltaY = temp;
        temp = x1;
        x1 = y1;
        y1 = temp;
        temp = stepX;
        stepX = stepY;
        stepY = temp;
        PutPixel(y1, x1);
    }
    else
    {
        PutPixel(x1, y1);
    }

    // If the current error greater or equal zero
    stepErrorGE = deltaX << 1;

    // If the current error less than zero
    stepErrorLT = deltaY << 1;

    // Error for the first pixel
    error = stepErrorLT - deltaX;

    style = 0;
    type = 1;

    while(--deltaX >= 0)
    {
        if(error >= 0)
        {
            y1 += stepY;
            error -= stepErrorGE;
        }

        x1 += stepX;
        error += stepErrorLT;

        if((++style) == _lineType)
        {
            type ^= 1;
            style = 0;
        }

        if(type)
        {
            if(steep)
            {
                PutPixel(y1, x1);
                if(_lineThickness)
                {
                    PutPixel(y1 + 1, x1);
                    PutPixel(y1 - 1, x1);
                }
            }
            else
            {
                PutPixel(x1, y1);
                if(_lineThickness)
                {
                    PutPixel(x1, y1 + 1);
                    PutPixel(x1, y1 - 1);
                }
            }
        }
    }   // end of while

    return (1);
}

#endif

#ifdef USE_DRV_FONT

/*********************************************************************
* Function: void SetFont(void* font)
*
* PreCondition: none
*
* Input: pointer to the font image
*
* Output: none
*
* Side Effects: none
*
* Overview: defines current font
*
* Note: none
*
********************************************************************/
void SetFont(void *font)
{
    FONT_HEADER *pHeader;

        #ifdef USE_FONT_EXTERNAL
    FONT_HEADER header;
        #endif

    if(_font == font)
    {
        return;
    }

    _font = font;
    switch(*((SHORT *)font))
    {
                        #ifdef USE_FONT_RAM
        case RAM:
            pHeader = (FONT_HEADER *) ((FONT_RAM *)font)->address;
            GFX_WaitForCommandQueue(1);
            GFX_SetFont((WORD)pHeader);
            break;
                #endif
                
                #ifdef USE_FONT_FLASH
        case FLASH:
            pHeader = (FONT_HEADER *) ((FONT_FLASH *)font)->address;
            break;
                #endif
                
                #ifdef USE_FONT_EXTERNAL

        case EXTERNAL:
            pHeader = &header;
            ExternalMemoryCallback(font, 0, sizeof(FONT_HEADER), pHeader);
            break;
                #endif

        default:
            return;
    }

    _fontFirstChar = pHeader->firstChar;
    _fontLastChar = pHeader->lastChar;
    _fontHeight = pHeader->height;
}

/*********************************************************************
* Function: WORD OutChar(XCHAR ch)
*
* PreCondition: none
*
* Input: character code
*
* Output: For NON-Blocking configuration:
*         - Returns 0 when device is busy and the character is not yet completely drawn.
*         - Returns 1 when the character is completely drawn.
*         For Blocking configuration:
*         - Always return 1.
*
* Side Effects: none
*
* Overview: outputs a character
*
* Note: none
*
********************************************************************/
WORD OutChar(XCHAR ch)
{
    GLYPH_ENTRY *pChTable = NULL;
    BYTE        *pChImage = NULL;

        #ifdef USE_FONT_EXTERNAL
    GLYPH_ENTRY chTable;
    BYTE        chImage[EXTERNAL_FONT_BUFFER_SIZE];
    WORD        imageSize;
    DWORD_VAL   glyphOffset;
        #endif
    SHORT       chWidth = 0;
    SHORT       xCnt, yCnt, x = 0, y;
    BYTE        temp = 0, mask;

    if(GFX_GetFreeCommandSpace() < 2)
    {
        #ifndef USE_NONBLOCKING_CONFIG
            GFX_WaitForCommandQueue(2);
        #else
            return (0);
        #endif
    }

    if((unsigned XCHAR)ch < (unsigned XCHAR)_fontFirstChar)
        return (-1);
    if((unsigned XCHAR)ch > (unsigned XCHAR)_fontLastChar)
        return (-1);

    switch(*((SHORT *)_font))
    {

        case RAM:
            if(_fontOrientation == ORIENT_HOR)
            {
                    pChTable = (GLYPH_ENTRY *) (((FONT_RAM *)_font)->address + sizeof(FONT_HEADER)) + ((unsigned XCHAR)ch - (unsigned XCHAR)_fontFirstChar);
        
                    pChImage = (BYTE *) (((FONT_RAM *)_font)->address + pChTable->offsetLSB);
        
                    chWidth = pChTable->width;
                    
                    if(_chrcolor.Val != _color.Val)
                    {
                        GFX_WaitForCommandQueue(3);  /* Already 2 commands space will be available */
                        GFX_SetCharFgColor(_color.Val);
                    }

                #ifndef USE_DOUBLE_BUFFERING
                    GFX_SetWorkArea1(_workArea1BaseAddr);
                #else
                    GFX_SetWorkArea1(_drawbuffer);
                #endif

                    GFX_SetPrintXY(GetX(), GetY());
                    GFX_PrintChar(ch, CHR_TRANSPARENT);
            
                MoveTo(GetX() + chWidth, GetY());
            }
            else
            {
                    // if orientation is vertical, process the font using PutPixel.
                    pChTable = (GLYPH_ENTRY *) (((FONT_FLASH *)_font)->address + sizeof(FONT_HEADER)) + ((unsigned XCHAR)ch - (unsigned XCHAR)_fontFirstChar);
                    pChImage = (BYTE *) (((FONT_FLASH *)_font)->address + ((DWORD)(pChTable->offsetMSB) << 8) + pChTable->offsetLSB);
                    chWidth = pChTable->width;
                break;
            }

            return (1);


                #ifdef USE_FONT_FLASH

        case FLASH:
        
            // if font is from FLASH process the font using PutPixel.
            pChTable = (GLYPH_ENTRY *) (((FONT_FLASH *)_font)->address + sizeof(FONT_HEADER)) + ((unsigned XCHAR)ch - (unsigned XCHAR)_fontFirstChar);
            pChImage = (BYTE *) (((FONT_FLASH *)_font)->address + ((DWORD)(pChTable->offsetMSB) << 8) + pChTable->offsetLSB);
            chWidth = pChTable->width;
            break;
                #endif
                
                #ifdef USE_FONT_EXTERNAL

        case EXTERNAL:

            // get glyph entry
            ExternalMemoryCallback
            (
                _font,
                sizeof(FONT_HEADER) + ((unsigned XCHAR)ch - (unsigned XCHAR)_fontFirstChar) * sizeof(GLYPH_ENTRY),
                sizeof(GLYPH_ENTRY),
                &chTable
            );

            chWidth = chTable.width;

            // width of glyph in bytes
            imageSize = 0;
            if(chWidth & 0x0007)
                imageSize = 1;
            imageSize += (chWidth >> 3);

            // glyph image size
            imageSize *= _fontHeight;

            // get glyph image
            glyphOffset.w[1] = chTable.offsetMSB;
            glyphOffset.w[0] = chTable.offsetLSB;

            ExternalMemoryCallback(_font, glyphOffset.Val, imageSize, &chImage);
            pChImage = (BYTE *) &chImage;

            break;
                #endif

        default:
            break;
    }

    if(_fontOrientation == ORIENT_HOR)
    {
        y = GetY();
        for(yCnt = 0; yCnt < _fontHeight; yCnt++)
        {
            x = GetX();
            mask = 0;
            for(xCnt = 0; xCnt < chWidth; xCnt++)
            {
                if(mask == 0)
                {
                    temp = *pChImage++;
                    mask = 0x01;
                }

                if(temp & mask)
                {
                    PutPixel(x, y);
                }

                x++;
                mask <<= 1;
            }

            y++;
        }

        // move cursor
        _cursorX = x;
    }
    else
    {
        y = GetX();
        for(yCnt = 0; yCnt < _fontHeight; yCnt++)
        {
            x = GetY();
            mask = 0;
            for(xCnt = 0; xCnt < chWidth; xCnt++)
            {
                if(mask == 0)
                {
                    temp = *pChImage++;
                    mask = 0x01;
                }

                if(temp & mask)
                {
                    PutPixel(y, x);
                }

                x--;
                mask <<= 1;
            }

            y++;
        }

        // move cursor
        _cursorY = x;
    }

    return (1);
}

#endif

#ifdef USE_DRV_PUTIMAGE

    #ifdef USE_BITMAP_FLASH

/*********************************************************************
* Function: void PutImage1BPP(SHORT left, SHORT top, FLASH_BYTE* bitmap, BYTE stretch)
*
* PreCondition: none
*
* Input: left,top - left top image corner,
*        bitmap - image pointer,
*        stretch - image stretch factor
*
* Output: none
*
* Side Effects: none
*
* Overview: outputs monochrome image starting from left,top coordinates
*
* Note: image must be located in flash
*
********************************************************************/
void PutImage1BPP(SHORT left, SHORT top, FLASH_BYTE *bitmap, BYTE stretch)
{
    register FLASH_BYTE *flashAddress;
    register FLASH_BYTE *tempFlashAddress;
    BYTE                temp = 0;
    WORD                sizeX, sizeY;
    WORD                x, y;
    WORD                xc, yc;
    BYTE                stretchX, stretchY;
    WORD                palette[2], color;
    BYTE                mask;
#if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
    WORD                outputSize;
    WORD                lineBuffer[(GetMaxX() + (DWORD) 1)];
    WORD                *pData; 

        GFX_WaitForCommandQueue(16);
        GFX_WaitForGpu();

#endif

    // Move pointer to size information
    flashAddress = bitmap + 2;

    // Read image size
    sizeY = *((FLASH_WORD *)flashAddress);
    flashAddress += 2;
    sizeX = *((FLASH_WORD *)flashAddress);
    flashAddress += 2;
    palette[0] = *((FLASH_WORD *)flashAddress);
    flashAddress += 2;
    palette[1] = *((FLASH_WORD *)flashAddress);
    flashAddress += 2;

    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                if (stretch == IMAGE_X2) {
                        outputSize = sizeX << 1;
                }       
                else //if (stretch == IMAGE_NORMAL)
                {
                        outputSize = sizeX;
                }
                GFX_SetWorkArea1((WORD)lineBuffer);
                GFX_SetWorkArea2(GFX_DISPLAY_BUFFER_START_ADDRESS);
                GFX_SetRectSize(outputSize, 1);
                GFX_SetSrcAddress(0);
        #endif  

    yc = top;
    for(y = 0; y < sizeY; y++)
    {
        tempFlashAddress = flashAddress;
        for(stretchY = 0; stretchY < stretch; stretchY++)
        {
            flashAddress = tempFlashAddress;
            mask = 0;
            xc = left;

                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                pData = lineBuffer;
            #endif      

            for(x = 0; x < sizeX; x++)
            {

                // Read 8 pixels from flash
                if(mask == 0)
                {
                    temp = *flashAddress;
                    flashAddress++;
                    mask = 0x80;
                }

                // Set color
                if(mask & temp)
                {
                        // Set color
                        #ifdef USE_PALETTE
                            color = 1;
                        #else
                            color = palette[1];
                        #endif
                }
                else
                {
                        // Set color
                        #ifdef USE_PALETTE
                            color = 0;
                        #else
                            color = palette[0];
                        #endif
                }
                                #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                                        SetColor(color); 
                                #endif  
                
                // Write pixel to screen
                for(stretchX = 0; stretchX < stretch; stretchX++)
                {
                                        #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                        PutPixel(xc++, yc);
                    #else
                                *pData++ = color;
                    #endif                                      
                }

                // Shift to the next pixel
                mask >>= 1;
            }
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                        GFX_WaitForCommandQueue(2);
                        GFX_SetDestAddress((yc * (DWORD)DISP_HOR_RESOLUTION) + left);
                        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_CONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
                        #endif  
            yc++;
        }
    }
}

/*********************************************************************
* Function: void PutImage4BPP(SHORT left, SHORT top, FLASH_BYTE* bitmap, BYTE stretch)
*
* PreCondition: none
*
* Input: left,top - left top image corner, bitmap - image pointer,
*        stretch - image stretch factor
*
* Output: none
*
* Side Effects: none
*
* Overview: outputs 16 color image starting from left,top coordinates
*
* Note: image must be located in flash
*
********************************************************************/
        #if (COLOR_DEPTH >= 4)

void PutImage4BPP(SHORT left, SHORT top, FLASH_BYTE *bitmap, BYTE stretch)
{
    register FLASH_BYTE *flashAddress;
    register FLASH_BYTE *tempFlashAddress;
    WORD                sizeX, sizeY;
    register WORD       x, y;
    WORD                xc, yc;
    BYTE                temp = 0;
    register BYTE       stretchX, stretchY;
    WORD                palette[16], color;
    WORD                counter;

#if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
    WORD                outputSize;
    WORD                lineBuffer[(GetMaxX() + (DWORD) 1)];
    WORD                *pData; 

        GFX_WaitForCommandQueue(16);
        GFX_WaitForGpu();

#endif
    // Move pointer to size information
    flashAddress = bitmap + 2;

    // Read image size
    sizeY = *((FLASH_WORD *)flashAddress);
    flashAddress += 2;
    sizeX = *((FLASH_WORD *)flashAddress);
    flashAddress += 2;

    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                if (stretch == IMAGE_X2) {
                        outputSize = sizeX << 1;
                }       
                else //if (stretch == IMAGE_NORMAL)
                {
                        outputSize = sizeX;
                }
                GFX_SetWorkArea1((WORD)lineBuffer);
                GFX_SetWorkArea2(GFX_DISPLAY_BUFFER_START_ADDRESS);
                GFX_SetRectSize(outputSize, 1);
                GFX_SetSrcAddress(0);
        #endif  

    // Read palette
    for(counter = 0; counter < 16; counter++)
    {
        palette[counter] = *((FLASH_WORD *)flashAddress);
        flashAddress += 2;
    }

    yc = top;
    for(y = 0; y < sizeY; y++)
    {
        tempFlashAddress = flashAddress;
        for(stretchY = 0; stretchY < stretch; stretchY++)
        {
            flashAddress = tempFlashAddress;
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                pData = lineBuffer;
            #endif      
            xc = left;
            for(x = 0; x < sizeX; x++)
            {

                // Read 2 pixels from flash
                if((x & 0x0001) == 0)
                {
                    temp = *flashAddress;
                    flashAddress++;
                }
                
                    #ifdef USE_PALETTE
                        color = temp >> ((x&0x0001)*4) & 0x000F;
                    #else
                        color = palette[(temp >> ((x&0x0001)*4)) & 0x000F];
                    #endif
                
                                #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                            SetColor(color);
                                #endif  

                // Write pixel to screen
                for(stretchX = 0; stretchX < stretch; stretchX++)
                {
                                        #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                        PutPixel(xc++, yc);
                    #else
                                *pData++ = color;
                    #endif                                  
                                }
                        }
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                        GFX_WaitForCommandQueue(2);
                        GFX_SetDestAddress((yc * (DWORD)DISP_HOR_RESOLUTION) + left);
                        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_CONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
                        #endif  
            yc++;
        }
    }
}

        #endif //#if (COLOR_DEPTH >= 4)

/*********************************************************************
* Function: void PutImage8BPP(SHORT left, SHORT top, FLASH_BYTE* bitmap, BYTE stretch)
*
* PreCondition: none
*
* Input: left,top - left top image corner, bitmap - image pointer,
*        stretch - image stretch factor
*
* Output: none
*
* Side Effects: none
*
* Overview: outputs 256 color image starting from left,top coordinates
*
* Note: image must be located in flash
*
********************************************************************/
        #if (COLOR_DEPTH >= 8)

void PutImage8BPP(SHORT left, SHORT top, FLASH_BYTE *bitmap, BYTE stretch)
{
    register FLASH_BYTE *flashAddress;
    register FLASH_BYTE *tempFlashAddress;
    WORD                sizeX, sizeY;
    WORD                x, y;
    WORD                xc, yc;
    BYTE                temp;
    BYTE                stretchX, stretchY;
    WORD                palette[256], color;
    WORD                counter;

#if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
    WORD                outputSize;
    WORD                lineBuffer[(GetMaxX() + (DWORD) 1)];
    WORD                *pData; 

        GFX_WaitForCommandQueue(16);
        GFX_WaitForGpu();

#endif

    // Move pointer to size information
    flashAddress = bitmap + 2;

    // Read image size
    sizeY = *((FLASH_WORD *)flashAddress);
    flashAddress += 2;
    sizeX = *((FLASH_WORD *)flashAddress);
    flashAddress += 2;

    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                if (stretch == IMAGE_X2) {
                        outputSize = sizeX << 1;
                }       
                else //if (stretch == IMAGE_NORMAL)
                {
                        outputSize = sizeX;
                }               
                GFX_SetWorkArea1((WORD)lineBuffer);
                GFX_SetWorkArea2(GFX_DISPLAY_BUFFER_START_ADDRESS);
                GFX_SetRectSize(outputSize, 1);
                GFX_SetSrcAddress(0);
        #endif  

    // Read palette
    for(counter = 0; counter < 256; counter++)
    {
        palette[counter] = *((FLASH_WORD *)flashAddress);
        flashAddress += 2;
    }

    yc = top;
    for(y = 0; y < sizeY; y++)
    {
        tempFlashAddress = flashAddress;
        for(stretchY = 0; stretchY < stretch; stretchY++)
        {
            flashAddress = tempFlashAddress;
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                pData = lineBuffer;
            #endif      
            xc = left;
            
            for(x = 0; x < sizeX; x++)
            {
                // Read pixels from flash
                temp = *flashAddress;
                flashAddress++;

                    #ifdef USE_PALETTE
                        color = temp;
                    #else
                        color = palette[temp];
                    #endif
                                #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                            SetColor(color);
                                #endif  

                // Write pixel to buffer
                for(stretchX = 0; stretchX < stretch; stretchX++)
                {
                                        #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                        PutPixel(xc++, yc);
                    #else
                                *pData++ = color;
                    #endif                                      
                }
            }
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                        GFX_WaitForCommandQueue(2);
                        GFX_SetDestAddress((yc * (DWORD)DISP_HOR_RESOLUTION) + left);
                        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_CONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
                        #endif  
            yc++;
        }
    }
}

        #endif //#if (COLOR_DEPTH >= 8)

/*********************************************************************
* Function: void PutImage16BPP(SHORT left, SHORT top, FLASH_BYTE* bitmap, BYTE stretch)
*
* PreCondition: none
*
* Input: left,top - left top image corner, bitmap - image pointer,
*        stretch - image stretch factor
*
* Output: none
*
* Side Effects: none
*
* Overview: outputs hicolor image starting from left,top coordinates
*
* Note: image must be located in flash
*
********************************************************************/
                #if (COLOR_DEPTH == 16)
void PutImage16BPP(SHORT left, SHORT top, FLASH_BYTE *bitmap, BYTE stretch)
{
    register FLASH_WORD *flashAddress;
    register FLASH_WORD *tempFlashAddress;
    WORD                sizeX, sizeY;
    register WORD       x, y;
    WORD                xc, yc;
    WORD                temp;
    register BYTE       stretchX, stretchY;

#if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
        WORD                            outputSize;
    WORD                lineBuffer[(GetMaxX() + (DWORD) 1)];
    WORD                *pData; 


        GFX_WaitForCommandQueue(16);
        GFX_WaitForGpu();

#endif


    // Move pointer to size information
    flashAddress = (FLASH_WORD *)bitmap + 1;

    // Read image size
    sizeY = *flashAddress;
    flashAddress++;
    sizeX = *flashAddress;
    flashAddress++;

    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                if (stretch == IMAGE_X2) {
                    outputSize = sizeX << 1;
                }
                else 
                {
                    outputSize = sizeX;
                }               
                GFX_SetWorkArea1((WORD)lineBuffer);
                GFX_SetWorkArea2(GFX_DISPLAY_BUFFER_START_ADDRESS);
                GFX_SetRectSize(outputSize, 1);
                GFX_SetSrcAddress(0);
        #endif  

    yc = top;
    for(y = 0; y < sizeY; y++)
    {
        tempFlashAddress = flashAddress;
        for(stretchY = 0; stretchY < stretch; stretchY++)
        {
            flashAddress = tempFlashAddress;
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                pData = lineBuffer;
            #endif      
            xc = left;
            
            for(x = 0; x < sizeX; x++)
            {
                temp = *flashAddress;
                flashAddress++;
                                #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                                        SetColor(temp);
                                #endif  

                // Write pixel to buffer
                for(stretchX = 0; stretchX < stretch; stretchX++)
                {
                                        #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                        PutPixel(xc++, yc);
                    #else
                                *pData++ = temp;
                    #endif                                      
                }
            }
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                        GFX_WaitForCommandQueue(2);
                        GFX_SetDestAddress((yc * (DWORD)DISP_HOR_RESOLUTION) + left);
                        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_CONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
                        #endif  
            yc++;
        }
    }    
}       
        #endif // #if (COLOR_DEPTH == 16)
    #endif //USE_BITMAP_FLASH
        
    #ifdef USE_BITMAP_EXTERNAL

/*********************************************************************
* Function: void PutImage1BPPExt(SHORT left, SHORT top, void* bitmap, BYTE stretch)
*
* PreCondition: none
*
* Input: left,top - left top image corner, bitmap - image pointer,
*        stretch - image stretch factor
*
* Output: none
*
* Side Effects: none
*
* Overview: outputs monochrome image starting from left,top coordinates
*
* Note: image must be located in external memory
*
********************************************************************/
void PutImage1BPPExt(SHORT left, SHORT top, void *bitmap, BYTE stretch)
{
    register DWORD  memOffset;
    BITMAP_HEADER   bmp;
    BYTE            lineBuffer[((GetMaxX() + (DWORD) 1) / 8) + 1];
    WORD            palette[2], color;
    BYTE            *pData; 
#if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
    WORD                        *pBufAddr, *pData2;
    WORD            lineBuffer2[(GetMaxX() + (DWORD) 1)];
    WORD                        outputSize;
#endif    
    SHORT           byteWidth;
    BYTE            mask, temp = 0;
    WORD            sizeX, sizeY;
    WORD            x, y;
    WORD            xc, yc;
    BYTE            stretchX, stretchY;

    // Get bitmap header
    ExternalMemoryCallback(bitmap, 0, sizeof(BITMAP_HEADER), &bmp);
    // Get palette (2 entries)
    ExternalMemoryCallback(bitmap, sizeof(BITMAP_HEADER), 2 * sizeof(WORD), palette);
    // Set offset to the image data
        memOffset = sizeof(BITMAP_HEADER) + 2 * sizeof(WORD);
        
    // Get size
    sizeX = bmp.width;
    sizeY = bmp.height;

        // Line width in bytes
    byteWidth = sizeX >> 3;
    if(sizeX & 0x0007)
        byteWidth++;    
    
        yc = top;

        GFX_WaitForCommandQueue(16);
        GFX_WaitForGpu();

    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                if (stretch == IMAGE_X2) {
                        outputSize = sizeX << 1;
                }       
                else //if (stretch == IMAGE_NORMAL)
                {
                        outputSize = sizeX;
                }               
                pBufAddr = lineBuffer2;
                GFX_SetWorkArea1((WORD)pBufAddr);
                GFX_SetWorkArea2(GFX_DISPLAY_BUFFER_START_ADDRESS);
                GFX_SetRectSize(outputSize, 1);
                GFX_SetSrcAddress(0);
        #endif  

    for(y = 0; y < sizeY; y++)
    {
        // Get line
        ExternalMemoryCallback(bitmap, memOffset, byteWidth, lineBuffer);
        memOffset += byteWidth;
        for(stretchY = 0; stretchY < stretch; stretchY++)
        {
                pData = lineBuffer;
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                pData2 = lineBuffer2;
            #endif      
        
                        mask = 0;
            xc = left;
            for(x = 0; x < sizeX; x++)
            {

                                if (mask == 0) 
                                {
                                        temp = *pData++;
                                        mask = 0x80;
                                }       
                                if (mask & temp)
                                {
                            #ifdef USE_PALETTE
                                color = 1;
                            #else       
                                color = palette[1];
                            #endif
                                } 
                                else
                                {
                            #ifdef USE_PALETTE
                                color = 0;
                            #else       
                                color = palette[0];
                            #endif
                                }               
                                #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                                        SetColor(color); 
                                #endif  

                // Write pixel to buffer
                for(stretchX = 0; stretchX < stretch; stretchX++)
                {
                                        #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                        PutPixel(xc++, yc);
                    #else
                                *pData2++ = color;
                    #endif                                      
                }
                mask >>= 1;
            }
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                        GFX_WaitForCommandQueue(2);
                        GFX_SetDestAddress((yc * (DWORD)DISP_HOR_RESOLUTION) + left);
                        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_CONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
                        #endif  
            yc++;
        }
    }

}


/*********************************************************************
* Function: void PutImage4BPPExt(SHORT left, SHORT top, void* bitmap, BYTE stretch)
*
* PreCondition: none
*
* Input: left,top - left top image corner, bitmap - image pointer,
*        stretch - image stretch factor
*
* Output: none
*
* Side Effects: none
*
* Overview: outputs monochrome image starting from left,top coordinates
*
* Note: image must be located in external memory
*
********************************************************************/
        #if (COLOR_DEPTH >= 4)

void PutImage4BPPExt(SHORT left, SHORT top, void *bitmap, BYTE stretch)
{
    register DWORD  memOffset;
    BITMAP_HEADER   bmp;
    BYTE            lineBuffer[((GetMaxX() + (DWORD) 1) / 2) + 1];
    WORD            palette[16], color;
    BYTE            *pData; 
#if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
    WORD                        *pBufAddr, *pData2;
    WORD            lineBuffer2[(GetMaxX() + (DWORD) 1)];
    WORD                         outputSize;
#endif    
    SHORT           byteWidth;
    BYTE            temp = 0;
    WORD            sizeX, sizeY;
    WORD            x, y;
    WORD            xc, yc;
    BYTE            stretchX, stretchY;

    // Get bitmap header
    ExternalMemoryCallback(bitmap, 0, sizeof(BITMAP_HEADER), &bmp);
    // Get palette (16 entries)
    ExternalMemoryCallback(bitmap, sizeof(BITMAP_HEADER), 16 * sizeof(WORD), palette);
    // Set offset to the image data
        memOffset = sizeof(BITMAP_HEADER) + 16 * sizeof(WORD);
        
    // Get size
    sizeX = bmp.width;
    sizeY = bmp.height;

        // Line width in bytes
    byteWidth = sizeX >> 1;
    if(sizeX & 0x0001)
        byteWidth++;    
    
        yc = top;

        GFX_WaitForCommandQueue(16);
        GFX_WaitForGpu();

    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                if (stretch == IMAGE_X2) {
                        outputSize = sizeX << 1;
                }       
                else //if (stretch == IMAGE_NORMAL)
                {
                        outputSize = sizeX;
                }
                pBufAddr = lineBuffer2;
                GFX_SetWorkArea1((WORD)pBufAddr);
                GFX_SetWorkArea2(GFX_DISPLAY_BUFFER_START_ADDRESS);
                GFX_SetRectSize(outputSize, 1);
                GFX_SetSrcAddress(0);
        #endif  

    for(y = 0; y < sizeY; y++)
    {
        // Get line
        ExternalMemoryCallback(bitmap, memOffset, byteWidth, lineBuffer);
        memOffset += byteWidth;
        for(stretchY = 0; stretchY < stretch; stretchY++)
        {
                pData = lineBuffer;
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                pData2 = lineBuffer2;
            #endif      
        
            xc = left;
            for(x = 0; x < sizeX; x++)
            {
                                if ((x & 0x0001) == 0)
                                        temp = *pData++;

                    #ifdef USE_PALETTE
                        color = temp >> ((x&0x0001)*4)) & 0x000F;
                    #else
                        color = palette[(temp >> ((x&0x0001)*4)) & 0x000F];
                    #endif
                                #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                                        SetColor(color); 
                                #endif  

                // Write pixel to buffer
                for(stretchX = 0; stretchX < stretch; stretchX++)
                {
                                        #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                        PutPixel(xc++, yc);
                    #else
                                *pData2++ = color;
                    #endif                                      
                }
            }
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                        GFX_WaitForCommandQueue(2);
                        GFX_SetDestAddress((yc * (DWORD)DISP_HOR_RESOLUTION) + left);
                        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_CONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
                        #endif  
            yc++;
        }
    }
}

        #endif //#if (COLOR_DEPTH >= 4)

/*********************************************************************
* Function: void PutImage8BPPExt(SHORT left, SHORT top, void* bitmap, BYTE stretch)
*
* PreCondition: none
*
* Input: left,top - left top image corner, bitmap - image pointer,
*        stretch - image stretch factor
*
* Output: none
*
* Side Effects: none
*
* Overview: outputs monochrome image starting from left,top coordinates
*
* Note: image must be located in external memory
*
********************************************************************/
        #if (COLOR_DEPTH >= 8)

void PutImage8BPPExt(SHORT left, SHORT top, void *bitmap, BYTE stretch)
{
    register DWORD  memOffset;
    BITMAP_HEADER   bmp;
    BYTE            lineBuffer[(GetMaxX() + (DWORD) 1)];
    WORD            palette[256], color;
    BYTE            *pData; 
#if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
    WORD                        *pBufAddr, *pData2;
    WORD            lineBuffer2[(GetMaxX() + (DWORD) 1)];
    WORD                        outputSize;
#endif    

    BYTE            temp;
    WORD            sizeX, sizeY;
    WORD            x, y;
    WORD            xc, yc;
    BYTE            stretchX, stretchY;

    // Get bitmap header
    ExternalMemoryCallback(bitmap, 0, sizeof(BITMAP_HEADER), &bmp);
    // Get palette (256 entries)
    ExternalMemoryCallback(bitmap, sizeof(BITMAP_HEADER), 256 * sizeof(WORD), palette);
    // Set offset to the image data
        memOffset = sizeof(BITMAP_HEADER) + 256 * sizeof(WORD);
        
    // Get size
    sizeX = bmp.width;
    sizeY = bmp.height;

    yc = top;

        GFX_WaitForCommandQueue(16);
        GFX_WaitForGpu();
        
    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                if (stretch == IMAGE_X2) {
                        outputSize = sizeX << 1;
                }       
                else //if (stretch == IMAGE_NORMAL)
                {
                        outputSize = sizeX;
                }
                pBufAddr = lineBuffer2;
                GFX_SetWorkArea1((WORD)pBufAddr);
                GFX_SetWorkArea2(GFX_DISPLAY_BUFFER_START_ADDRESS);
                GFX_SetRectSize(outputSize, 1);
                GFX_SetSrcAddress(0);
        #endif  

    for(y = 0; y < sizeY; y++)
    {
        // Get line
        ExternalMemoryCallback(bitmap, memOffset, sizeX, lineBuffer);
        memOffset += sizeX;
        for(stretchY = 0; stretchY < stretch; stretchY++)
        {
                pData = lineBuffer;
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                pData2 = lineBuffer2;
            #endif      
        
            xc = left;
            for(x = 0; x < sizeX; x++)
            {
                temp = *pData++;
                    #ifdef USE_PALETTE
                        color = temp;
                    #else
                        color = palette[temp];
                    #endif
                                #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                            SetColor(color);
                                #endif  

                // Write pixel to buffer
                for(stretchX = 0; stretchX < stretch; stretchX++)
                {
                                        #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                        PutPixel(xc++, yc);
                    #else
                                *pData2++ = color;
                    #endif                                      
                }
            }
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                        GFX_WaitForCommandQueue(2);
                        GFX_SetDestAddress((yc * (DWORD)DISP_HOR_RESOLUTION) + left);
                        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_CONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
                        #endif  
            yc++;
        }
    }
}

        #endif //#if (COLOR_DEPTH >= 8)

/*********************************************************************
* Function: void PutImage16BPPExt(SHORT left, SHORT top, void* bitmap, BYTE stretch)
*
* PreCondition: none
*
* Input: left,top - left top image corner, bitmap - image pointer,
*        stretch - image stretch factor
*
* Output: none
*
* Side Effects: none
*
* Overview: outputs monochrome image starting from left,top coordinates
*
* Note: image must be located in external memory
*
********************************************************************/
        #if (COLOR_DEPTH == 16)

void PutImage16BPPExt(SHORT left, SHORT top, void *bitmap, BYTE stretch)
{
    register DWORD  memOffset;
    BITMAP_HEADER   bmp;
    WORD            lineBuffer[(GetMaxX() + (DWORD) 1)];
    WORD            *pData; 
#if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
    WORD                        *pBufAddr, *pData2;
    WORD            lineBuffer2[(GetMaxX() + (DWORD) 1)];
    WORD                        outputSize;
#endif    
    WORD            byteWidth;

    WORD            temp;
    WORD            sizeX, sizeY;
    WORD            x, y;
    WORD            xc, yc;
    BYTE            stretchX, stretchY;

        GFX_WaitForCommandQueue(16);
        GFX_WaitForGpu();

    // Get bitmap header
    ExternalMemoryCallback(bitmap, 0, sizeof(BITMAP_HEADER), &bmp);

    // Set offset to the image data
    memOffset = sizeof(BITMAP_HEADER);

    // Get size
    sizeX = bmp.width;
    sizeY = bmp.height;

        // calculate how many bytes to fetch
    byteWidth = sizeX << 1;

    yc = top;

    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                if (stretch == IMAGE_X2) {
                        outputSize = sizeX << 1;
                }       
                else //if (stretch == IMAGE_NORMAL)
                {
                        outputSize = sizeX;
                }
                pBufAddr = lineBuffer2;
                GFX_SetWorkArea1((WORD)pBufAddr);
                GFX_SetWorkArea2(GFX_DISPLAY_BUFFER_START_ADDRESS);
                GFX_SetRectSize(outputSize, 1);
                GFX_SetSrcAddress(0);
        #endif  

    for(y = 0; y < sizeY; y++)
    {
        // Get line
        ExternalMemoryCallback(bitmap, memOffset, byteWidth, lineBuffer);
        memOffset += byteWidth;
        for(stretchY = 0; stretchY < stretch; stretchY++)
        {
                pData = lineBuffer;
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                pData2 = lineBuffer2;
            #endif      
        
            xc = left;
            for(x = 0; x < sizeX; x++)
            {
                temp = *pData++;
                                #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                                        SetColor(temp);
                                #endif  

                // Write pixel to buffer
                for(stretchX = 0; stretchX < stretch; stretchX++)
                {
                                        #if (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)
                        PutPixel(xc++, yc);
                    #else
                                *pData2++ = temp;
                    #endif                                      
                }
            }
                    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)
                        GFX_WaitForCommandQueue(2);
                        GFX_SetDestAddress((yc * (DWORD)DISP_HOR_RESOLUTION) + left);
                        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_CONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
                        #endif  
            yc++;
        }
    }
}
        #endif //#if (COLOR_DEPTH == 16)
    #endif //#ifdef USE_BITMAP_EXTERNAL
    
/*********************************************************************
* Function: WORD PutImage(SHORT left, SHORT top, void* bitmap, BYTE stretch)
*
* PreCondition: none
*
* Input: left,top - left top image corner,
*        bitmap - image pointer,
*        stretch - image stretch factor
*
* Output: For NON-Blocking configuration:
*         - Returns 0 when device is busy and the image is not yet completely drawn.
*         - Returns 1 when the image is completely drawn.
*         For Blocking configuration:
*         - Always return 1.
*
* Side Effects: none
*
* Overview: outputs image starting from left,top coordinates
*
* Note: image must be located in flash
*
********************************************************************/
WORD PutImage(SHORT left, SHORT top, void *bitmap, BYTE stretch)
{
#if defined (USE_BITMAP_FLASH) || defined (USE_BITMAP_EXTERNAL)
    FLASH_BYTE  *flashAddress;
    BYTE        colorDepth;
#endif
    WORD        colorTemp;

    if(GFX_GetFreeCommandSpace() < 4)
    {
        #ifndef USE_NONBLOCKING_CONFIG
            GFX_WaitForCommandQueue(4);
        #else
            return (0);
        #endif
    }

    // Save current color
    colorTemp = GetColor();

    switch(*((SHORT *)bitmap))
    {
                #ifdef USE_BITMAP_FLASH

        case FLASH:

            // Image address
            flashAddress = ((BITMAP_FLASH *)bitmap)->address;

            // Read color depth
            colorDepth = *(flashAddress + 1);

            // Draw picture
            switch(colorDepth)
            {
                case 1:     PutImage1BPP(left, top, flashAddress, stretch); break;
                    
                    #if (COLOR_DEPTH >= 4)
                case 4:     PutImage4BPP(left, top, flashAddress, stretch); break;
                    #endif
                    
                    #if (COLOR_DEPTH >= 8)
                case 8:     PutImage8BPP(left, top, flashAddress, stretch); break;
                    #endif
                    
                    #if (COLOR_DEPTH == 16)
                case 16:    PutImage16BPP(left, top, flashAddress, stretch); break;
                    #endif
                    
                default:    break;
            }

            break;
                #endif
                #ifdef USE_BITMAP_EXTERNAL

        case EXTERNAL:

            // Get color depth
            ExternalMemoryCallback(bitmap, 1, 1, &colorDepth);

            // Draw picture
            switch(colorDepth)
            {
                case 1:     PutImage1BPPExt(left, top, bitmap, stretch); break;
                
                    #if (COLOR_DEPTH >= 4)
                case 4:     PutImage4BPPExt(left, top, bitmap, stretch); break;
                    #endif
                
                    #if (COLOR_DEPTH >= 8)
                case 8:     PutImage8BPPExt(left, top, bitmap, stretch); break;
                    #endif
                    
                    #if (COLOR_DEPTH == 16)
                case 16:    PutImage16BPPExt(left, top, bitmap, stretch); break;
                    #endif
                    
                default:    break;
            }

            break;
                #endif

        default:
            break;
    }

    // Restore current color
    SetColor(colorTemp);
    return (1);
}

#endif // USE_DRV_PUTIMAGE

/*********************************************************************
* Function:  BYTE Decompress(DWORD SrcAddress, DWORD DestAddress, DWORD nbytes);
*
* Overview: Decompresses the nbytes number of data at SrcAddress and
*           places starting from DestAddress. (Blocking)
*
* PreCondition: SrcAddress must point to the start of a compressed block.
*
* Input: SrcAddress  - Source address
*        DestAddress - Destination address
*        nbytes      - Number of bytes to be decompressed
*
* Output: error flag
*
* Side Effects: Modifies workarea_1 & workarea_2 registers.
*
********************************************************************/
BYTE Decompress(DWORD SrcAddress, DWORD DestAddress, DWORD nbytes)
{
    GFX_WaitForCommandQueue(GFX_COMMAND_QUEUE_LENGTH);
    while(GFX_IsPuGpuBusy());
    
    GFX_SetWorkArea1(SrcAddress);
    GFX_SetCompressedSource(0);
    GFX_SetWorkArea2(DestAddress);
    GFX_SetDecompressionDest(0);
    GFX_SetDecompressSize(nbytes);
    
    while(!GFX_DecomperssionDone())
    {
        if(GFX_DecompressionError())
        {
            return GFX_DecompressionError();
        }
    }
    
    return GFX_DecompressionError();
}

/*********************************************************************
* Function: void __GFX1Interrupt(void)
*
* Overview: This is an ISR to handle VMRGN Interrupt
*
* PreCondition: Interrupts must be enabled
*
* Input: none
*
* Output: none
*
* Side Effects: Sets the error flag blPaletteChangeError
*
********************************************************************/
void __attribute__((interrupt, shadow, no_auto_psv)) _GFX1Interrupt(void)
{
    _GFX1IF = 0;
    if(_VMRGNIF != 0)
    {
        _VMRGNIF = 0;

        #ifdef USE_PALETTE
        
        if(pPendingPalette != NULL)
        {
            blPaletteChangeError = SetPalette(pPendingPalette, PendingStartEntry, PendingLength);
            if(!blPaletteChangeError)
            {
                _palette = pPendingPalette;
                pPendingPalette = NULL;
            }
        }
        
        #endif
        
        #ifdef USE_DOUBLE_BUFFERING
        
        if(blDisplayUpdatePending)            
        {
            UpdateDisplayNow();
            blDisplayUpdatePending = 0;
        }
        
        #endif
    }    
}

/*********************************************************************
* Function: void StartVBlankInterrupt(void)
*
* Overview: Sets up the Vertical Blanking Interrupt
*
* PreCondition: Interrupts must be enabled
*
* Input: none
*
* Output: none
*
* Side Effects: none
*
********************************************************************/
void StartVBlankInterrupt(void)
{
    #if (GFX_LCD_TYPE == GFX_LCD_TFT)
    
        _VMRGNIF = 0;
        _VMRGNIE = 1;
        _GFX1IE = 1;
    
    #else
    
    #ifdef USE_PALETTE
    
    if(pPendingPalette != NULL)
    {
        blPaletteChangeError = SetPalette(pPendingPalette, PendingStartEntry, PendingLength);
        
        if(!blPaletteChangeError)
        {
            _palette = pPendingPalette;
            pPendingPalette = NULL;
        }
        
    #endif
        
    #ifdef USE_DOUBLE_BUFFERING
    
        if(blDisplayUpdatePending)            
        {
            UpdateDisplayNow();
            blDisplayUpdatePending = 0;
        }
        
    #endif
    
    }

    #endif
}

#ifdef USE_DOUBLE_BUFFERING

BYTE blInvalidateAll;
BYTE blEnableDoubleBuffering;
BYTE NoOfInvalidatedRectangleAreas;
RectangleArea InvalidatedArea[GFX_MAX_INVALIDATE_AREAS];

/*********************************************************************
* Function:  void InvalidateRectangle(WORD left, WORD top, WORD right, WORD bottom)
*
* Overview: Invalidates the specified rectangular area and if the
*           invalidated areas exceed the GFX_MAX_INVALIDATE_AREAS,
*           whole area is marked as invalidate
*
* PreCondition: None
*
* Input: left,top - top left corner coordinates,
*        right,bottom - bottom right corner coordinates
*
* Output: None
*
* Side Effects: Only copies back the invalidated areas to the draw -
*               buffer after the exchange of draw and frame buffers
*
********************************************************************/
void InvalidateRectangle(WORD left, WORD top, WORD right, WORD bottom)
{
    if(blInvalidateAll == 1 || blEnableDoubleBuffering == 0)
    {
        return;
    }
    
    if(NoOfInvalidatedRectangleAreas >= GFX_MAX_INVALIDATE_AREAS)
    {
        blInvalidateAll = 1;
        return;
    }
    else
    {
        WORD width, height;

    #if (DISP_ORIENTATION == 0) || (DISP_ORIENTATION == 180)

        width   =   right - left + 1;
        height  =   bottom - top + 1;

    #elif (DISP_ORIENTATION == 90) || (DISP_ORIENTATION == 270)

        height  =   right - left + 1;
        width   =   bottom - top + 1;

    #endif

    #if (DISP_ORIENTATION == 90)

        bottom  =   DISP_VER_RESOLUTION - left;
        left    =   top;
        right   =   left + width;
        top     =   bottom - height;

    #elif (DISP_ORIENTATION == 180)

        right   =   DISP_HOR_RESOLUTION - left;
        bottom  =   DISP_VER_RESOLUTION - top;
        left    =   right - width;
        top     =   bottom - height;

    #elif (DISP_ORIENTATION == 270)

        right   =   DISP_HOR_RESOLUTION - top;
        top     =   left;
        bottom  =   top + height;
        left    =   right - width;

    #endif

        InvalidatedArea[NoOfInvalidatedRectangleAreas].X = left;
        InvalidatedArea[NoOfInvalidatedRectangleAreas].Y = top;
        InvalidatedArea[NoOfInvalidatedRectangleAreas].W = width;
        InvalidatedArea[NoOfInvalidatedRectangleAreas].H = height;
        NoOfInvalidatedRectangleAreas++;
    }
}

/*********************************************************************
* Function:  static void ExchangeDrawAndFrameBuffers(void);
*
* Overview: Interchanges Draw and Frame buffers and copies the contents
*           of current frame buffer to the draw buffer
*
* PreCondition: The graphical frame must be completely drawn.
*
* Input: None
*
* Output: None
*
* Side Effects: Always draw on draw buffer & not on frame buffer
*
********************************************************************/
static void ExchangeDrawAndFrameBuffers(void)
{
    DWORD SourceBuffer, DestBuffer;
    
    if(blEnableDoubleBuffering == 0)
    {
        return;
    }
    
    if(_drawbuffer == GFX_BUFFER1)
    {
        SourceBuffer = GFX_BUFFER1;
        DestBuffer   = GFX_BUFFER2;
    }
    else
    {
        SourceBuffer = GFX_BUFFER2;
        DestBuffer   = GFX_BUFFER1;
    }
    
    _drawbuffer = DestBuffer;
    GFX_SetDisplayArea(SourceBuffer);

    GFX_WaitForCommandQueue(GFX_COMMAND_QUEUE_LENGTH);
    while(GFX_IsPuGpuBusy());
    
    GFX_SetWorkArea1(SourceBuffer);
    GFX_SetWorkArea2(DestBuffer);

    if(blInvalidateAll == 1 || NoOfInvalidatedRectangleAreas > GFX_MAX_INVALIDATE_AREAS)
    {
        blInvalidateAll = 0;
        NoOfInvalidatedRectangleAreas = 0;
        GFX_SetSrcAddress(0);
        GFX_SetDestAddress(0);
        GFX_SetRectSize((WORD)DISP_HOR_RESOLUTION, (WORD)DISP_VER_RESOLUTION);
        GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_CONTINUOUS, RCC_DEST_ADDR_CONTINUOUS);
    }
    else if(NoOfInvalidatedRectangleAreas)
    {
        while(NoOfInvalidatedRectangleAreas)
        {
            DWORD address;
            NoOfInvalidatedRectangleAreas--;
            address = ((DWORD)InvalidatedArea[NoOfInvalidatedRectangleAreas].Y * DISP_HOR_RESOLUTION) + InvalidatedArea[NoOfInvalidatedRectangleAreas].X;
            GFX_WaitForCommandQueue(4);
            GFX_SetSrcAddress(address);
            GFX_SetDestAddress(address);
            GFX_SetRectSize(InvalidatedArea[NoOfInvalidatedRectangleAreas].W, InvalidatedArea[NoOfInvalidatedRectangleAreas].H);
            GFX_StartCopy(RCC_COPY, RCC_ROP_C, RCC_SRC_ADDR_DISCONTINUOUS, RCC_DEST_ADDR_DISCONTINUOUS);
        }
    }
}

/*********************************************************************
* Function:  void UpdateDisplayNow(void)
*
* Overview: Synchronizes the draw and frame buffers immediately
*
* PreCondition: none
*
* Input: none
*
* Output: none
*
* Side Effects: none
*
********************************************************************/
void UpdateDisplayNow(void)
{
    ExchangeDrawAndFrameBuffers();
}

/*********************************************************************
* Function:  void RequestDisplayUpdate(void)
*
* Overview: Synchronizes the draw and frame buffers at next VBlank
*
* PreCondition: none
*
* Input: none
*
* Output: none
*
* Side Effects: none
*
********************************************************************/
void RequestDisplayUpdate(void)
{
    if(blInvalidateAll == 1 || NoOfInvalidatedRectangleAreas > 0)
    {
        blDisplayUpdatePending = 1;
        StartVBlankInterrupt();
    }
}

#endif //USE_DOUBLE_BUFFERING

#ifdef USE_PALETTE

/*********************************************************************
* Function: void PaletteInit(void)
*
* Overview: Initializes the CLUT.
*
* PreCondition: none
*
* Input: none
*
* Output: none
*
* Side Effects: none
*
********************************************************************/
void PaletteInit(void)
{
    while(_CLUTBUSY != 0)
    {
        Nop();
    }
    _CLUTRWEN = 0;
    _CLUTEN = 0;
}

/*********************************************************************
* Function: void EnablePalette(void)
*
* Overview: Enables the Palette mode
*
* PreCondition: A system palette has been set using RequestPaletteChange()
*               or SetPalette() and SetPaletteBpp() must have been called
*
* Input: none
*
* Output: none
*
* Side Effects: There may be a little flicker with SetPalette() which
*               can be avoided for TFT with RequestPaletteChange()
*
********************************************************************/
void EnablePalette(void)
{
    if(PaletteBpp <= GFX_16_BPP)
    {
        _PUBPP = PaletteBpp;
        _DPBPP = PaletteBpp;
        _CLUTEN = 1;
    }    
}

/*********************************************************************
* Function: void DisablePalette(void)
*
* Overview: Disables the Palette mode
*
* PreCondition: none
*
* Input: none
*
* Output: none
*
* Side Effects: There may be a little flicker which can be avoided for TFT
*               by preceding with a dummy RequestPaletteChange()
*
********************************************************************/
void DisablePalette(void)
{
    _CLUTEN = 0;
    _PUBPP  = GFX_BITS_PER_PIXEL;
    _DPBPP  = GFX_BITS_PER_PIXEL;
}

/*********************************************************************
* Function: BYTE IsPaletteEnabled(void)
*
* Overview: Returns if the Palette mode is enabled or not
*
* PreCondition: none
*
* Input: none
*
* Output: Enabled -> 1, Disabled -> 0
*
* Side Effects:
*
********************************************************************/
BYTE IsPaletteEnabled(void)
{
    return _CLUTEN;
}

/*********************************************************************
* Function: BYTE SetPaletteBpp(BYTE bpp)
*
* Overview: Sets the CLUT's number of valid entries.
*
* PreCondition: PaletteInit() must be called before.
*
* Input: bpp -> Bits per pixel
*
* Output: Status: Zero -> Success, Non-zero -> Error.
*
* Side Effects: Drawing mode will change to support palettes
*
********************************************************************/
BYTE SetPaletteBpp(BYTE bpp)
{
    switch(bpp)
    {
        case 1:         PaletteBpp = GFX_1_BPP;
                        break;

        case 2:         PaletteBpp = GFX_2_BPP;
                        break;

        case 4:         PaletteBpp = GFX_4_BPP;
                        break;

        case 8:         PaletteBpp = GFX_8_BPP;
                        break;

        default:        PaletteBpp = GFX_16_BPP;
                        return -1;                        
    }
    
    return 0;
}

/*********************************************************************
* Function: BYTE SetPaletteFlash(PALETTE_ENTRY *pPaletteEntry, WORD startEntry, WORD length)
*
* Overview: Loads the palettes from the flash immediately.
*
* PreCondition: PaletteInit() must be called before.
*
* Input: pPaletteEntry   - Pointer to the palette table in ROM
*        startEntry      - Start entry to load (inclusive)
*        length          - Number of entries
*
* Output: Status: Zero -> Success, Non-zero -> Error.
*
* Side Effects: There may be a slight flicker when the Palette entries
*               are getting loaded one by one.
*
********************************************************************/
BYTE SetPaletteFlash(PALETTE_ENTRY *pPaletteEntry, WORD startEntry, WORD length)
{
    WORD counter;

    if((pPaletteEntry == NULL) || ((startEntry + length) > 256))
    {
        return -1;
    }

    _CLUTRWEN = 1;
    for(counter = 0; counter < length; counter++)
    {
        _CLUTADR = counter;
        _CLUTWR  = pPaletteEntry[counter].value;
        while(_CLUTBUSY)
        {
            Nop();
        }
    }
    _CLUTRWEN = 0;

    return 0;
}

#endif // USE_PALETTE
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3