/*================================< Show.c >==================================*/
//
//    Title:      SHOW APPLICATION
//    Saved date: 16 Jul 2003 10:49:15
//    Written by: JAG
//    Project:    RMS101 SBC
//    Target:     LH79520
//    Compiler:   GNU GCC for ARM
//		Copyright:	Subject to the Revely Open Source License (see readme.txt)
//
// Show.c demonstrates the capabilities of the RMS101 SBC.
// Various graphical objects are drawn on the screen in VGA resolution.
// Single key commands entered on the keyboard select different options.
// 
// History:                     
// 05/05/03 JAG Initial Release
// 02/06/03 JAG Added PAL video mode
// 15/07/03 JAG Added disk access demo code
//
//============================================================================*/
    
#include <stddefs.h>          
#include <regs.h>                 
#include <uart1.h> 
#include <flash.h>
#include <sdram.h>  
#include <graphics.h>
#include <rstring.h>
#include <video.h>
#include <logoyw.h>
#include <rms101.h>
#include <system.h>
#include <sprites.h>
#include <card.h>
     
/*-----------------------------< Defines >-----------------------------*/


/*----------------------------< Prototypes >---------------------------*/

void InitializeHardware(void);
void Sketch(void);
void TestSound(void);
void SpriteDemo(void);
void Presentation(void);
void FlashFileInfo(void);
BYTE CheckCard(void);

/*-----------------------------< Typedefs >----------------------------*/
// File System Stuff
struct diskinfo
{
	HALF	hBytesPerSector;
	BYTE	bSectorsPerCluster;
	HALF  hMaxRootEntries;
	HALF  hSectors;
	HALF  hSectorsPerFat;
	char  sFatName[8];
	char  sVolName[11];
	WORD	wFat1Addr;
	WORD	wFat2Addr;
	WORD	wDataAddr;
	WORD	wRootDirAddr;
} DiskInfo;
	
typedef struct direntry
{
	char	sName[8];
	char	sExt[3]; 
	BYTE	bAttr;
	BYTE	bReserved[10];
	HALF	hTime;
	HALF	hDate;
	HALF	hCluster;
	WORD	wSize;
} DIR;

/*------------------------------< Globals >----------------------------*/
char str[100];  		// GP string
BYTE TBuff[512];		// Temporary File buffer
	
/*--------------------------------< Main >-----------------------------*/
  
int _main(void)
{
	WORD i,j;
	
	InitializeHardware();
	 	
	while (1)
	{
		UartSend("\r\n\r\n");
		UartSend("----------------------------\r\n");
		UartSend("    RMS101 SHOW PROGRAM\r\n");
		UartSend("Revely Microsystems 07-15-03\r\n");
		UartSend("----------------------------\r\n");
		 
		TestSound();
		
		GraphTextXY("RMS101 SBC SHOW APPLICATION", 100, 40, GREY, BOLD); 
		GraphTextXY("Revely Microsystems", 100, 60, GREY, BOLD); 
		GraphTextXY("Copyright Jul-15 2003", 100, 80, GREY, BOLD);
		GraphTextXY("www.revely.com", 100, 100, GREY, BOLD);
		
		// Display all characters
		GraphTextXY(" ! #$%&'()*+,-./", 100, 200, BLUE, BOLD);
		GraphTextXY("0123456789:;<=>?", 100, 214, BLUE, BOLD);
		GraphTextXY("@ABCDEFGHIJKLMNO", 100, 228, BLUE, BOLD);
		GraphTextXY("PQRSTUVWXYZ[\\]^_", 100, 242, BLUE, BOLD);
		GraphTextXY("`abcdefghijklmno", 100, 256, BLUE, BOLD);
		GraphTextXY("pqrstuvwxyz{|}~", 100, 270, BLUE, BOLD);
		
		GraphTextXY(" ! #$%&'()*+,-./", 400, 200, BLUE, THIN);
		GraphTextXY("0123456789:;<=>?", 400, 214, BLUE, THIN);
		GraphTextXY("@ABCDEFGHIJKLMNO", 400, 228, BLUE, THIN);
		GraphTextXY("PQRSTUVWXYZ[\\]^_", 400, 242, BLUE, THIN);
		GraphTextXY("`abcdefghijklmno", 400, 256, BLUE, THIN);
		GraphTextXY("pqrstuvwxyz{|}~", 400, 270, BLUE, THIN);
	
		// 16 Color bars
		for (i=0; i<6; i++)
		{
			GraphLine(400+i, 40, 400+i, 100, 0);
			GraphLine(406+i, 40, 406+i, 100, 1);
			GraphLine(412+i, 40, 412+i, 100, 2);
			GraphLine(418+i, 40, 418+i, 100, 3);
			GraphLine(424+i, 40, 424+i, 100, 4);
			GraphLine(430+i, 40, 430+i, 100, 5);
			GraphLine(436+i, 40, 436+i, 100, 6);
			GraphLine(442+i, 40, 442+i, 100, 7);
			GraphLine(448+i, 40, 448+i, 100, 8);
			GraphLine(454+i, 40, 454+i, 100, 9);
			GraphLine(460+i, 40, 460+i, 100, 10);
			GraphLine(466+i, 40, 466+i, 100, 11);
			GraphLine(472+i, 40, 472+i, 100, 12);
			GraphLine(478+i, 40, 478+i, 100, 13);
			GraphLine(484+i, 40, 484+i, 100, 14);
			GraphLine(490+i, 40, 490+i, 100, 15);
		}
		// 216 color bars
		for (i=0; i < 432; i++)
		{
			GraphLine(104+i, 130, 104+i, 140, i/2+40);
			GraphLine(105+i, 130, 105+i, 140, i/2+40);
		}			
		
		Sketch();
		
	}
}

