//----------------------------------------------------------------------------
// C main line
//----------------------------------------------------------------------------

#include <m8c.h>        // part specific constants and macros
#include "PSoCAPI.h"    // PSoC API definitions for all User Modules
#include <stdlib.h>
#include <string.h>

#include "tk_80_games.h"

void init(void);
void all_key_off(void);
void key_wait_ms(unsigned int n);
void push_tk80_key(unsigned char c);
void tk80_push_string(unsigned char *string);
void tk80_push_codestring(unsigned char *string);
void tk80_push_ccodestring(const unsigned char *string);
void tk80_display_string(unsigned char *string, int is_last_wait);
void tk80_display_8char(unsigned char *string);
void tk_80_push_gamecode(const unsigned char *string);

//RESET			:R
//RET			:B
//RUN			:G
//STORE DATA	:S
//LOAD DATA		:L
//ADRS SET		:A
//READ INCR		:I
//READ DECR		:D
//WRITE INCR	:W
//NORMAL KEYS	:0123456789abcdef

//const static int tk80_wait_after_key_push = 120;
//const static int tk80_wait_after_key_release = 120;
//
//const static int tk80_wait_after_key_push = 50;
//const static int tk80_wait_after_key_release = 50;
//
//static const int tk80_wait_after_key_push = 50;
//static const int tk80_wait_after_key_release = 10;

static const int tk80_wait_after_key_push = 50;
static const int tk80_wait_after_key_release = 10;

static unsigned char tk80_init[] = "R  8000A";
static unsigned char tk80_run_8000h[] = "8000AG";

	
void main(void)
{
	#define MAX_RCV_LEN_NUM (256)
	static unsigned char cmdBuff[MAX_RCV_LEN_NUM];
	
	char *recvd;
	int mode = 0;
	int i;
	//							   1234567812345678123456781234567812345678
 	unsigned char test_string[] = "Hello   from    TK-80.";
	
	//-------------------------------------------------------------
	M8C_EnableGInt;
	
    init();
	
	mode = (((PRT2DR>>7) & 1) * 0x01) | (((PRT2DR>>5) & 1) * 0x02) | (((PRT2DR>>3) & 1) * 0x04) | (((PRT2DR>>1) & 1) * 0x08);
	for( i=0 ; i<mode ; i++)
	{
		LED_MODE0_On();
		key_wait_ms(250);
		LED_MODE0_Off();
		key_wait_ms(250);
	}
	
	if( mode == 0 ){
		//DEMO mode
		for(i=0;i<5;i++)
		{
			LED_MODE1_On();
			key_wait_ms(1000);
			LED_MODE1_Off();
			key_wait_ms(1000);
		}
		LED_MODE1_On();
		while(1) tk80_display_string(test_string, 1);
	}else if( mode == 1 ){
		//TELNET Server mode
		LED_MODE1_On();
		while(1){
			if( UART_1_bCmdCheck() ){
				recvd = UART_1_szGetParam();
				strncpy( cmdBuff, recvd, MAX_RCV_LEN_NUM );
				cmdBuff[MAX_RCV_LEN_NUM-1] = '\0';
				UART_1_CmdReset();
				
				tk80_display_string(cmdBuff, 0);
			}
		}
	}else if( mode == 2 ){
		//HTTP Server mode
		int http_mode = 0;
		int is_display_string = 0;
		char * ptr;
		char c;
		LED_MODE1_On();
		while(1){
			if( UART_1_bCmdCheck() ){
				recvd = UART_1_szGetParam();
				if( recvd[0] == 'G' && recvd[1] == 'E' && recvd[2] == 'T' && recvd[3] == ' ' )
				{
					http_mode = 0;
					ptr = recvd;
					while(*ptr++){
						if( ptr[0] == '?' && ptr[1] == 't' && ptr[2] == '=' )
						{
							i = 0;
							ptr += 3;
							while(*ptr != '\0' && *ptr != ' ')
							{
								c = *ptr++;
								if( c == '+' ) cmdBuff[i++] = ' ';
								else cmdBuff[i++] = c;
							}
							cmdBuff[i++] = '\0';
							http_mode = 1;
							LED_MODE0_On();
						}
					}
				}
				
				if( !recvd[0] )
				{	//改行のみだった。
					if( http_mode == 0 )
					{
						//Content-Length: 68\r\n
						UART_1_CPutString("HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n<html><head><title>The TK-80 automata.</title></head><body><H3>The TK-80 automata.</h3><form method='get' action='/'>String to display:<input type='text' name='t'><input type='submit' value='GO'></form><hr>by <a href='http://twitter.com/mizunon' target='_blank'>http://twitter.com/mizunon</a></body></html>");
					}else if( http_mode == 1 ){
						UART_1_CPutString("HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n<html><head><title>The TK-80 automata.</title></head><body>Display start!<br>[");
						UART_1_PutString(cmdBuff);
						UART_1_CPutString("]<br><a href='/'>TOP</a><hr>by <a href='http://twitter.com/mizunon' target='_blank'>http://twitter.com/mizunon</a></body></html>");
						
						is_display_string = 1;
					}
					//LED_MODE0_On();
				}
				UART_1_CmdReset();
				
				if( is_display_string == 1 )
				{
					tk80_display_string(cmdBuff, 0);
					is_display_string = 0;
					LED_MODE0_Off();
				}
			}
		}
	}else if( mode == 3 ){
		//TCP Keypad mode
		char * ptr;
		
		LED_MODE1_On();
		while(1){
			if( UART_1_bCmdCheck() ){
				recvd = UART_1_szGetParam();
				strncpy( cmdBuff, recvd, MAX_RCV_LEN_NUM );
				cmdBuff[MAX_RCV_LEN_NUM-1] = '\0';
				UART_1_CmdReset();
				
				ptr = cmdBuff;
				while( *ptr ) push_tk80_key(*ptr++);
			}
		}
	}else if( mode == 0x0f ){
		tk_80_push_gamecode(tk_80_game_mogura);
	}else if( mode == 0x0e ){
		tk_80_push_gamecode(tk_80_game_slot);
	}else if( mode == 0x0d ){
		tk_80_push_gamecode(tk_80_game_oddclps);
	}else if( mode == 0x0c ){
		tk_80_push_gamecode(tk_80_game_moo);
	}else if( mode == 0x0b ){
		tk_80_push_gamecode(tk_80_game_wildsevn);
	}else if( mode == 0x0a ){
		tk_80_push_gamecode(tk_80_game_flipflop);
	}
}


