/*****************************************************************************
 * Microchip Graphics Library Demo Application
 * This program shows how to use the Graphics Objects Layer.
 *****************************************************************************
 * FileName:        MainDemo.c
 * Dependencies:    MainDemo.h
 * Processor:       PIC24, PIC32
 * Compiler:       	MPLAB C30 V3.00, MPLAB C32
 * Linker:          MPLAB LINK30, MPLAB LINK32
 * Company:         Microchip Technology Incorporated
 *
 * Software LicenseJpeg
  Agreement
 *
 * Copyright ?2007 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
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Anton Alkhimenok
 * Paolo Tamayo         03/10/08    ...
 *****************************************************************************/

/******************************************************************************
* Revision:
* Modified to support TechToys SSD1963 and SSD1928 driver development using
*    the PIC24/32-Eval-Rev C2 board and either LVC75Z779 Eval Board (SSD1928)
*    or SSD1963 Eval Rev 2A
* Programmer: John Leung, Company: TechToys Co.
* Programmer: Bruce Elliott added SSD1928/SSD1963 HardwareProfile and PIC33F NON-PMP
* 
* Select the correct hardware configuration from file HardwareProfile.h
* 
* Caveats:
* (1) Configuration Bits assume Internal Fast OSC for some processors. 
*	  Check this carefully.
* (2) PIC33FJ256GP710 PIM, PIC24H256GP610 PIM without PMP supported (Port E)
* (3) Board, Graphics Controller and Processor used in #defines
*     see EEPROM.x, TouchScreen.x
* (4) panelBrightness, SetTearingCfg() and SetBacklight() functions for SSD1963
*
* TechToys Company
* Web site: www.TechToys.com.hk
* Date: 3rd Feb 2010
******************************************************************************/

/*
******************************************************************************
* Revision:
* This file modified for Solomon SSD1963 driver development
* Programmer: Bruce Elliott
* email: bruce.t.elliott@web.de
* Date: 11 Feb 2010
* (1) Change 
*     The clock and data lines didn't work after TouchInit() was called.
*     RB8 and RB9 (which are AN pins) on the Eval C2 board were being turned 
*	  into analog lines on the PIC33FJ256GP710.
*
*	  The following lines removed from TouchInit() for PIC33F or PIC24H
*		AD1PCFGL = 0;           // All inputs are analog
*		AD1PCFGLbits.PCFG11 = AD1PCFGLbits.PCFG12 = 1;
*		in TouchScreen.c
******************************************************************************
*/

/*
******************************************************************************
* Revision:
* Add support for 5" TFT (800x480) sync mode
* Programmer: John Leung
* Date: 6th Oct 2010
******************************************************************************
*/


/*
******************************************************************************
* Revision:
* Add support for a new hardware platform PIC32 Starter Kit on 
* SSD1963 EVK (namely PIC32STK_ON_PIC32STK_SSD1963_EVK_R1A)
* A new hardwareProfile added with filename: HardwareProfile_PIC32STK_ON_PIC32STK_SSD1963_EVK_R1A.h
* The file EEPROM.c modified for SPI1 used as EEPROM SPI access on this new board
* TouchScreen.h also modified to add support for PIC32STK_ON_PIC32STK_SSD1963_EVK_R1A
* Programmer: John Leung
* Date: 28th Jan 2011
******************************************************************************
*/

/*

*/

#include "MainDemo.h"
#include "MainDemoStrings.h"

/*****************************************************************************
* Caveats:
* Removed USB Support, since USB pins blocked on PIC24/32 Eval C2 board
* Graphic boards for PIC24/32 Eval C2 board have no external Flash memory, so:
*    //#define USE_FONT_EXTERNAL		// No Support external fonts.
*    //#define USE_BITMAP_EXTERNAL	// No Support for external bitmaps.
* Icons internal (Flash) since no external Flash on SSD1928 TFT_LVC75Z779V1S board
* Only 8-Bit PMP Support for PIC32 on SSD1928 TFT_LVC75Z779V1S board
*
******************************************************************************/

/*
 ********************************************************************
 * Revisions
 * Date 1st Feb 2011
 * (1) Add vs1003b.h under MainDemo.h and vs1003b.c in project workspace
 ********************************************************************
*/

