#include <stdint.h>
#include "common.h"
#include "rtc.h"
#include "uart.h"
#include "sysinit.h"
#include "flash.h"
#include "eeprom.h"
#include "ringbuffer.h"
#include "DownloadScoreData.h"
#include "Player.h"
#include <string.h>

#define EVENT_FRAME_FLAG 0x776E //ASCII:"wn"

enum _CMD
{
	CMD_FLASH_WRITE_START = 0x01,
	CMD_FLASH_WRITE_BLOCK,
	CMD_FLASH_WRITE_END,
	CMD_FLASH_SIZE,
	CMD_SCHEDULER_PREV,
	CMD_SCHEDULER_NEXT,
};

#define CMD_OFFEST 0x04

typedef struct _CMD_FLASH_WRITE_BLOCK_HEADER
{
	uint16_t blockIndex;
	uint16_t dataLen;
} __attribute__((packed)) CMD_FLASH_WRITE_BLOCK_HEADER;

typedef enum _EVENT_FRAME_PARSER_STATUS
{
	FRAME_PARSER_STATUS_IDLE = 0,
	FRAME_PARSER_STATUS_SOF_LO,
	FRAME_PARSER_STATUS_SOF_HI,
	FRAME_PARSER_STATUS_RECV_CMD_LEN,

} EVENT_FRAME_PARSER_STATUS;

EVENT_FRAME_PARSER_STATUS frameParseStatus = FRAME_PARSER_STATUS_IDLE;

/* application address */
#define BOOT_ADDR 24 * 1024 //24k

/* flash block size */
#define BLOCK_SIZE 512

ring_buffer_t ring_buffer;

uint8_t cmdBuf[1024];
uint8_t cmdRetBuf[1024];

uint8_t blockBuf[BLOCK_SIZE];

extern uint32_t __SCORE_DATA_FLASH_SIZE__;
extern Player mPlayer;

void UART_HandleInt(UART_Type *pUART)
{

	volatile uint8_t read_temp = 0;

	/* �������Ƿ���� */
	if (UART_CheckFlag(pUART, UART_FlagOR))
	{
		read_temp = UART_ReadDataReg(pUART);
	}
	/* ���������Ƿ��� */
	else if (UART_IsRxBuffFull(pUART))
	{
		/* �������ݵĻ����� */
		read_temp = UART_ReadDataReg(pUART);
		ring_buffer_queue(&ring_buffer, read_temp);
	}
}

/**
 * Initialize UART1 in 8N1 mode
 */
void uart_init()
{

	UART_ConfigType sConfig;

	sConfig.u32SysClkHz = BUS_CLK_HZ; //ѡ��ʱ��ԴΪ����ʱ��
	sConfig.u32Baudrate = 115200;	 //������
	UART_Init(UART0, &sConfig);		  //��ʼ������ 1
	UART_SetCallback(UART_HandleInt);
	UART_EnableInterrupt(UART0, UART_RxBuffFullInt);
	UART_EnableInterrupt(UART0, UART_RxOverrunInt);
	SIM_RemapUART0Pin();
	NVIC_EnableIRQ(UART0_IRQn);
}

void DownloadInit()
{
	uart_init();
	ring_buffer_init(&ring_buffer);
	Flash_Init();
}

uint8_t *GetCmdDataPtr(uint8_t *buffer)
{
	return buffer + CMD_OFFEST;
}

