#include "clip.h"

//#define FNAME "CQ_StartSample.elf"
#define FNAME "LCD_Test.elf"
//#define FNAME "demo_block.elf"
//#define FNAME "demo_button.elf"
//#define FNAME "UART_Test.elf"
//#define FNAME "ayaka.elf"

/////////////////////////////////////////////////////////////////////////////
#define APPNAME	"C17WIN"
#define WIDTH	(72)
#define HEIGHT	(32)
#define SCALE	4
unsigned char xbuff[HEIGHT][WIDTH / 8];
int P0 = -1;
int P2 = -1;
/////////////////////////////////////////////////////////////////////////////
BITMAPINFO* pBMI;
RGBQUAD* pRGB;
HWND MainWnd;
LRESULT CALLBACK
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_CHAR:
		if(wParam == 'q') {
			DestroyWindow(hWnd);
			return 0;
		}
		return 0;
	case WM_KEYDOWN:
		switch(wParam) {
		case '2':
			P0 &= ~0x40;
			break;
		case '3':
			P0 &= ~0x80;
			break;
		}
		break;
	case WM_KEYUP:
		switch(wParam) {
		case '2':
			P0 |= 0x40;
			break;
		case '3':
			P0 |= 0x80;
			break;
		}
		break;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}
int
DoMsg()
{
	MSG msg;
	while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
		if(msg.message == WM_QUIT) {
			return 0;
		}
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 1;
}
void
InitUI()
{
	BITMAPINFOHEADER* bi;
	HINSTANCE hInst;
	WNDCLASS wc;
	RECT rcWin;
	RECT rcCli;
	int ncW;
	int ncH;

	pBMI = (BITMAPINFO*)calloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 2, 1);
	bi = &pBMI->bmiHeader;
	pRGB = &pBMI->bmiColors[0];
	bi->biSize = sizeof(BITMAPINFOHEADER);
	bi->biWidth = WIDTH;
	bi->biHeight = -HEIGHT;
	bi->biPlanes = 1;
	bi->biBitCount = 1;

	hInst = GetModuleHandle(NULL);
	//
	memset(&wc, 0, sizeof wc);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.hInstance = hInst;
	wc.hCursor = LoadCursor(NULL, IDC_CROSS);
	wc.lpszClassName = APPNAME;
	RegisterClass(&wc);
	//
	MainWnd = CreateWindow(APPNAME, APPNAME,
		WS_OVERLAPPED,
		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
		NULL, NULL, hInst, NULL);
	//
	GetWindowRect(MainWnd, &rcWin);
	GetClientRect(MainWnd, &rcCli);
	ncW = (rcWin.right - rcWin.left) - (rcCli.right - rcCli.left);
	ncH = (rcWin.bottom - rcWin.top) - (rcCli.bottom - rcCli.top);
	MoveWindow(MainWnd, 0, 0,
		ncW + bi->biWidth  * SCALE,
		ncH - bi->biHeight * SCALE, 0);
	//
	ShowWindow(MainWnd, SW_SHOW);
	UpdateWindow(MainWnd);
}

/****************************************************************************
 *	
 ****************************************************************************/

void
InitROM(const char* fname)
{
	FILE* fp;
	int size;

	Elf32_Ehdr* ehdr;
	Elf32_Phdr* phdr;
	int i;

	/* ELFファイルをロードする */
	fp = fopen(fname, "rb");
	fseek(fp, 0, SEEK_END);
	size = ftell(fp);
	rewind(fp);
	ehdr = malloc(size);
	fread(ehdr, 1, size, fp);
	fclose(fp);

	/* マジックナンバーを確認する */
	if(*(int*)ehdr->e_ident != 0x464C457F) {
		DIE();
	}

	/* 各セグメントについて… */
	for(i = 0; i < ehdr->e_phnum; i++) {
		/* セグメント情報を取得する */
		phdr = (Elf32_Phdr*)((char*)ehdr + ehdr->e_phoff + ehdr->e_phentsize * i);
		/* セグメントをロードする。 */
		if((phdr->p_type == 1/*PT_LOAD*/) && phdr->p_filesz) { /* 実体が無い場合(.bss)はロード不要 */
			printf("addr = %06x, size = %06x\n", phdr->p_paddr, phdr->p_filesz);
			s1c17_flash_load(phdr->p_paddr/*LMA*/, (char*)ehdr + phdr->p_offset, phdr->p_filesz);
		}
	}

	/* バッファを開放 */
	free(ehdr);
}