/*
******************************************************************************
* Revision:
* (1) MPLAB upgraded to IDE version v8.63, C32 compiler upgraded to version 1.12a
* After the upgrade, touch panel didn't work for some unknown reason
* However, by comment out the touch screen calibration part, this program is 
* able to display properly with PIC32 GP STK, PIC32 Ethernet STK, and PIC32 USB STK1
* (2) Comment out 	if (BTN_S3 == 0){...} for touch screen calibration
* (3) Remove all vs1003 related setup for now
******************************************************************************
*/

// Configuration bits
#if defined(__dsPIC33F__) || defined(__PIC24H__)
	_FOSCSEL(FNOSC_PRI);
	_FOSC(FCKSM_CSECMD &OSCIOFNC_OFF &POSCMD_XT);
	_FWDT(FWDTEN_OFF);
#elif defined(__PIC32MX__)
	#if defined (PIC32_STARTER_KIT) || defined (PIC32MX_EVK_RD2)		
	#pragma config FNOSC = PRIPLL, POSCMOD = XT, OSCIOFNC = OFF			
	#pragma config FPLLODIV = DIV_1, FPLLMUL = MUL_18, FPLLIDIV = DIV_2, FWDTEN = OFF, FCKSM = CSECME, FPBDIV = DIV_1
	#pragma config FSOSCEN = ON, IESO = OFF
	#pragma config CP = OFF, BWP = OFF, PWP = OFF	
	#elif defined (PIC32MX_EVK_RC2)	// PIC24 Eval board RevC2 with PIC32MX360F512L onboard, Internal Fast Osc for 8MHz*18= 72MH
	#pragma config FNOSC = FRCPLL, POSCMOD = OFF, ICESEL = ICS_PGx2
	#pragma config FPLLODIV = DIV_1, FPLLMUL = MUL_18, FPLLIDIV = DIV_2, FWDTEN = OFF, FCKSM = CSECME, FPBDIV = DIV_1
	#pragma config FSOSCEN = ON, IESO = OFF
	#pragma config CP = OFF, BWP = OFF, PWP = OFF
	#endif
	// If a 8.0MHz crystal and 32kHz crystal soldered onboard
	//#pragma config FPLLODIV = DIV_1, FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FWDTEN = OFF, FCKSM = CSECME, FPBDIV = DIV_8
	//#pragma config OSCIOFNC = ON, POSCMOD = XT, FSOSCEN = ON, FNOSC = PRIPLL
	//#pragma config CP = OFF, BWP = OFF, PWP = OFF
	// If a 8.0MHz crystal and 32kHz crystal soldered onboard
	// If no crystal soldered onboard, use internal fast OSC
#else
    #if defined(__PIC24FJ256GA110__)
_CONFIG1(JTAGEN_OFF & GCP_OFF & GWRP_OFF & COE_OFF & FWDTEN_OFF & ICS_PGx2)
_CONFIG2(IESO_OFF & FCKSM_CSDCMD & OSCIOFNC_OFF & POSCMOD_HS & FNOSC_PRIPLL & IOL1WAY_OFF)
    #endif
    #if defined(__PIC24FJ128GA010__)	//TechToys
_CONFIG2(FNOSC_FRCPLL) 					// Fast RC oscillator with PLL
_CONFIG1(JTAGEN_OFF & FWDTEN_OFF)   	// JTAG off, watchdog timer off
    #endif
#endif

//////////////////////////////////////////////////////////////////////////////
//                            LOCAL PROTOTYPES
//////////////////////////////////////////////////////////////////////////////
#define WAIT_UNTIL_FINISH(x)    while(!x)
void                    StartScreen(void);
void                    Init_CPUClocks(void);
void                    TickInit(void);

//////////////////////////////////////////////////////////////////////////////
//                            IMAGES USED
//////////////////////////////////////////////////////////////////////////////

extern BITMAP_FLASH  intro;      // the following images are stored in flash
extern BITMAP_FLASH  mchpLogo;   // since no external flash memory on TechToys
extern BITMAP_FLASH  mchpIcon0;

