#include "ikk-uart.h"
#include "../general/ikk-debug.h"


__attribute__((aligned(4))) uint8_t dma_uartTxBuf[UMSG_NODE_SIZE] = {0};
__attribute__((aligned(4))) uint8_t dma_uartRxBuf[UART_RECEIVER_CACHE_SIZE] = {0};

// Serial Data Sending Time Cycle Period
#define UART_SENTLOOP_INTV				35	// unit:ms
// Serial Data retry Sending Time Cycle Period
#define UART_SENTRETRY_INTERVAL			500	// unit:ms
// Serial Data Receiving Time Cycle Period
#define UART_RECVLOOP_INTV				25	// unit:ms
// Waitting times for Serial Receiving Data
#define UART_RECV_TIMEOUT				3000// unit:ms

// uart message recv queue
UMsgQueueSt g_uMsgRecvQueue,g_uMsgSentQueue;


// uart manager instance
UartManagerSt g_uManagerInsc;

static ev_timer_event_t *ikkUartSentLoopCheckEventEvt = NULL;
static ev_timer_event_t *ikkUartRecvLoopCheckEventEvt = NULL;

static void dma_uartRcvHandler(void);
static s32 ikkUartSentLoopCheckEventHandler(void *arg );

static s32 ikkUartRecvLoopCheckEventHandler(void *arg );
//
//void ikkUartRecvLoopCheckEventHandler(void );
//
/*	DESP: serial usart driver init interface.
 *	PARAM[recv_header]: Recognition Sequence of recv effective data frame header and detection of Data Frame start.
 *	PARAM[recv_header_n]: the length of recv data frame header.
 *	PARAM[buffer_len_index]: the length of paload.
 *	PARAM[addtional_len]: the length of added
 *	PARAM[pfunc_crc]: CRC function.
 *	PARAM[pfunc_incoming]: Callback function when valid data frame is detected, provided by youself.
 *	PARAM[bSleepSupport]: support for sleepy device function.
 * 	Auth: dingmz_frc.20190620.
 * */
kk_err_t kUartModuleInit(GPIO_PinTypeDef Txpin,GPIO_PinTypeDef Rxpin, uint32_t rate, UART_ParityTypeDef parity, UART_StopBitTypeDef stopBits
		, uint8_t recv_header[], uint8_t recv_header_n,uint8_t buffer_len_index,uint8_t addtional_len
		, PFUNC_CRC pfunc_crc, PFUNC_INCOMING_CALLBACK pfunc_incoming
		, bool bSleepSupport )
{
	if((0 == recv_header_n) || (NULL == pfunc_crc) || (NULL == pfunc_incoming)) {
		return KET_ERR_INVALID_PARAM;
	}

	if( recv_header_n > sizeof(g_uManagerInsc.recv_header)) {
		return KET_ERR_INVALID_PARAM;
	}

	kk_err_t err = KET_OK;

	g_uManagerInsc.Rxpin = Rxpin;
	g_uManagerInsc.Txpin = Txpin;
	memcpy(g_uManagerInsc.recv_header, recv_header, recv_header_n);
	g_uManagerInsc.recv_header_n = recv_header_n;
	g_uManagerInsc.buffer_len_index = buffer_len_index;
	g_uManagerInsc.additional_len = addtional_len;

	g_uManagerInsc.pfunc_crc = pfunc_crc;
	g_uManagerInsc.pfunc_incoming = pfunc_incoming;
	g_uManagerInsc.bSleepSupport = bSleepSupport;
	g_uManagerInsc.u16SleepCounter = UART_RECV_TIMEOUT / UART_RECVLOOP_INTV;

	drv_uart_pin_set(Txpin, Rxpin);

	drv_uart_init_self(rate,parity,stopBits, dma_uartRxBuf, sizeof(dma_uartRxBuf)/sizeof(u8), dma_uartRcvHandler);

	//regesiter send time tick
	if(ikkUartSentLoopCheckEventEvt){
		TL_ZB_TIMER_CANCEL(&ikkUartSentLoopCheckEventEvt);
	}
	ikkUartSentLoopCheckEventEvt = TL_ZB_TIMER_SCHEDULE(ikkUartSentLoopCheckEventHandler, NULL, UART_SENTLOOP_INTV);

	//regesiter recv time tick
	if(ikkUartRecvLoopCheckEventEvt){
		TL_ZB_TIMER_CANCEL(&ikkUartRecvLoopCheckEventEvt);
	}
	ikkUartRecvLoopCheckEventEvt = TL_ZB_TIMER_SCHEDULE(ikkUartRecvLoopCheckEventHandler, NULL, UART_RECVLOOP_INTV);

	//reset g_uMsgSentQueue,g_uMsgSentQueue buff
	memset(&g_uMsgSentQueue,0,sizeof(UMsgQueueSt));
	memset(&g_uMsgRecvQueue,0,sizeof(UMsgQueueSt));
	return err;
}