/*---------------------------< InitializeHardware >--------------------------*/
void InitializeHardware(void)
{
	// Initialize UART 1 as ASCII terminal
	UartInit(BAUD_115200);
	
	// Many I/O's default to Inputs. Set these to an appropriate state since
	// they are not initialized elsewhere.
	// PORT H Bits 5-7 are outputs
	PORTH_DDR |= 0xe0;
	MEMMUX &= 0xffffc7ff;
	// PORT C Bits 0-2 are outputs
	PORTC_DDR |= 0x07;
	// PORT B Bits 0-3 are outputs
	PORTB_DDR |= 0x0f;
	// PORT A Bits 0-2 and 5-7 are outputs
	PORTA_DDR |= 0xe7;
		
	// Set up video hardware
	GraphInit(VRES_VGA, VOUT_RGB);
	GraphSetPalette();
	GraphClear(); 
	
	// Other stuff
	SysInit();
}

/*-------------------------------< TestSound >-------------------------------*/
void TestSound(void)
{
	SoundOn(D4); 
	SysDelay(50);
	SoundOn(E4);
	SysDelay(50);
	SoundOn(F4);
	SysDelay(50);
	SoundOn(G4);
	SysDelay(50);
	SoundOn(A4);
	SysDelay(50);
	SoundOn(B4);
	SysDelay(50);
	SoundOn(C5);
	SysDelay(50);
	SoundOn(D5);
	SysDelay(50);
	SoundOff();
}

/*------------------------------< Sketch >-----------------------------*/
void Sketch(void)
{
	WORD x,y, z;
	BYTE b=0,c, bc;

	GraphTextXY("SKETCH INSTRUCTIONS", 100, 330, GREEN, BOLD);
	GraphTextXY("Use Arrow keys to draw", 100, 344, GREEN, THIN);
	GraphTextXY("C=Pen Color B=Paper Color", 100, 358, GREEN, THIN);
	GraphTextXY("E=Erase G=Graphics F=Flash Info", 100, 372, GREEN, THIN);
	GraphTextXY("R=RGB N=NTSC P=PAL S=Sound", 100, 386, GREEN, THIN);

	y=400;x=420;c=1;bc=0;
	
	while (1)
	{
		if (c > 15)
			c = 0;
		
		// 4 pixel block
		GraphDraw(x,y,c);
		GraphDraw(x-1,y,c);
		GraphDraw(x,y-1,c);
		GraphDraw(x-1,y-1,c);
	
		b = toupper(getch());
			
		switch (b)
		{
			case 'C':	c++;
							b=0;
							break;
			case 'B':	if (++bc > 15)
								bc = 0;
							GraphSetBackground(bc);
							b=0;
							break;
			case 'N':	GraphInit(VRES_VGA, VOUT_NTSC);
							break;
			case 'P':	GraphInit(VRES_VGA, VOUT_PAL);
							break;
			case 'G':	Presentation();
							return;
							break;
			case 'R':	GraphInit(VRES_VGA, VOUT_RGB);
							break;
			case 'S':	TestSound();
							break;
			case 'E':	SpriteDemo();	// Erase
							GraphClear();
							return;
							break;
			case 'F':	FlashFileInfo();
							GraphClear();
							return;
							break;
			case 	1:		y-=2;		// Up arrow
						break;
			case 	2:		y+=2;		// Down arrow
							break;
			case  3:		x-=2;		// Left arrow
							break;
			case  4:		x+=2;		// Right arrow
							break; 
		}
		
		if (y > 479)
			y = 479;
		if (x > 639) 
			x=639;
	} 
}