//////////////////////////////////////////////////////////////////////////////
//                       GLOBAL VARIABLES FOR DEMO
//////////////////////////////////////////////////////////////////////////////
SCREEN_STATES           screenState = CREATE_DEMOSELECTION; // current state of main demo state mashine
GOL_SCHEME              *altScheme;                         // alternative style scheme
GOL_SCHEME              *iconScheme;                        // alternative icon style scheme
GOL_SCHEME              *meterScheme;                       // style scheme used to draw the meter
GOL_SCHEME              *navScheme;                         // style scheme for the navigation
GOL_SCHEME              *gridScheme;                        // style scheme used to draw the grid
GOL_SCHEME              *graphScheme;                       // style scheme used for the graph demo
OBJ_HEADER              *pNavList;                          // pointer to navigation list
BYTE                    usbErrorCode;                       // USB error
BYTE                    usbHIDStatus;                       // HID device status
BYTE                    usbMSDStatus;                       // MSD device status
volatile DWORD          tick = 0;                           // tick counter
extern BOOL             gEnableDemoFlag;                    // flag for automatic demo mode

//////////////////////////////////////////////////////////////////////////////
//                            STRINGS USED
//////////////////////////////////////////////////////////////////////////////
const XCHAR             ErrMsgStandard[] = {'U','S','B',' ','E','r','r','o','r',0};
const XCHAR             ErrNotSupported[] = {'n','o','t',' ','s','u','p','p','o','r','t','e','d','!',0};
const XCHAR             ErrMsgFailedStr[] = {'F','a','i','l','e','d',0};
const XCHAR             ErrMsgHUBAttachedStr[] = {'H','U','B',0};
const XCHAR             ErrMsgUDAttachedStr[] = {'D','e','v','i','c','e',0};
const XCHAR             ErrMsgEnumerationStr[] = {'E','n','u','m','e','r','a','t','i','o','n',0};
const XCHAR             ErrMsgClientInitStr[] = {'C','l','i','e','n','t',' ','I','n','i','t','i','a','l','i','z','a','t','i','o','n',0};
const XCHAR             ErrMsgOutofMemoryStr[] = {'O','u','t',' ','o','f',' ','M','e','m','o','r','y',0};
const XCHAR             ErrMsgUnpecifiedErrStr[] = {'U','n','s','p','e','c','i','f','i','e','d',0};
const XCHAR             MsgTouchToProceedStr[] = {'T','o','u','c','h',' ','t','o',' ','p','r','o','c','e','e','d',0};
const XCHAR				MsgTouchToCalibrateStr[] = {'T','o','u','c','h',' ','t','o',' ','c','a','l','i','b','r','a','t','e',' ','o','r',' ','w','a','i','t',' ','5', 's', 'e', 'c',0};
//////////////////////////////////////////////////////////////////////////////
//                                  MAIN
//////////////////////////////////////////////////////////////////////////////

WORD	vs1003TestWord;				// test word for vs1003