//http://ja.wikipedia.org/wiki/7%E3%82%BB%E3%82%B0%E3%83%A1%E3%83%B3%E3%83%88%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4
static const char *seg_code_numeric[] = {
	//0    1    2    3    4    5    6    7    8    9
	"3f","06","5b","4f","66","6d","7c","07","7f","67"
	};
static const char *seg_code_alpha[] = {
	//a    b    c    d    e    f    g    h    i    j    k    l    m    n    o    p    q    r    s    t    u    v    w    x    y    z
	"77","7c","58","5e","79","71","3d","74","04","1e","75","38","37","54","5c","73","7b","50","6c","78","1c","3e","7e","76","6e","1b"
	};
static const char *seg_code[] = {
	"32f883", "32f983", "32fa83", "32fb83", "32fc83", "32fd83", "32fe83", "32ff83", 
	};

void tk80_display_8char(unsigned char *string)
{
	static unsigned char code_buff_8seg[128];

	int count = 0;
	int tk80_8seg_address = 0x83f8;
	unsigned char c = 0;
	
	//memset(code_buff_8seg, 0, 128);
	code_buff_8seg[0] = '\0';
	while(count < 8 && (c = *string++)){
		cstrcat( code_buff_8seg, "3e" );
		
		if(      '0' <= c && c <= '9' ) cstrcat( code_buff_8seg, seg_code_numeric[c-'0'] );
		else if( 'a' <= c && c <= 'z' ) cstrcat( code_buff_8seg, seg_code_alpha[c-'a'] );
		else if( 'A' <= c && c <= 'Z' ) cstrcat( code_buff_8seg, seg_code_alpha[c-'A'] );
		else if( c == '-'             ) cstrcat( code_buff_8seg, "40" );
		else if( c == '_'             ) cstrcat( code_buff_8seg, "08" );
		else if( c == '~'             ) cstrcat( code_buff_8seg, "01" );
		else if( c == '\''            ) cstrcat( code_buff_8seg, "20" );
		else if( c == '.' || c == ',' ) cstrcat( code_buff_8seg, "80" );
		else cstrcat( code_buff_8seg, "00" );
		
		cstrcat( code_buff_8seg, seg_code[count++] );
	}
	while(count < 8){
		cstrcat( code_buff_8seg, "3e" );
		cstrcat( code_buff_8seg, "00" );
		cstrcat( code_buff_8seg, seg_code[count++] );
	}
	cstrcat( code_buff_8seg, "76" );
	
	tk80_push_string(tk80_init);
	tk80_push_codestring(code_buff_8seg);
	tk80_push_string(tk80_run_8000h);
}

void tk80_display_string(unsigned char *string, int is_last_wait)
{
	unsigned char buff[9];
	unsigned char c = 0;
	int count = 0;
	int i;
	
	for(i=0;i<9;i++) buff[i] = '\0';
	while( (c = *(string++)) ){
		buff[count++] = c;
		if( count == 8 )
		{
			tk80_display_8char(buff);
			count = 0;

			//memset(buff, 0, 9);
			for(i=0;i<9;i++) buff[i] = '\0';
			
			if( *string != '\0' || is_last_wait ){
				for(i=0;i<10;i++) key_wait_ms(1000);
			}
		}
	}
	if( 0 < count ){
		tk80_display_8char(buff);
		if( is_last_wait )
		{
			for(i=0;i<10;i++) key_wait_ms(1000);
		}
	}
}

void tk80_push_string(unsigned char *string)
{
	int len = strlen(string);
	int i;
	unsigned char c;
	for( i=0 ; i<len; i++)
	{
		c = *(string + i);
		push_tk80_key(c);
	}
}