int Protocol_Process(unsigned char *Buf)
{
	int retByteNum = 0;
	uint8_t *rbf;
	uint32_t fSize = (uint32_t)(&__SCORE_DATA_FLASH_SIZE__);

	CMD_FLASH_WRITE_BLOCK_HEADER *cmdFlashWriteBlockHeader;

	switch (Buf[0])
	{
	case CMD_FLASH_WRITE_START:
		StopPlayScheduler(&mPlayer);
		rbf = GetCmdDataPtr(cmdRetBuf);
		rbf[0] = Buf[0];
		retByteNum = 1;
		break;

	case CMD_FLASH_WRITE_END:
		StartPlayScheduler(&mPlayer);
		rbf = GetCmdDataPtr(cmdRetBuf);
		rbf[0] = Buf[0];
		retByteNum = 1;
		break;

	case CMD_FLASH_WRITE_BLOCK:
		cmdFlashWriteBlockHeader = (CMD_FLASH_WRITE_BLOCK_HEADER *)&Buf[1];
		uint32_t addr = cmdFlashWriteBlockHeader->blockIndex * BLOCK_SIZE + BOOT_ADDR;
		Flash_EraseSector(addr);
		memcpy(blockBuf, &Buf[5], cmdFlashWriteBlockHeader->dataLen);
		Flash_Program(addr, blockBuf, cmdFlashWriteBlockHeader->dataLen);

		rbf = GetCmdDataPtr(cmdRetBuf);
		rbf[0] = Buf[0];
		rbf[1] = Buf[1];
		rbf[2] = Buf[2];
		rbf[3] = Buf[3];
		rbf[4] = Buf[4];
		retByteNum = 5;
		break;

	case CMD_FLASH_SIZE:
		rbf = GetCmdDataPtr(cmdRetBuf);
		rbf[0] = Buf[0];
		rbf[1] = fSize & 0xFF;
		rbf[2] = (fSize >> 8) & 0xFF;
		rbf[3] = (fSize >> 16) & 0xFF;
		rbf[4] = (fSize >> 24) & 0xFF;
		retByteNum = 5;
		break;

	default:
		break;
	}
	return retByteNum;
}

void ParseEventFrameStream(ring_buffer_t *buffer)
{
	uint8_t streamByte;
	static int cmdLen = 0;

	switch (frameParseStatus)
	{
	case FRAME_PARSER_STATUS_IDLE:
	{
		if (!ring_buffer_is_empty(buffer))
		{
			ring_buffer_dequeue(buffer, &streamByte);
			if (streamByte == ((uint8_t)(0xFF & EVENT_FRAME_FLAG)))
			{
				frameParseStatus = FRAME_PARSER_STATUS_SOF_LO;
			}
		}
	}
	break;
	case FRAME_PARSER_STATUS_SOF_LO:
	{
		if (!ring_buffer_is_empty(buffer))
		{
			ring_buffer_dequeue(buffer, &streamByte);
			if (streamByte == ((uint8_t)(0xFF & (EVENT_FRAME_FLAG >> 8))))
			{
				frameParseStatus = FRAME_PARSER_STATUS_SOF_HI;
			}
		}
	}
	break;
	case FRAME_PARSER_STATUS_SOF_HI:
	{
		if (ring_buffer_num_items(buffer) >= 2)
		{
			ring_buffer_dequeue(buffer, &streamByte);
			cmdLen = streamByte;
			ring_buffer_dequeue(buffer, &streamByte);
			cmdLen += streamByte << 8;
			frameParseStatus = FRAME_PARSER_STATUS_RECV_CMD_LEN;
		}
	}
	break;

	case FRAME_PARSER_STATUS_RECV_CMD_LEN:
	{
		int bufferRemain = ring_buffer_num_items(buffer);
		static int receiveCounter = 0;
		if (receiveCounter < cmdLen)
		{
			if (bufferRemain > 0)
			{
				if (bufferRemain + receiveCounter > cmdLen)
					bufferRemain = cmdLen - receiveCounter;
				ring_buffer_dequeue_arr(buffer, cmdBuf + receiveCounter, bufferRemain);
				receiveCounter += bufferRemain;
			}
		}
		else
		{
			receiveCounter = 0;
			int retByteNum = Protocol_Process(cmdBuf);
			if (retByteNum > 0)
			{
				cmdRetBuf[0] = (uint8_t)(0xFF & EVENT_FRAME_FLAG);
				cmdRetBuf[1] = (uint8_t)(0xFF & (EVENT_FRAME_FLAG >> 8));
				cmdRetBuf[2] = retByteNum & 0xFF;
				cmdRetBuf[3] = retByteNum >> 8;
				retByteNum += 4;
				UART_SendWait(UART0, cmdRetBuf, retByteNum);
			}

			frameParseStatus = FRAME_PARSER_STATUS_IDLE;
			cmdLen = 0;
		}
	}
	break;

	default:
		break;
	}
}

void DownloadProcess(void)
{
	ParseEventFrameStream(&ring_buffer);
}