int main(void)
{
	GOL_MSG msg;						// GOL message structure to interact with GOL
	BYTE	panelBrightness = 255;		// Set panel brightness on system reset
	WORD 	counter;

    ///////////////////////////////////////////////
//	Init_CPUClocks();

   /////////////////////////////////////////////////////////////////////////////
#if defined(__dsPIC33F__) || defined(__PIC24H__)
	// Configure Oscillator to operate the device at 40Mhz
	// Fosc= Fin*M/(N1*N2), Fcy=Fosc/2
	// Fosc= 8M*40(2*2)=80Mhz for 8M input clock
	PLLFBD = 38;                    // M=40
	CLKDIVbits.PLLPOST = 0;         // N1=2
	CLKDIVbits.PLLPRE = 0;          // N2=2
	OSCTUN = 0;                     // Tune FRC oscillator, if FRC is used

	// Disable Watch Dog Timer
	RCONbits.SWDTEN = 0;

	// Clock switching to incorporate PLL
	__builtin_write_OSCCONH(0x03);  // Initiate Clock Switch to Primary

	// Oscillator with PLL (NOSC=0b011)
	__builtin_write_OSCCONL(0x01);  // Start clock switching
	while(OSCCONbits.COSC != 0b011);

	// Wait for Clock switch to occur	
	// Wait for PLL to lock
	while(OSCCONbits.LOCK != 1)
	{ };
    
	// Set PMD0 pin functionality to digital
	AD1PCFGL = AD1PCFGL | 0x1000;
    
#elif defined(__PIC32MX__)
	INTEnableSystemMultiVectoredInt();
	SYSTEMConfigPerformance(GetSystemClock());
	/*
	// activate LEDs on TechToys C2 board 
	PORTDbits.RD0 = 1;		// RD0 is also PWM for Beeper
	PORTDbits.RD1 = 1;
	PORTDbits.RD2 = 1;
	PORTDbits.RD3 = 1;

	TRISDbits.TRISD0 = 0;
	TRISDbits.TRISD1 = 0;
	TRISDbits.TRISD2 = 0;
	TRISDbits.TRISD3 = 0;
	*/
	//TRISFbits.TRISF6 = 1;			//Just for debug, RF6 connected to VDD for PIC24FJ256GB110 USB MCU. 

#elif defined (__PIC24F__)			//TehcToys
	CLKDIV = 0x0000;				//FRC postscaler divided by 1 (8MHz from internal RC)	
#endif

	/////////////////////////////////////////////////////////////////////////////

	GOLInit();				// Initialize graphics library and create default style scheme for GOL

#if (DISPLAY_CONTROLLER == SSD1963)
	SetTearingCfg(1,0);			// Set tearing effect on with V-blanking 
								// information only
	SetBacklight(panelBrightness);	// Set initial screen brightness	
#endif

#if (GRAPHICS_HARDWARE_PLATFORM == PIC32STK_ON_PIC32STK_SSD1963_EVK_R1A) 
	/*
	vs1003LLInit();
	vs1003TestWord = vs1003MemoryTest();
	Nop();
	vs1003SineTest(1, 500);
	*/
#endif

	BeepInit();				// Initialize beeper
	EEPROMInit();			// initialize EEPROM SPI for Calibration data
	TickInit();				// Start tick counter
	TouchInit();			// Initialize touch screen
	RTCCInit();				// Setup the RTCC
	RTCCProcessEvents();


#ifdef ENABLE_SCREEN_CAPTURE
	UARTInit();
#endif

	// If left-most button on Eval C2 / PIC24/32 EVK RD2 board is pressed, calibrate touch screen
	/*
	if (BTN_S3 == 0)
	{
			TouchCalibration();
			TouchStoreCalibration();
	};
	*/
	SetColor(WHITE);
	ClearDevice();
	SetColor(BRIGHTRED);
	SetFont((void *) &FONTDEFAULT);
	MoveTo((GetMaxX() - GetTextWidth((XCHAR *)MsgTouchToCalibrateStr, (void *) &FONTDEFAULT)) >> 1, ((GetMaxY()-140+1)/2));
	WAIT_UNTIL_FINISH(OutText((XCHAR *)MsgTouchToCalibrateStr));


	for(counter=0;counter<5000;counter++)
	{
		DelayMs(1);
		if((ADCGetX()!=-1)||(ADCGetY()!=-1))
		{
			TouchCalibration();
			TouchStoreCalibration();
			break;			
		}
	}

	// If it's a new board (VERSION word is not programed) calibrate touch screen
	if(GRAPHICS_LIBRARY_VERSION != EEPROMReadWord(ADDRESS_VERSION))
	{
		TouchCalibration();
		TouchStoreCalibration();
	}

	// Load touch screen calibration parameters from memory
	TouchLoadCalibration();



#if defined(ENABLE_SD_MSD_DEMO)
	int temp;

	MDD_SDSPI_InitIO();
	if (MDD_MediaDetect())
	{
		// check if SD Device is connected, but will not wait forever.
		temp = 500;
		while (temp)
		{
			if (FSInit())
				break;
			temp--;
		}
	}
#endif

#ifdef ENABLE_DEMO_MODE
	InitDemoMode();
#endif

	StartScreen();                      // Show intro screen and wait for touch

	// create the the style schemes
	navScheme = GOLCreateScheme();
	altScheme = GOLCreateScheme();
	meterScheme = GOLCreateScheme();
	iconScheme = GOLCreateScheme();
	gridScheme = GOLCreateScheme();
	graphScheme = GOLCreateScheme();

	InitECGStyleScheme(altScheme);
	InitGamesStyleScheme(gridScheme);
	InitDemoSelectStyleScheme(iconScheme);
	InitAnimationStyleScheme(meterScheme);
	InitGraphDemoStyleScheme(graphScheme);

	while(1)
	{
		if(GOLDraw())
		{                               // Draw GOL objects
			// Drawing is finished, we can now process new message
			TouchGetMsg(&msg);          // Get message from touch screen

#ifdef ENABLE_DEMO_MODE
			// when running in demo mode enabled fake the messages to perform
			// demo on selected screens
			if (gEnableDemoFlag == TRUE)
			{
				UpdateDemoMode(&msg);   // update the next step of the automatic demo
			}
#endif
			GOLMsg(&msg);               // Process message

			// When USE_FOCUS is set, the Demo can be controlled using
			// Explorer 16 buttons. See SideButtons.h for details.
#ifdef USE_FOCUS
			SideButtonsMsg(&msg);
			GOLMsg(&msg);               // Process message
#endif

			// FOR DEBUG ONLY (holding down Button S3 of Eval C2 will pause the screen)
			//while (BTN_S6 == 0); removed for PIC32STK_SSD1963EVK_R1A
		}
	}
}

