/*
* This program was created by AXELL CORPORATION.
* Copyright (C) 2017 AXELL CORPORATION, all rights reserved.
*/
#include <string.h>
#include "kernel.h"
#include "sample_common.h"
#include "com.h"
#include "AG903_UC3.h"
#include "AG903_errno.h"
#include "DDR_COM.h"
#include "DDR_AG903_FTUART010.h"

/*************************************************************************************
		定数定義
 ************************************************************************************/
enum _ComCmd {				/* -> Com */
	COMCMD_TX_STRING,
	COMCMD_RX_NUMBER,
	COMCMD_RX_CHARA,
};

typedef struct _ComMsg {	/* -> Com */
	uint32_t	cmd;
	uint32_t	size;
	void* 		buf;
	void*		sub;
} ComMsg;

typedef struct _ComPutParam {
	uint32_t	size;
	char* 	buf;
} ComPutParam;

typedef struct _ComGetParam {
	uint32_t	cmd;
	uint32_t	size;
	uint32_t	getsz;
	char* 	buf;
	void		(*func)(void);
} ComGetParam;

#define	COM_PUT_TOUT	(5000)		/* 文字送信タイムアウト */
#define	COM_INTERVAL	(50)		/* ComTaskインターバル */
#define	COM_PUTBUF_CNT	(16)		/* 文字送信Buf段数 */
#define	COM_PUTBUF_SIZE	(AG903_SAMPLE_SYS_PRINT_MAX)		/* 文字送信Bufサイズ */

/*************************************************************************************
		プロトタイプ定義
 ************************************************************************************/
static void PutProc(ComPutParam* putprm);
static void GetProc(ComGetParam* getprm);
static void	ComGetStr(uint32_t cmd, char *buf, uint8_t size, void* clbk);
static void WaitStr(void);
static void CallbackGetStr(void);
static void ComInternalError(int32_t ercd);

/******************************************************************
        resource
 ******************************************************************/
const T_CMBF cmbf_com = {TA_TFIFO, 32, 0, NULL, NULL};		/* -> Com */
const T_COM_SMOD  uart0_ini = {115200, BLEN8, PAR_NONE, SBIT1, FLW_NONE};

/*************************************************************************************
		変数定義
 ************************************************************************************/
static ID ComMbfID;
static _Bool	ComInit = false;
static _Bool	GetStr=false;
volatile static int32_t	ErrorCode = 0;
static ComPutParam	putprm = {0};
static ComGetParam	getprm = {0};
static uint8_t	ComPutBuf[COM_PUTBUF_CNT][COM_PUTBUF_SIZE];

/*******************************
        Com Task
 *******************************/
void ComTask(VP_INT exinf)
{
    ComMsg		msg;
    ER			ercd;

    ini_com(AG903_SAMPLE_DID_UART0, &uart0_ini);
    dly_tsk(1);
    ctr_com(AG903_SAMPLE_DID_UART0, STA_COM, 0);
	ComMbfID = acre_mbf((T_CMBF*)&cmbf_com);
	ComInit = true;

    for(;;) {
		ercd = trcv_mbf(ComMbfID, (VP)&msg, COM_INTERVAL); /* msg待ち */
		if(0 < ercd) {
			switch(msg.cmd) {
				case COMCMD_TX_STRING:
					if(NULL==putprm.buf) {
						putprm.buf  = (char*)msg.buf;
						putprm.size = msg.size;
					}
					break;
				case COMCMD_RX_NUMBER:
				case COMCMD_RX_CHARA:
					if(NULL==getprm.buf) {
						getprm.cmd  = msg.cmd;
						getprm.buf  = (char*)msg.buf;
						getprm.size = msg.size;
						getprm.func = (void(*)(void))msg.sub;
					}
					break;
				default:
					break;
			}
		}
		PutProc(&putprm);
		GetProc(&getprm);
	}
}

/*******************************
        初期化完了チェック
 *******************************/
_Bool ComCheckInit(void)
{
	return ComInit;
}

/*******************************
        文字列出力
 *******************************/
void COM_PutStr(char* str)
{
	static uint8_t cnt=0;
	ComMsg	 msg;
	ER		 ercd;
	uint32_t size;
	uint8_t* buf;

	size = (uint32_t)strlen((char const*)str);
	if(COM_PUTBUF_SIZE<size) {
		size = COM_PUTBUF_SIZE; /* Bufサイズで切る */
	}
	if(COM_PUTBUF_CNT<=cnt) {
		cnt=0;
	}
	buf = &ComPutBuf[cnt++][0];
	sys_memcpy(buf, str, size);

	msg.cmd = COMCMD_TX_STRING;
	msg.size = size;
	msg.buf  = (void*)buf;
	ercd = tsnd_mbf(ComMbfID, (VP)&msg, sizeof(msg), 100);
	if(E_OK != ercd) {
		ComInternalError((int32_t)ercd);
	}
	return;
}