/*----------------------------< SpriteDemo >---------------------------*/
void SpriteDemo(void)
{
	WORD wH1, wX, wM, wFire;
	
	wH1 = GraphDrawSprite(0, 450, SprJet);
	for (wX=0; wX < 620; wX+=2)
	{
		// Anything to shoot at ?
		wFire=FALSE;
		for (wM=448; wM!=4; wM-=1)
		{
			if (GraphGetPixel(wX+7,wM) != BG)
				wFire=TRUE;
			if (GraphGetPixel(wX+8,wM) != BG)
				wFire=TRUE;
		}
		
		if (wFire)
		{
			// Fire Missile
			for (wM=448; wM!=4; wM-=2)
			{
				SoundOn(wM+600);
				GraphDraw(wX+7, wM, RED);
				GraphDraw(wX+7, wM-1, RED);
				GraphDraw(wX+7, wM-2, RED);
				GraphDraw(wX+8, wM, RED);
				GraphDraw(wX+8, wM-1, RED);
				GraphDraw(wX+8, wM-2, RED);
				GraphDraw(wX+7, wM+1, BG);
				GraphDraw(wX+7, wM+2, BG);
				GraphDraw(wX+8, wM+1, BG);
				GraphDraw(wX+8, wM+2, BG);
			}
			GraphDraw(wX+7, 4, BG);
			GraphDraw(wX+7, 5, BG);
			GraphDraw(wX+7, 6, BG);
			GraphDraw(wX+8, 4, BG);
			GraphDraw(wX+8, 5, BG);
			GraphDraw(wX+8, 6, BG);
			SoundOff();
		}
		else
			SysDelay(20);
		GraphMoveSprite(wH1, 1, 0);
		GraphMoveSprite(wH1, 1, 0);
	}
	GraphKillSprite(wH1); 
}

/*---------------------------< Presentation >--------------------------*/
void Presentation(void)
{
	WORD wI;
	
	while (!kbhit())
	{ 
		GraphClear();
		GraphDisplayBitMap((PHALF)rms101, rms101_w, rms101_h, 1);
		SysDelay(3000);

		GraphClear();
		GraphDisplayBitMap((PHALF)logoyw, logoyw_w, logoyw_h, 1);
		SysDelay(3000);
	}
	getch();
	GraphClear();
}