/************************************************************************
 Function: WORD GOLMsgCallback(WORD objMsg, OBJ_HEADER* pObj, GOL_MSG* pMsg)

 Overview: This function must be implemented by user. GOLMsg() function 
 		   calls it each time the valid message for the object received.
           
 Input: objMsg - translated message for the object,
        pObj - pointer to the object,
        pMsg - pointer to the non-translated, raw GOL message 

 Output: If the function returns non-zero the message will 
 		 be processed by the object directly affected by the message.
 		 Default action on the object based on the message will be 
 		 performed.
************************************************************************/
WORD GOLMsgCallback(WORD objMsg, OBJ_HEADER *pObj, GOL_MSG *pMsg)
{
    if(objMsg == BTN_MSG_PRESSED)
    {
        Beep();
    }

    // Process messages for demo screens. Each of the
    // demo screens will have its own corresponding message callback
    // functions.
    switch(screenState)
    {
        case DISPLAY_TIMEDATE:
            return (TimeDateDemoMsgCallback(objMsg, pObj, pMsg));

        case DISPLAY_MULTIFONT:
            return (MultiFontDemoMsgCallback(objMsg, pObj, pMsg));

        case DISPLAY_RGB:
            return (RGBDemoMsgCallback(objMsg, pObj, pMsg));

        case DISPLAY_SNAKE:
            return (ProcessMessageSnake(objMsg, pObj, pMsg));

        case DISPLAY_SNAKE_SCORE:
            return (ProcessMessageSnake(objMsg, pObj, pMsg));
            return (1);

        case DISPLAY_SCALE:
            return (MsgDrawTool(objMsg, pObj, pMsg));

        case DISPLAY_ANIMATION:
            return (MsgAnimation(objMsg, pObj, pMsg));

        case DISPLAY_DEMOSELECTION:
            return (MsgDemoSelection(objMsg, pObj, pMsg));

        case DISPLAY_ECG:
            return (MsgECG(objMsg, pObj, pMsg));

        case DISPLAY_SLIDESHOW:
            return (SlideShowDemoMsgCallback(objMsg, pObj, pMsg));
            #ifdef ENABLE_USB_MSD_DEMO

        case DISPLAY_JPEGDEMO:
            return (JPEGMsgCallback(objMsg, pObj, pMsg));   // see JPEGDemo.c for this implementation
            #endif
            #ifdef ENABLE_SD_MSD_DEMO

        case DISPLAY_SDCARDDEMO:
            return (JPEGMsgCallback(objMsg, pObj, pMsg));   // see SDCardDemo.c for this implementation
            #endif

        case DISPLAY_GRAPHSHOW:
            return (GraphMsgCallback(objMsg, pObj, pMsg));

        default:
            return (1); // process message by default
    }
}