/*  DESP: serial usart message data sent interface.
    Auth: dingmz_frc.20190627.
*/
kk_err_t MsgSent(uint8_t *buffer, uint8_t length )
{
#if 1 // Just for debug
	iKonkeAfSelfPrint("\r\n-- MSG SENT[%d]:\r\n", length);
	iKonkeAfSelfPrintBuffer(buffer, length);
#endif
	return ((drv_uart_tx_start(buffer, length))?KET_OK:KET_ERR_UNKNOW);
}

/*  DESP: message header sniffer.
    Auth: dingmz_frc.20190601.
*/
static bool MsgHeaderSniffer(uint8_t org_data )
{
	if( g_uManagerInsc.header_chunk_index < g_uManagerInsc.recv_header_n ) {
		g_uManagerInsc.header_chunk[g_uManagerInsc.header_chunk_index++] = org_data;
	}else { // shift...
		int index = 0;
		for( ; index < (g_uManagerInsc.recv_header_n - 1); ++index ) {
			g_uManagerInsc.header_chunk[index] = g_uManagerInsc.header_chunk[index + 1];
		}

		g_uManagerInsc.header_chunk[index] = org_data;
	}

	bool _bfound = false;

	if( g_uManagerInsc.header_chunk_index == g_uManagerInsc.recv_header_n ) {
		if( memcmp(g_uManagerInsc.header_chunk, g_uManagerInsc.recv_header, g_uManagerInsc.recv_header_n) == 0 ) {
			_bfound = true;
		}
	}

	return _bfound;
}
//
/*  DESP: pop msg from the head of buffer queue chunk.
    Auth: dingmz_frc.20190626.
*/
static UMsgNodeSt *PopMsg(QueueEm eQ )
{
	UMsgQueueSt *pQ = (eQ == EQU_RECV)?(&g_uMsgRecvQueue):(&g_uMsgSentQueue);

	return (pQ->counter?(&(pQ->node[0])):NULL);
}

/*  DESP: push msg to buffer queue chunk .
    Auth: dingmz_frc.20180626.
*/
static kk_err_t PushMsg(QueueEm eQ, UMsgNodeSt *pNode )
{
	if( NULL == pNode ) {
		return KET_ERR_INVALID_PARAM;
	}

	kk_err_t err = KET_OK;

	UMsgQueueSt *pQ = (eQ == EQU_RECV)?(&g_uMsgRecvQueue):(&g_uMsgSentQueue);

	if( pQ->counter < UMSG_NODE_MAX ) {
		memcpy(&pQ->node[pQ->counter], pNode, sizeof(UMsgNodeSt));
		pQ->counter++;

	}else {
		err = KET_ERR_NO_PERMISSIONS;
	}

	return err;
}

/*	DESP: Remove Msg from Specified position[index base 0].
	Auth: dingmz_frc.20180430.
*/
static kk_err_t RemoveMsg(QueueEm eQ, uint8_t index_pos )
{
	kk_err_t err = KET_OK;

	UMsgQueueSt *pQ = (eQ == EQU_RECV)?(&g_uMsgRecvQueue):(&g_uMsgSentQueue);

	if( index_pos < pQ->counter ) {
		for(int index = index_pos; index < (pQ->counter - 1); ++index ) {
			memcpy(&(pQ->node[index]), &(pQ->node[index + 1]), sizeof(UMsgNodeSt));
		}

		pQ->counter--;
	}else {
		err = KET_ERR_NON_EXIST;
	}

	return err;
}

/*	DESP: serial usart msg sending loop check handler.
 * 	Auth: dingmz_frc.20190702.
 * */
static s32 ikkUartSentLoopCheckEventHandler(void *arg )
{
	UMsgNodeSt *pMsgNode = PopMsg(EQU_SENT);
	if( pMsgNode ) {
		// check if the message is valid.
		if( pMsgNode->sent_try > 0 ) {
			MsgSent(pMsgNode->buffer, pMsgNode->length);
			--pMsgNode->sent_try;
		}
		else {
		// delete msg form head when invaild!
			RemoveMsg(EQU_SENT, 0);
		}
	}
	return 0;
}

/*	DESP: serial usart msg receiving loop check handler.
 * 	Auth: dingmz_frc.20190626.
 * */