/****************************************************************************
 *	
 ****************************************************************************/

/* 0x00C07C */
static const unsigned char MagicCode[] = {0x00,0x00,0x17,0xEC};

int
main(int argc, char* argv[])
{
	int t0;
	int t1;
	HDC hDC;
	RECT rc;
	int param;

	InitUI();

	InitROM("SimpleGDBServer.elf");	/* ファームウェア */
	InitROM(FNAME);	/* アプリケーション */

	s1c17_flash_load(0x00C07C, MagicCode, sizeof MagicCode);	//フリーランモードのため
	s1c17_init();
	s1c17_port_set(3, 0);	//フリーランモードのため

	t0 = GetTickCount();
	hDC = GetDC(MainWnd);
	GetClientRect(MainWnd, &rc);
	for(;;) {
		if(!DoMsg()) {
			break;
		}

		//-----------------------------------------------------------
		s1c17_port_set(0, P0);
		s1c17_exec(8000000 / 60);
		param = s1c17_lcd_image(xbuff);
		P2 = s1c17_port_get(2);
		//-----------------------------------------------------------

		{	/* PIECE_BMP→Windows BMP変換 */
			unsigned char tmpbuf[HEIGHT][((WIDTH / 8) + 3) & ~3];
			int i;
			for(i = 0; i < HEIGHT; i++) {
				memcpy(tmpbuf[i], xbuff[i], sizeof xbuff[0]);
			}
			pRGB[0].rgbRed = pRGB[0].rgbGreen = pRGB[0].rgbBlue = (param & 0x18) ? 0 : -1;
			pRGB[1].rgbRed = pRGB[1].rgbGreen = pRGB[1].rgbBlue = (param & 0x03) ? 0 : -1;
			/* S1C17702基板は液晶が上下左右逆に付いているので、反転ビットを逆に解釈する。 */
			if(param & DRW_REVX) {
				if(param & DRW_REVY) {
					StretchDIBits(hDC,
						rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
						0, 0, pBMI->bmiHeader.biWidth, -pBMI->bmiHeader.biHeight,
						tmpbuf, pBMI, DIB_RGB_COLORS, SRCCOPY);
				} else {
					StretchDIBits(hDC,
						rc.left, rc.bottom - 1, rc.right - rc.left, rc.top - rc.bottom,
						0, 0, pBMI->bmiHeader.biWidth, -pBMI->bmiHeader.biHeight,
						tmpbuf, pBMI, DIB_RGB_COLORS, SRCCOPY);
				}
			} else {
				if(param & DRW_REVY) {
					StretchDIBits(hDC,
						rc.right - 1, rc.top, rc.left - rc.right, rc.bottom - rc.top,
						0, 0, pBMI->bmiHeader.biWidth, -pBMI->bmiHeader.biHeight,
						tmpbuf, pBMI, DIB_RGB_COLORS, SRCCOPY);
				} else {
					StretchDIBits(hDC,
						rc.right - 1, rc.bottom - 1, rc.left - rc.right, rc.top - rc.bottom,
						0, 0, pBMI->bmiHeader.biWidth, -pBMI->bmiHeader.biHeight,
						tmpbuf, pBMI, DIB_RGB_COLORS, SRCCOPY);
				}
			}
		}
		{
			static int old_P2;
			if(old_P2 != P2) {
				old_P2 = P2;
				if(P2 & 0x80) {
					SetWindowText(MainWnd, APPNAME);
				} else {
					SetWindowText(MainWnd, APPNAME "■");
				}
			}
		}

		for(;;) {
			t1 = GetTickCount();
			if(t1 - t0 >= 1000 / 60) break;
			Sleep(0);
		}
		t0 = GetTickCount();
	}
	ReleaseDC(MainWnd, hDC);
}