/************************************************************************
 Function: WORD GOLDrawCallback()

 Overview: This function must be implemented by user. GOLDraw() function 
 		   calls it each time when GOL objects drawing is completed. User 
 		   drawing should be done here. GOL will not change color, line 
 		   type and clipping region settings while  this function 
 		   returns zero.

 Input: none

 Output: If the function returns non-zero the draw control will be passed 
		to GOL. GOLDraw() can proceed and re-draw objects that needs 
		to be redrawn.
************************************************************************/
WORD GOLDrawCallback(void)
{
    static DWORD    prevTick = 0;                   // keeps previous value of tick

#ifdef ENABLE_SCREEN_CAPTURE
	if(PORTDbits.RD6 == 0)
	{                                               // used to capture screen to PC through UART.
		GetBMP();
	}
#endif

    switch(screenState)
    {
        case CREATE_DEMOSELECTION:
            CreateDemoSelection();                  // create demo selection screen
            screenState = DISPLAY_DEMOSELECTION;    // switch to next state
            return (1);                             // draw objects created

        case DISPLAY_DEMOSELECTION:
            CheckDemoStatus();
            return (1);                             // redraw objects if needed

        case CREATE_TIMEDATE:
            CreateTimeDateDemo();
            screenState = DISPLAY_TIMEDATE;         // switch to next state
            return (1);

        case DISPLAY_TIMEDATE:
            TimeDateDemoDrawCallback();
            return (1);

        case CREATE_MULTIFONT:
            CreateMultiFontsDemo();
            screenState = DISPLAY_MULTIFONT;        // switch to next state
            return (1);

        case DISPLAY_MULTIFONT:
            MultiFontDemoDrawCallback(tick);
            return (1);

        case CREATE_RGB:
            CreateRGBDemo();                        // create RGB demo
            screenState = DISPLAY_RGB;              // switch to next state
            return (1);

        case DISPLAY_RGB:
            RGBDemoDrawCallback();                  // RGB demo draw callback
            return (1);

        case CREATE_SLIDESHOW:
            CreateSlideShowDemo();                  // create slide show demo
            screenState = DISPLAY_SLIDESHOW;        // switch to next state
            return (1);

            #ifdef ENABLE_USB_MSD_DEMO

        case CREATE_JPEGDEMO:
            if(CreateJPEGDemo() == 1)               // create JPEG demo (see JPEGDemo.c)
                screenState = DISPLAY_JPEGDEMO;     // switch to next state
            else
                screenState = CREATE_DEMOSELECTION; // go back to demo selection
            return (1);

        case DISPLAY_JPEGDEMO:
            JPEGDrawCallback();                     // see JPEGDemo.c
            return (1);
            #endif
            #ifdef ENABLE_SD_MSD_DEMO

        case CREATE_SDCARDDEMO:
            if(CreateJPEGDemo() == 1)               // create JPEG demo (see SDCardDemo.c)
                screenState = DISPLAY_SDCARDDEMO;   // switch to next state
            else
                screenState = CREATE_DEMOSELECTION; // go back to demo selection
            return (1);

        case DISPLAY_SDCARDDEMO:
            JPEGDrawCallback();                     // see SDCardDemo.c
            return (1);
            #endif

        case CREATE_ANIMATION:
            CreateAnimation();
            screenState = DISPLAY_ANIMATION;        // switch to next state
            return (1);

        case DISPLAY_ANIMATION:
            NextAnimation(tick);
            return (1);

        case CREATE_SCALE:
            CreateDrawTool();
            screenState = DISPLAY_SCALE;            // switch to next state
            return (1);

        case DISPLAY_SCALE:
            return (1);

        case CREATE_SNAKE:
            ShowScreenSnake();
            screenState = DISPLAY_SNAKE;            // switch to next state
            return (1);

        case DISPLAY_SNAKE:
            DrawSnake(tick);
            return (1);

        case CREATE_SNAKE_SCORE:
            ShowScreenScore();
            prevTick = tick;
            while((tick - prevTick) < 1000);

            // delay the switching of state so that score can be read
            screenState = DISPLAY_SNAKE_SCORE;      // switch to next state
            return (1);

        case DISPLAY_SNAKE_SCORE:
            return (1);

        case CREATE_ECG:
            CreateECG();                            // create window
            screenState = BOX_DRAW_ECG;             // switch to next state
            return (1);                             // draw objects created

        case BOX_DRAW_ECG:
            if(0 == PanelECG())                     // draw box for ECG graph
                return (0);                         // drawing is not completed, don't pass

            // drawing control to GOL, try it again
            screenState = DISPLAY_ECG;              // switch to next state
            return (1);                             // pass drawing control to GOL, redraw objects if needed

        case DISPLAY_ECG:
            UpdateECG(tick);
            return (1);                             // redraw objects if needed

        case CREATE_GRAPHSHOW:
            CreateGraphDemo();
            screenState = DISPLAY_GRAPHSHOW;        // switch to next state
            return (1);

        case DISPLAY_GRAPHSHOW:
            UpdateGraphDemo(tick);
            return (1);

        case CREATE_GAME:
        case DISPLAY_GAME:
        case DISPLAY_SLIDESHOW:
        case DEMO_MODE:
        default:
            break;
    }

    return (1); // release drawing control to GOL
}