void tk80_push_codestring(unsigned char *string)
{
	int len = strlen(string);
	int i;
	unsigned char c;
	for( i=0 ; i<len; i++)
	{
		c = *(string + i);
		push_tk80_key(c);
		if( i%2 == 1 ) push_tk80_key('W');
	}
}

void tk80_push_ccodestring(const unsigned char *string)
{
	int len = cstrlen(string);
	int i;
	unsigned char c;
	for( i=0 ; i<len; i++)
	{
		c = *(string + i);
		push_tk80_key(c);
		if( i%2 == 1 ) push_tk80_key('W');
	}
}

void tk_80_push_gamecode(const unsigned char *string)
{
	int i;
	unsigned char init[] = "R  8200A";
	unsigned char start[] = "8200A";
	
	for(i=0;i<2;i++)
	{
		LED_MODE1_On();  key_wait_ms(1000);
		LED_MODE1_Off(); key_wait_ms(1000);
	}
	LED_MODE1_On();
	
	tk80_push_string(init);
	tk80_push_ccodestring(string);
	tk80_push_string(start);
}

void push_tk80_key(unsigned char c)
{
	all_key_off();
	switch(c)
	{
		case 'R':
			LED_TK80_RES_On();
			break;
		case '':
			break;
		case 'B':
			LED_TK80_PA1_On(); LED_TK80_PB6_On(); break;
		case 'G':
			LED_TK80_PA0_On(); LED_TK80_PB6_On(); break;
		case 'S':
			LED_TK80_PA6_On(); LED_TK80_PB6_On(); break;
		case 'L':
			LED_TK80_PA7_On(); LED_TK80_PB6_On(); break;
		case 'A':
			LED_TK80_PA2_On(); LED_TK80_PB6_On(); break;
		case 'I':
			LED_TK80_PA4_On(); LED_TK80_PB6_On(); break;
		case 'D':
			LED_TK80_PA3_On(); LED_TK80_PB6_On(); break;
		case 'W':
			LED_TK80_PA5_On(); LED_TK80_PB6_On(); break;
		case '0':
			LED_TK80_PA0_On(); LED_TK80_PB4_On(); break;
		case '1':
			LED_TK80_PA1_On(); LED_TK80_PB4_On(); break;
		case '2':
			LED_TK80_PA2_On(); LED_TK80_PB4_On(); break;
		case '3':
			LED_TK80_PA3_On(); LED_TK80_PB4_On(); break;
		case '4':
			LED_TK80_PA4_On(); LED_TK80_PB4_On(); break;
		case '5':
			LED_TK80_PA5_On(); LED_TK80_PB4_On(); break;
		case '6':
			LED_TK80_PA6_On(); LED_TK80_PB4_On(); break;
		case '7':
			LED_TK80_PA7_On(); LED_TK80_PB4_On(); break;
		case '8':
			LED_TK80_PA0_On(); LED_TK80_PB5_On(); break;
		case '9':
			LED_TK80_PA1_On(); LED_TK80_PB5_On(); break;
		case 'a':
			LED_TK80_PA2_On(); LED_TK80_PB5_On(); break;
		case 'b':
			LED_TK80_PA3_On(); LED_TK80_PB5_On(); break;
		case 'c':
			LED_TK80_PA4_On(); LED_TK80_PB5_On(); break;
		case 'd':
			LED_TK80_PA5_On(); LED_TK80_PB5_On(); break;
		case 'e':
			LED_TK80_PA6_On(); LED_TK80_PB5_On(); break;
		case 'f':
			LED_TK80_PA7_On(); LED_TK80_PB5_On(); break;
	};
	key_wait_ms(tk80_wait_after_key_push);
	all_key_off();
	key_wait_ms(tk80_wait_after_key_release);
}

void key_wait_ms(unsigned int n)
{
	unsigned int i = 0;
	i = n * 57;
	while(i--);
	i = n * 57;
	while(i--);
}

void init(void)
{
	UART_1_CmdReset();
	UART_1_IntCntl(UART_1_ENABLE_RX_INT);
	UART_1_Start(UART_1_PARITY_NONE);

	LED_TK80_PA0_Start();
	LED_TK80_PA1_Start();
	LED_TK80_PA2_Start();
	LED_TK80_PA3_Start();
	LED_TK80_PA4_Start();
	LED_TK80_PA5_Start();
	LED_TK80_PA6_Start();
	LED_TK80_PA7_Start();
	LED_TK80_PB4_Start();
	LED_TK80_PB5_Start();
	LED_TK80_PB6_Start();
	LED_TK80_RES_Start();
	
	LED_MODE0_Start();
	LED_MODE1_Start();
	all_key_off();
}

void all_key_off(void)
{
	LED_TK80_PA0_Off();
	LED_TK80_PA1_Off();
	LED_TK80_PA2_Off();
	LED_TK80_PA3_Off();
	LED_TK80_PA4_Off();
	LED_TK80_PA5_Off();
	LED_TK80_PA6_Off();
	LED_TK80_PA7_Off();
	LED_TK80_PB4_Off();
	LED_TK80_PB5_Off();
	LED_TK80_PB6_Off();
	LED_TK80_RES_Off();
}