/*******************************
        文字列入力待ち
 *******************************/
void COM_GetNum_Wait(char *buf, uint8_t size)
{
	ComGetStr(COMCMD_RX_NUMBER, buf, size, (void *)CallbackGetStr);	/* size = size+CRLF */
	WaitStr();
	return;
}

void COM_GetChara_Wait(char *buf, uint8_t size)
{
	ComGetStr(COMCMD_RX_CHARA, buf, size, (void *)CallbackGetStr);	/* size = size+CRLF */
	WaitStr();
	return;
}

void COM_GetChara(char *buf, uint8_t size, void* callback)
{
	ComGetStr(COMCMD_RX_CHARA, buf, size, (void *)callback);	/* size = size+CRLF */
	return;
}

/*******************************
        Com Task処理関数
 *******************************/
static void PutProc(ComPutParam* putprm)
{
	if(NULL != putprm->buf) {
		puts_com(AG903_SAMPLE_DID_UART0, (VB*)putprm->buf, (UINT*)&putprm->size, COM_PUT_TOUT);
	}
	putprm->buf = NULL;

	return;
}

static void GetProc(ComGetParam* getprm)
{
    ER			ercd;
	char		chara;

	ercd = getc_com(AG903_SAMPLE_DID_UART0, (VB*)&chara, 0, TMO_POL);
	if( (E_OK!=ercd) || (NULL==getprm->buf) ) {
		return;
	}

	if((getprm->size-2) > getprm->getsz) {
		if(COMCMD_RX_NUMBER == getprm->cmd) {
			if( (('0' <= chara) && ('9' >= chara)) || /* 0〜F入力判定 */
				(('A' <= chara) && ('F' >= chara)) ||
				(('a' <= chara) && ('f' >= chara)) ){
				putc_com(AG903_SAMPLE_DID_UART0, chara, COM_PUT_TOUT);
				*(getprm->buf+getprm->getsz) = chara;
				getprm->getsz++;
			}
		}
		else {
			if( (0x08 != chara) && (0x0d != chara) && (0x0a != chara) ) { /* BS,CRLF以外 */
				putc_com(AG903_SAMPLE_DID_UART0, chara, COM_PUT_TOUT);
				*(getprm->buf+getprm->getsz) = chara;
				getprm->getsz++;
			}
		}
	}
	if( (((getprm->size-2)==getprm->getsz)&&(0x0d==chara)) || /* CRLF入力判定 */
		(((getprm->size-1)==getprm->getsz)&&(0x0a==chara)) ) {
		putc_com(AG903_SAMPLE_DID_UART0, chara, COM_PUT_TOUT);
		*(getprm->buf+getprm->getsz) = chara;
		getprm->getsz++;
	}
	if((0<getprm->getsz)&&(0x08==chara)) { /* BS入力判定 */
		putc_com(AG903_SAMPLE_DID_UART0, chara, COM_PUT_TOUT);
		putc_com(AG903_SAMPLE_DID_UART0, 0x20, COM_PUT_TOUT);
		putc_com(AG903_SAMPLE_DID_UART0, chara, COM_PUT_TOUT);
		getprm->getsz--;
	}

	if(getprm->size<=getprm->getsz) {
		getprm->func();
		getprm->buf=NULL;
		getprm->getsz=0;
	}

	return;
}

/*******************************
        0〜F入力処理要求
 *******************************/
static void	ComGetStr(uint32_t cmd, char *buf, uint8_t size, void* clbk)
{
	ComMsg	msg;
	ER		ercd;

	msg.cmd = cmd;
	msg.size = size;
	msg.buf  = (void*)buf;
	msg.sub  = clbk;
	ercd = tsnd_mbf(ComMbfID, (VP)&msg, sizeof(msg), 100);
	if(E_OK != ercd) {
		ComInternalError((int32_t)ercd);
	}
	return;
}

/*******************************
        0〜F入力待ち処理
 *******************************/
static void WaitStr(void)
{
	while(1) {
		if(true == GetStr) {
			GetStr = false;
			break;
		}
		dly_tsk(10);
	}
}

/*******************************
        0〜F入力コールバック
 *******************************/
static void CallbackGetStr(void)
{
	GetStr = true;
}

/***********************************
       ERROR
 ***********************************/
static void ComInternalError(int32_t ercd)
{
	ErrorCode = ercd;
    for(;;);
}