/************************************************************************
 Function: void StartScreen()

 Overview: Shows the splash screen for introduction.
 
 Input: none

 Output: none
 ************************************************************************/
// Shows intro screen and waits for short period of time
#define SS_ORIGIN_X    ((GetMaxX()-316+1)/2)
#define SS_ORIGIN_Y    ((GetMaxY()-140+1)/2)

void StartScreen(void)
{
	SHORT               counter;
	static const XCHAR  text[] = {'W','e','l','c','o','m','e','!',0};
	WORD                i, j, k;
	WORD                ytemp, xtemp, srRes = 0x0001;

	SetColor(WHITE);
	ClearDevice();

	WAIT_UNTIL_FINISH(PutImage(0, 0, (void *) &mchpLogo, IMAGE_NORMAL));
	WAIT_UNTIL_FINISH(PutImage(SS_ORIGIN_X,SS_ORIGIN_Y, (void *) &intro, IMAGE_X2));

	for(counter = 0; counter < (GetMaxX()+1) - 32; counter++)
	{   // move Microchip icon
		WAIT_UNTIL_FINISH(PutImage(counter, GetMaxY() - 34, (void *) &mchpIcon0, IMAGE_NORMAL));
	}

	SetColor(BRIGHTRED);
	SetFont((void *) &FONTDEFAULT);

	MoveTo((GetMaxX() - GetTextWidth((XCHAR *)text, (void *) &FONTDEFAULT)) >> 1, SS_ORIGIN_Y+122);
	WAIT_UNTIL_FINISH(OutText((XCHAR *)text));

	DelayMs(1200);

	// random fade effect using a Linear Feedback Shift Register (LFSR)
	SetColor(WHITE);
	for(i = 1800; i > 0; i--)
	{
		// for a 16 bit LFSR variable the taps are at bits: 1, 2, 4, and 15
		srRes = (srRes >> 1) ^ (-(int)(srRes & 1) & 0x8006);
		xtemp = (srRes & 0x00FF) % 40;
		ytemp = (srRes >> 8) % 30;

		// by replicating the white (1x1) bars into 8 areas fading is faster
		for(j = 0; j < 8; j++)
		{
			for(k = 0; k < 8; k++)
				PutPixel(SS_ORIGIN_X+xtemp + (j * 40), ytemp + (k * 30));
		}
	}
}