/*----------------------------< FileFileInfo >-------------------------*/
void FlashFileInfo(void)
{
	WORD wI, wFatSize, wPos;
	DIR *pDir;
	
	GraphClear();
	GraphTextXY("Reading Information from MMC Flash Card...",0,0,WHITE, BOLD);
	GraphTextXY("(Card Must be FAT16 format >=32MB)",0,14, WHITE, BOLD);
	
	// Detect Card
	CardSlotInit();
	while (!CardDetect())
	{
		GraphTextXY("ERROR : No Card Present - Press any key",0,460, RED, THIN);
		getch();
		return;
	}
	// Init Card
	if (!CardInit())
	{
		GraphTextXY("ERROR : Can't Initialize Card - Press any key",0,460, RED, THIN);
		getch();
		return;
	}
		
	// Read VBR
	if (CardReadBlock(0, TBuff) == FALSE)
	{
		GraphTextXY("ERROR : Can't Read Volume Boot Record - Press any key",0,460, RED, THIN);
		getch();
		return;
	}
	// Extract Disk Vitals
	DiskInfo.hBytesPerSector = (HALF)TBuff[0x0b] + TBuff[0x0c] * 256;
	DiskInfo.bSectorsPerCluster = TBuff[0x0d];
	DiskInfo.hMaxRootEntries = (HALF)TBuff[0x11] + TBuff[0x12] * 256;
	DiskInfo.hSectors = (HALF)TBuff[0x13] + TBuff[0x14] * 256;
	DiskInfo.hSectorsPerFat = (HALF)TBuff[0x16] + TBuff[0x17] * 256;
	TBuff[0x3e] = NULL;
	strcpy (DiskInfo.sFatName, &TBuff[0x36]);
	
	// Calculate Addresses
	wFatSize = DiskInfo.hSectorsPerFat * DiskInfo.hBytesPerSector;
	DiskInfo.wFat1Addr = DiskInfo.hBytesPerSector * 2;
	DiskInfo.wFat2Addr = DiskInfo.wFat1Addr + wFatSize;
	DiskInfo.wRootDirAddr = DiskInfo.wFat2Addr + wFatSize;
	DiskInfo.wDataAddr = DiskInfo.wRootDirAddr + DiskInfo.hMaxRootEntries * 32;
		
	// Display Disk Vitals
	GraphTextXY("Bytes per Sector   : ",0,28,GREEN, THIN);
	SprintWord(str, DiskInfo.hBytesPerSector, 5);
	GraphTextXY(str, 200,28, GREEN, THIN);
	
	GraphTextXY("Sectors per Cluster: ", 0,42,GREEN, THIN);
	SprintWord(str, DiskInfo.bSectorsPerCluster, 5);
	GraphTextXY(str, 200,42, GREEN, THIN);
	
	GraphTextXY("Max Root Entries   : ", 0,56,GREEN, THIN);
	SprintWord(str, DiskInfo.hMaxRootEntries, 5);
	GraphTextXY(str, 200,56, GREEN, THIN);
	
	GraphTextXY("Sectors under 32MB : ", 0,70,GREEN, THIN);
	SprintWord(str, DiskInfo.hSectors, 5);
	GraphTextXY(str, 200,70, GREEN, THIN);
	
	GraphTextXY("Sectors per FAT    : ",0,84,GREEN, THIN);
	SprintWord(str, DiskInfo.hSectorsPerFat, 5);
	GraphTextXY(str, 200,84,GREEN, THIN);
			
	GraphTextXY("FAT Type           : ",0,98, GREEN, THIN);
	strcpy(str, DiskInfo.sFatName);
	GraphTextXY(str, 200,98, GREEN, THIN);
	
	GraphTextXY("Start of Data      : ",0,112, GREEN, THIN);
	SprintWord(str, DiskInfo.wDataAddr, 5);
	GraphTextXY(str, 200,112, GREEN, THIN);
	
	GraphTextXY("Total Space (MB)   : ", 0,126,GREEN, THIN);
	wI = (DiskInfo.hBytesPerSector * DiskInfo.hSectors) / 1048576;
	SprintWord(str, wI, 5);
	GraphTextXY(str, 200,126, GREEN, THIN);
	
	// Show contents of root directory
		
	if (CheckCard()==FALSE)
	{
		GraphClear();
		return;
	}
	// Read root directory data	
	if (CardReadBlock(DiskInfo.wRootDirAddr, TBuff) == FALSE)
	{
		GraphTextXY("ERROR : Read Error - Press any key", 0,460,RED, THIN);
		getch();
		return;
	}
	// First get volume label
	pDir = (DIR*)TBuff+0;
	strcpy(str, "Root Directory Contents of Volume :  ");
	strncpy(&str[36], pDir->sName, 8);
	str[44]=NULL;
	GraphTextXY(str, 0,154, WHITE, BOLD);
	// Display contents of directory (limited to 16 right now)
	wI=1, wPos=0;
	do
	{
		pDir = (DIR*)(TBuff+(32*wI));
		// Ignore if Deleted or Long file name
		if ((pDir->sName[0] != 0xe5) && (pDir->bAttr != 0x0f))
		{
			// If it's a directory print name and <DIR>
			if (pDir->bAttr & 0x10)
			{
				strncpy(&str[0], pDir->sName, 8);
				strcpy(&str[8], " <DIR>\0");
				GraphTextXY(str, 0,168 + wPos++ * 14, GREEN, THIN);
			}
			else if (pDir->sName[0])
			{
				// Print name and extension and size	
				strncpy(&str[0], pDir->sName, 8);
				str[8]='.';
				strncpy(&str[9], pDir->sExt, 3);
				str[12]=' ';
				SprintWord(&str[13],pDir->wSize, 8);
				strcpy(&str[21]," bytes\0");
				GraphTextXY(str,0,168 + wPos++ * 14,GREEN, THIN);
			}
		}
		wI++;
	} while ((pDir->sName[0]) && (wI <= 16));	
	
	GraphTextXY("Press any key to continue", 0,460, GREEN, THIN);
	getch();
	return;
}

/*-----------------------------< CheckCard >---------------------------------*/
BYTE CheckCard(void)
{
	// Detect Card
	CardSlotInit();
	while (!CardDetect())
	{
		GraphTextXY("ERROR : No Card Present - Press any key", 0,460,RED, THIN);
		return FALSE;
	}
	// Init Card
	if (!CardInit())
	{
		GraphTextXY("ERROR : Can't Initialize Card - Press any key", 0,460,RED, THIN);
		return FALSE;
	}
	return TRUE;
}

// end of show.c