static s32 ikkUartRecvLoopCheckEventHandler(void *arg )
{
	UMsgNodeSt *pMsgNode = PopMsg(EQU_RECV), *pMsgSending = PopMsg(EQU_SENT);
	if( pMsgNode ) {
		bool bDispatchEnable = true;
		// reset the recving timeout counter.
		g_uManagerInsc.u16SleepCounter = UART_RECV_TIMEOUT / UART_RECVLOOP_INTV;

		// Does the matching message send a response for the specified message?
		if( pMsgSending ) {
			iKonkeAfSelfPrint("match: org(%X:%X), des(%X:%X)\r\n"
				, pMsgNode->buffer[pMsgSending->matcher_offset], pMsgNode->buffer[pMsgSending->matcher_offset + 1]
				, pMsgSending->matcher[0], pMsgSending->matcher[1]);

			if( memcmp(pMsgNode->buffer + pMsgSending->matcher_offset, pMsgSending->matcher, pMsgSending->matcher_n) == 0 ) {
				pMsgSending->sent_try = 0;
				// need to dispatch?
				if( !pMsgSending->bRspNeedtoDispatch ) {
					bDispatchEnable = false;
				}
			}
		}

		if((bDispatchEnable) && (g_uManagerInsc.pfunc_incoming)) {
			g_uManagerInsc.pfunc_incoming(pMsgNode);
		}
		// Remove the Msg form head;
		RemoveMsg(EQU_RECV, 0);
	}
	return 0;
}

/*  DESP: serial usart message data sent interface.
 *  Note: Actively sending data requiring detection and retransmitting needs to join the sending queue,
 *  	But the ACK packet is sent only once.
    Auth: dingmz_frc.20190627.
*/
kk_err_t kUartMsgSent(UMsgNodeSt *pMsgNode )
{
	kk_err_t err = KET_ERR_UNKNOW;

	if( pMsgNode->sent_try > 0 ) {
		err = PushMsg(EQU_SENT, pMsgNode);
	}else {
		err = MsgSent(pMsgNode->buffer, pMsgNode->length);
	}

	return err;
}

static void dma_uartRcvHandler(void)
{
	static UMsgNodeSt MsgNode;
	bool recving = false;
	uint8_t head_index = 0;

	uint32_t len = *dma_uartRxBuf;
	iKonkeAfSelfPrint("#############dma_uartRcvHandler,recv data len = %d \r\n",len);
	iKonkeAfSelfPrintBuffer(dma_uartRxBuf+4,len);
	memset(&MsgNode,0,sizeof(UMsgNodeSt));
	for(uint8_t i = 0;i< len;i++)
	{
		// find the message header
		if( recving == false ) {
			if( MsgHeaderSniffer(dma_uartRxBuf[i+4]) ) {
				recving = true;
				head_index = i+4-g_uManagerInsc.recv_header_n +1;
				//muster tell this pack data total length
				MsgNode.length = dma_uartRxBuf[head_index+g_uManagerInsc.buffer_len_index]+g_uManagerInsc.additional_len;
				//iKonkeAfSelfPrint("#############bufferlen = %d, addtional len = %d \r\n",dma_uartRxBuf[head_index+g_uManagerInsc.buffer_len_index],g_uManagerInsc.additional_len);
			}
		}else {
			if( MsgNode.length < UMSG_NODE_SIZE )
				memcpy(MsgNode.buffer,dma_uartRxBuf+head_index,MsgNode.length);

			// push to msg queue when crc succeed.
			if( g_uManagerInsc.pfunc_crc(MsgNode.buffer, MsgNode.length)) {
				// process;
				PushMsg(EQU_RECV, &MsgNode);
			}
			recving = false;
		}
	}
}
#if 0
#define UART_TX_PIN		GPIO_PC2
#define UART_RX_PIN		GPIO_PC3

//__attribute__((aligned(4))) u8 moduleTest_uartTxBuf[32] = {0xAA,0x55,0x05,0x01,0x02,0x03,0x04,0x05,0x93,0x04};
//__attribute__((aligned(4))) u8 moduleTest_uartRxBuf[128] = {0};

void module_test_uartRcvHandler(void){
	iKonkeAfSelfPrint("#############33module_test_uartRcvHandler,recv data is \r\n");
	iKonkeAfSelfPrintBuffer(moduleTest_uartRxBuf,50);
}

void UART_TEST(void)
{
	drv_uart_pin_set(UART_TX_PIN, UART_RX_PIN);

	drv_uart_init_self(115200,PARITY_NONE,STOP_BIT_ONE, moduleTest_uartRxBuf, sizeof(moduleTest_uartRxBuf)/sizeof(u8), module_test_uartRcvHandler);

	if(drv_uart_tx_start(moduleTest_uartTxBuf, 10) == 1)
		WaitMs(1000);
}
#endif