/************************************************************************
 Function: void CreateCtrlButtons(XCHAR *pTextA, XCHAR *pTextB, 
 								  XCHAR *pTextC, XCHAR *pTextD)

 Overview: Creates the navigation and control buttons of the menu.
 
 Input: pTextA - pointer to button A label.
		pTextB - pointer to button B label.
		pTextC - pointer to button C label.
		pTextB - pointer to button D label.

 Output: none
************************************************************************/
void CreateCtrlButtons(XCHAR *pTextA, XCHAR *pTextB, XCHAR *pTextC, XCHAR *pTextD)
{
    WORD    state;

    state = BTN_DRAW;
    if(pTextA == NULL)
        state = BTN_DRAW | BTN_DISABLED;
    BtnCreate
    (
        ID_BUTTON_A,
        CtrlBtnLeft(0),
        CtrlBtnTop(),
        CtrlBtnRight(0),
        CtrlBtnBottom(),
        0,
        state,
        NULL,
        pTextA,
        altScheme
    );

    state = BTN_DRAW;
    if(pTextB == NULL)
        state = BTN_DRAW | BTN_DISABLED;
    BtnCreate
    (
        ID_BUTTON_B,
        CtrlBtnLeft(1),
        CtrlBtnTop(),
        CtrlBtnRight(1),
        CtrlBtnBottom(),
        0,
        state,
        NULL,
        pTextB,
        altScheme
    );

    state = BTN_DRAW;
    if(pTextC == NULL)
        state = BTN_DRAW | BTN_DISABLED;
    BtnCreate
    (
        ID_BUTTON_C,
        CtrlBtnLeft(2),
        CtrlBtnTop(),
        CtrlBtnRight(2),
        CtrlBtnBottom(),
        0,
        state,
        NULL,
        pTextC,
        altScheme
    );

    state = BTN_DRAW;
    if(pTextD == NULL)
        state = BTN_DRAW | BTN_DISABLED;
    BtnCreate
    (
        ID_BUTTON_D,
        CtrlBtnLeft(3),
        CtrlBtnTop(),
        CtrlBtnRight(3),
        CtrlBtnBottom(),
        0,
        state,
        NULL,
        pTextD,
        altScheme
    );
}


/*********************************************************************
* Function: Timer4 ISR
*
* PreCondition: none
*
* Input: none
*
* Output: none
*
* Side Effects: none
*
* Overview: increments tick counter. Tick is approx. 1 ms.
*
* Note: none
*
********************************************************************/
#ifdef __PIC32MX__
    #define __T4_ISR    __ISR(_TIMER_4_VECTOR, ipl1)
#else
    #define __T4_ISR    __attribute__((interrupt, shadow, auto_psv))
#endif

/* */
void __T4_ISR _T4Interrupt(void)
{
    tick++;

    // Clear flag
    #ifdef __PIC32MX__
    mT4ClearIntFlag();
    #else
    IFS1bits.T4IF = 0;
    #endif
}

/*********************************************************************
* Function: void TickInit(void)
*
* PreCondition: none
*
* Input: none
*
* Output: none
*
* Side Effects: none
*
* Overview: sets tick timer
*
* Note: none
*
********************************************************************/

/*********************************************************************
 * Section: Tick Delay
 *********************************************************************/

// for a system clock of 72 MHz
#ifdef __PIC32MX__
    #define TICK_PERIOD (72000 / 8)
#else

// for a system clock of 32 MHz
    #define TICK_PERIOD 16000
#endif

/* */
void TickInit(void)
{

    // Initialize Timer4
    #ifdef __PIC32MX__
    OpenTimer4(T4_ON | T4_PS_1_8, TICK_PERIOD);
    ConfigIntTimer4(T4_INT_ON | T4_INT_PRIOR_1);
    #else
    TMR4 = 0;
    PR4 = TICK_PERIOD;
    IFS1bits.T4IF = 0;  //Clear flag
    IEC1bits.T4IE = 1;  //Enable interrupt
    T4CONbits.TON = 1;  //Run timer
    #endif
}

/*********************************************************************
* Function: WORD ExternalMemoryCallback(EXTDATA* memory, LONG offset, WORD nCount, void* buffer)
*
* PreCondition: none
*
* Input:  memory - pointer to the bitmap or font external memory structures
*                  (FONT_EXTERNAL or BITMAP_EXTERNAL)
*         offset - data offset
*         nCount - number of bytes to be transferred to the buffer
*         buffer - pointer to the buffer
*
* Output: number of bytes were transferred.
*
* Side Effects: none
*
* Overview: this function must be implemented in application. Graphics Library calls it
*           each time the data from external memory is required. The application must copy 
*           required data to the buffer provided.
*
* Note: none
*
********************************************************************/

// If there are several memories in the system they can be selected by IDs.
// In this demo ID for memory chip installed on Graphics PICTail board is assumed to be 0.
#define SST39_MEMORY    0

/* */

WORD ExternalMemoryCallback(EXTDATA *memory, LONG offset, WORD nCount, void *buffer)
{
    if(memory->ID == SST39_MEMORY)
    {
        // Read data requested into buffer provided
        EEPROMReadArray(memory->address + offset, // address to read from
        (BYTE *)buffer, nCount);
    }

    return (nCount);
}
