/*
 * @history     2020_07_22  [SDK3.1] UARTサンプルでPIO転送での動作が安定していない不具合を修正 (#2781)
 * @history     2025_03_06  [SDK3.7] DMA要求が非同期のときの対策がされていない不具合を修正 (#5786)
 */
/*
 * This program was created by Axell Corporation.
 * Copyright (C) 2017-2025 Axell Corporation, all rights reserved.
 */
#include "sample_common.h"
#include "com.h"
#include "uart/uartmgr.h"
#include "register/AG903_uartreg.h"
#include "dmac/dmacmgr.h"
#include "timr/timrmgr.h"

/* プロトタイプ */
static int32_t Uart_init_module(void);
static int32_t Uart_term_module(void);
static void Uart_SampleHelp(void);
static void Uart_EchoBackPio(void);
static void Uart_EchoBackDma(void);
static void Uart_LoopSendDma(void);
static void Uart_EchoBackPioRs485(void);
static void Uart_EchoBackDmaRs485(void);
static void Uart_LoopSendDmaRs485(void);
static void Uart_EchoBack_pio(_Bool rs485en);
static void Uart_EchoBack_dma(_Bool rs485en);
static void Uart_LoopSend_dma(_Bool rs485en);
static void Uart_InitHw(uint8_t ch, uint8_t initype);
static int32_t Uart_WaitSend(uint32_t timout);
static int32_t Uart_WaitDmaTerm(uint32_t timout);
static int32_t Uart_WaitDmaLoop(AG903_DMACMgrHandle* handle, uint32_t timout);
static void Uart_CallbackPio(AG903_UARTMgrHandle* handle, uint32_t event);
static void Uart_CallbackDma(AG903_UARTMgrHandle* handle, uint32_t event);
static void Uart_CallbackDmaTerm(AG903_DMACMgrHandle* handle, AG903_DMACMgrDesc** desc, uint8_t* end);
static void Uart_CallbackDmaAbort(AG903_DMACMgrHandle* handle);
static void Uart_CallbackDmaErr(AG903_DMACMgrHandle* handle);
static void Uart_SFifoInit(void);
static int Uart_SFifoIsEmpty(void);
static int Uart_SFifoIsFull(void);
static int Uart_SFifoWrite(const uint8_t *dat, int size);
static int Uart_SFifoRead(uint8_t *dat, int size);


/* Param */
#define UART_SMP_BUFSIZE		(256)			/* バッファサイズ */
#define UART_SMP_BAUDRATE		(115200)		/* Uart ボー・レート [bps] */
#define UART_SMP_CH				(3)				/* Uart CH [注：CH0はuC3が使用] */
#define UART_SMP_DMACH			(0)				/* DMAC CH */
#define UART_SMP_DMACSEL		(4)				/* DMAC Handshake Select */
#define UART_SMP_LOOP_NUM		(10)			/* Loop Send 数 */
#define UART_SMP_DMASEL_BASE	(0x10)			/* dma_req選択値(UART0) */
#define UART_SMP_DMASEL_TIMR	(0x08)			/* dma_req選択値(TIMR0) */
#define UART_SMP_REG_INTERVAL	(0x00100000)	/* UART Register Interval */
#define UART_SMP_SFIFOSIZE		(512)			/* ソフトFIFOサイズ */

enum {
	UART_SMP_HW_NORMAL=0,
	UART_SMP_HW_RS485,
};

/* Macro */
#define	EPRINT(FMT, ...)		sys_print(0, FMT,##__VA_ARGS__)
#define	PRINT(FMT, ...)			sys_print(0, FMT"\r\n",##__VA_ARGS__)
#define UART_ERROR(str)			sys_print(1, " ERROR:%s[%d] *%s*\r\n",__FUNCTION__, __LINE__, str)

static void (*func[])() = {
	Uart_SampleHelp,
	Uart_EchoBackPio,
	Uart_EchoBackDma,
	Uart_LoopSendDma,
	Uart_EchoBackPioRs485,
	Uart_EchoBackDmaRs485,
	Uart_LoopSendDmaRs485,
};

static volatile int32_t	UartRcvSize=0;
static uint32_t	UartLoopCnt=0;
static _Bool	UartSendEnd=false;
static _Bool	UartDmaTerm=false;
static uint8_t	UartBuf[UART_SMP_BUFSIZE];
static const uint8_t	UartSampleStr1[]={" Uart DMA Loop Send : Sample String 1 \r\n"};
static const uint8_t	UartSampleStr2[]={" Uart DMA Loop Send : Sample String 2 \r\n"};
static const uint8_t	UartTimingParam[]={0,0,2,3};
static struct uart_sfifo {
	uint8_t buf[UART_SMP_SFIFOSIZE];
	volatile int iw;	/* ライトインデックス 割り込み中の更新あり */
	volatile int ir;	/* リードインデックス 割り込み中の更新あり */
} UartSFifo;

/**
 * @brief		メイン処理
 * @param[in]	param	制御パラメータ
 * @return		なし
 * @note		なし
 */
void UART_main(uint8_t param)
{
	uint8_t		mode = 0;
	char		input[2+2];

	((void)param);

	Uart_SampleHelp();	/* Help表示 */

	Uart_init_module();

	while (mode != 0xFF) {
		EPRINT(" -- Choose sample number (00h<HELP> to FFh): ");
		COM_GetNum_Wait(input, sizeof(input));
		mode = (ASCtoBIN(input[0]) << 4)
			 | (ASCtoBIN(input[1]) << 0);
		if(0xFF == mode) {
			break;
		}
		if(mode >= (sizeof(func)/sizeof(void*))) {
			func[0](); /* Help */
		}
		else {
			func[mode]();	/* Sample func実行 */
		}
	}

	Uart_term_module();

	return;
}

/**
 * @brief		サブ処理
 * @param[in]	param	制御パラメータ
 * @return		なし
 * @note		なし
 */
void UART_sub(uint32_t param)
{
	((void)param);
	/* 処理なし */
	return;
}

/**
 * @brief		モジュール初期化
 * @param[in]	なし
 * @retval		AG903_ENONE		正常終了
 * @note		なし
 */
static int32_t Uart_init_module(void)
{
	static _Bool	UartInit=false;
	int32_t 		result;

	if(false == UartInit) {
		result = AG903_UARTMgrInit(UART_SMP_CH); /* Managaer 初期化 */
		if(AG903_ENONE != result) {
			UART_ERROR("Init");
		}
		else {
			UartInit = true;
		}
	}

	return AG903_ENONE;
}

/**
 * @brief		モジュール終了
 * @param[in]	なし
 * @retval		AG903_ENONE		正常終了
 * @note		なし
 */
static int32_t Uart_term_module(void)
{
	/* 処理なし */
	return AG903_ENONE;
}

/**
 * @brief		ヘルプ表示
 * @param		なし
 * @return		なし
 * @note		なし
 */
static void Uart_SampleHelp(void)
{
	PRINT("\t# 00 ... Help");
	PRINT("\t# 01 ... Echo Back PIO");
	PRINT("\t# 02 ... Echo Back DMA");
	PRINT("\t# 03 ... Loop Send DMA");
	PRINT("\t# 04 ... Echo Back PIO RS485");
	PRINT("\t# 05 ... Echo Back DMA RS485");
	PRINT("\t# 06 ... Loop Send DMA RS485");
	PRINT("\t# FF ... Exit Sample");

	return;
}

/**
 * @brief		エコーバック [PIO]
 * @param		なし
 * @return		なし
 * @note		なし
 */
static void Uart_EchoBackPio(void)
{
	Uart_InitHw(UART_SMP_CH, UART_SMP_HW_NORMAL);
	Uart_EchoBack_pio(false);

	return;
}

/**
 * @brief		エコーバック(RS485) [PIO]
 * @param		なし
 * @return		なし
 * @note		なし
 */
static void Uart_EchoBackPioRs485(void)
{
	Uart_InitHw(UART_SMP_CH, UART_SMP_HW_RS485);
	Uart_EchoBack_pio(true);

	return;
}

/**
 * @brief		エコーバック [DMA]
 * @param		なし
 * @return		なし
 * @note		なし
 */
static void Uart_EchoBackDma(void)
{
	Uart_InitHw(UART_SMP_CH, UART_SMP_HW_NORMAL);
	Uart_EchoBack_dma(false);

	return;
}

/**
 * @brief		エコーバック(RS485) [DMA]
 * @param		なし
 * @return		なし
 * @note		なし
 */
static void Uart_EchoBackDmaRs485(void)
{
	Uart_InitHw(UART_SMP_CH, UART_SMP_HW_RS485);
	Uart_EchoBack_dma(true);

	return;
}

/**
 * @brief		ループ送信 [DMA]
 * @param		なし
 * @return		なし
 * @note		なし
 */
static void Uart_LoopSendDma(void)
{
	Uart_InitHw(UART_SMP_CH, UART_SMP_HW_NORMAL);
	Uart_LoopSend_dma(false);

	return;
}

/**
 * @brief		ループ送信(RS485) [DMA]
 * @param		なし
 * @return		なし
 * @note		なし
 */
static void Uart_LoopSendDmaRs485(void)
{
	Uart_InitHw(UART_SMP_CH, UART_SMP_HW_RS485);
	Uart_LoopSend_dma(true);

	return;
}

/**
 * @brief		PIOエコーバック処理
 * @param[in]	rs485en  RS485有効/無効 [true:有効]
 * @return		なし
 * @note		入力文字をエコーバックします。"end\r\n"の入力で終了します。
 * @note		シリアルのパラメータ設定は関数内で行っています。
 */
static void Uart_EchoBack_pio(_Bool rs485en)
{
	AG903_UARTMgrHandle*	handle;
	AG903_UARTMgrParam		com;
	AG903_UARTMgrRs485Param rs485;
	int32_t 	result;
	int32_t 	loop;
	_Bool		end;
	uint8_t 	chara[5]={0};
	uint8_t		buf[16];	/* 送受信処理単位 UARTのFIFOと同サイズで十分 */
	int32_t		buf_size = sizeof(buf)/sizeof(buf[0]);
	int32_t		rsize;

	if(true == rs485en) { /* RS485選択時 */
		PRINT(" Echo back the RS485 Port. [use PIO]");
	}
	else {
		PRINT(" Echo Back the COM2 Port. [use PIO]");
	}

	UartRcvSize=0;
	UartSendEnd=false;
	Uart_SFifoInit();

	/* UART設定 */
	result = AG903_UARTMgrGetHandle(UART_SMP_CH, &handle); 								/* ハンドル取得 */
	if(AG903_ENONE != result) {
		UART_ERROR("GetHandle");
	}
	result = AG903_UARTMgrSetCallback(handle, (AG903_UARTMgrClbk)Uart_CallbackPio);		/* コールバック登録 */
	if(AG903_ENONE != result) {
		UART_ERROR("SetCallback");
	}
	com.baud	= UART_SMP_BAUDRATE;
	com.parity  = AG903_UART_PARITY_NON;
	com.stopbit = AG903_UART_STOPBIT_1;
	com.databit = AG903_UART_DATBIT_8;
	if(true == rs485en) { /* RS485選択時 */
		com.flow = AG903_UART_FLOW_CTS;
	}
	else {
		com.flow = AG903_UART_FLOW_NON;
	}
	result = AG903_UARTMgrSetParam(handle, &com); 										/* UART通信パラメータ設定 */
	if(AG903_ENONE != result) {
		UART_ERROR("SetParam");
	}
	if(true == rs485en) { /* RS485選択時 */
		rs485.setuptime = 1;
		rs485.holdtime  = 1;
		rs485.rcvtime	= 10000;
		rs485.interval	= 10000;
		rs485.timeout	= 10000;
		rs485.event		= 0x00;
		result = AG903_UARTMgrSetRs485Param(handle, &rs485);							/* RS485パラメータ設定 */
		if(AG903_ENONE != result) {
			UART_ERROR("Set485Param");
		}
	}
	result = AG903_UARTMgrReceive(handle, false);										/* 受信開始 */
	if(AG903_ENONE != result) {
		UART_ERROR("Receive");
	}

	/* エコーバック処理 */
	PRINT(" Echo Back is terminated When you enter the 'end+CRLF'.");
	end = false;
	while(1) {
		if (!Uart_SFifoIsEmpty()) {
			rsize = Uart_SFifoRead(buf, buf_size); /* 連続したバッファへコピー */
			if(true == rs485en) { /* RS485選択時 */
				result = AG903_UARTMgrStopReceive(handle); 								/* 受信停止 */
				if(AG903_ENONE != result) {
					UART_ERROR("StopReceive");
				}
			}
			result = AG903_UARTMgrSend(handle, buf, rsize, false); 			/* 送信開始 */
			if(AG903_ENONE != result) {
				UART_ERROR("Send");
			}
			result = Uart_WaitSend(500);												/* 送信完了待ち */
			if(AG903_ENONE != result) {
				UART_ERROR("WaitSend");
			}
			for(loop=0; loop<rsize; loop++) { /* 終了文字検索 */			
				chara[4] = chara[3];
				chara[3] = chara[2];
				chara[2] = chara[1];
				chara[1] = chara[0];
				chara[0] = buf[loop];
				if(('e'==chara[4])&&('n'==chara[3])&&('d'==chara[2])&&(0x0d==chara[1])&&(0x0a==chara[0])) {
					end = true;
					break;
				}
			}
			if(true == end) {
				break; /* 終了 */
			}
			UartRcvSize=0;
			if(true == rs485en) { /* RS485選択時 */
				result = AG903_UARTMgrReceive(handle, false);							/* 受信開始 */
				if(AG903_ENONE != result) {
					UART_ERROR("Receive");
				}
			}
		}
	}

	/* UART停止 */
	result = AG903_UARTMgrStopReceive(handle); 											/* 受信停止 */
	if(AG903_ENONE != result) {
		UART_ERROR("StopReceive");
	}

	result = AG903_UARTMgrStopSend(handle); 											/* 送信停止 */
	if(AG903_ENONE != result) {
		UART_ERROR("StopSend");
	}

	result = AG903_UARTMgrReleaseHandle(handle); 										/* ハンドル解放 */
	if(AG903_ENONE != result) {
		UART_ERROR("ReleaseHandle");
	}

	Uart_SFifoInit();																	/* 残ったデータがあれば破棄 */

	return;
}

/**
 * @brief		DMAエコーバック処理
 * @param[in]	rs485en  RS485有効/無効 [true:有効]
 * @return		なし
 * @note		UART_SMP_BUFSIZE分の文字をDMA受信し、DMA送信でエコーバックします。
 * @note		シリアルのパラメータ設定は関数内で行っています。
 */
static void Uart_EchoBack_dma(_Bool rs485en)
{
	AG903_DMACMgrHandle*	hdl_dmac;
	AG903_UARTMgrHandle*	hdl_uart;
	AG903_UARTMgrParam		com;
	AG903_UARTMgrRs485Param rs485;
    AG903_DMACMgrConfig     config;
	AG903_DMACMgrDesc		desc;
	int32_t 	result;

	if(true == rs485en) { /* RS485選択時 */
		PRINT(" Echo back the RS485 Port. [use DMA]");
	}
	else {
		PRINT(" Echo Back the COM2 Port. [use DMA]");
	}

	UartDmaTerm=false;
	UartSendEnd=false;

	/* UART設定 */
	result = AG903_UARTMgrGetHandle(UART_SMP_CH, &hdl_uart); 							/* UARTハンドル取得 */
	if(AG903_ENONE != result) {
		UART_ERROR("GetUartHandle");
	}
	result = AG903_UARTMgrSetCallback(hdl_uart, (AG903_UARTMgrClbk)Uart_CallbackDma); 	/* UARTコールバック登録 */
	if(AG903_ENONE != result) {
		UART_ERROR("SetUartCallback");
	}
	com.baud	= UART_SMP_BAUDRATE;
	com.parity  = AG903_UART_PARITY_NON;
	com.stopbit = AG903_UART_STOPBIT_1;
	com.databit = AG903_UART_DATBIT_8;
	com.flow	= AG903_UART_FLOW_CTS;
	result = AG903_UARTMgrSetParam(hdl_uart, &com); 									/* UART通信パラメータ設定 */
	if(AG903_ENONE != result) {
		UART_ERROR("SetParam");
	}
	if(true == rs485en) { /* RS485選択時 */
		rs485.setuptime = 1;
		rs485.holdtime  = 1;
		rs485.rcvtime	= 10000;
		rs485.interval	= 10000;
		rs485.timeout	= 10000;
		rs485.event		= 0x00;
		result = AG903_UARTMgrSetRs485Param(hdl_uart, &rs485);							/* RS485パラメータ設定 */
		if(AG903_ENONE != result) {
			UART_ERROR("Set485Param");
		}
	}

	/* DMAC設定 [UART→Memory] */
	Sys_SetDmaInterface(UART_SMP_DMACSEL, (UART_SMP_DMASEL_BASE+(0x02*UART_SMP_CH)));	/* dma_req 選択(受信buf) */
	AG903_DMACMgrSetSyncPeripheral(UART_SMP_DMACH, 1);
	result = AG903_DMACMgrGetHandle(UART_SMP_DMACH, &hdl_dmac); 						/* DMACハンドル取得 */
	if(AG903_ENONE != result) {
		UART_ERROR("GetDmacHandle");
	}
	result = AG903_DMACMgrSetIntCallback(hdl_dmac, Uart_CallbackDmaTerm,
										Uart_CallbackDmaAbort, Uart_CallbackDmaErr);	/* DMACコールバック登録 */
	if(AG903_ENONE != result) {
		UART_ERROR("SetDmacCallback");
	}
	config.val = 0;
	config.st.SrcHEn = 1;
	config.st.SrcRS  = UART_SMP_DMACSEL;
	desc.Ctrl.val = 0;
	desc.Ctrl.st.SrcCtrl = 2; /* Fixed */
	desc.SrcAddr  = (uint32_t)(&AG903_UARTn(UART_SMP_CH)->RBR);
	desc.DstAddr  = (uint32_t)UartBuf;
	desc.Trns.val = UART_SMP_BUFSIZE;
	desc.Stride.val = 0;
	desc.next = 0;
	AG903_DMACMgrSetDescList(hdl_dmac, &config, &desc, 1); 								/* ディスクリプタ設定 */

	/* 受信開始〜受信待ち */
	PRINT(" * Wait receive data %d[Byte]", UART_SMP_BUFSIZE);
	result = AG903_UARTMgrReceive(hdl_uart, true); 										/* UART受信開始(割込み許可) */
	if(AG903_ENONE != result) {
		UART_ERROR("Receive");
	}
	result = AG903_DMACMgrEnable(hdl_dmac); 											/* DMA実行 */
	if(AG903_ENONE != result) {
		UART_ERROR("Enable");
	}
	result = Uart_WaitDmaTerm(60000); 													/* DMA転送完了待ち */
	if(AG903_ENONE != result) {
		UART_ERROR("WaitDmaTerm");
	}
	result = AG903_UARTMgrStopReceive(hdl_uart); 										/* 受信停止(割込み禁止) */
	if(AG903_ENONE != result) {
		UART_ERROR("StopReceive");
	}

	/* DMAC設定 [Memory→UART] */
	Sys_SetDmaInterface(UART_SMP_DMACSEL, (UART_SMP_DMASEL_BASE+(0x02*UART_SMP_CH)+1));	/* dma_req 選択(送信buf) */
	AG903_DMACMgrSetSyncPeripheral(UART_SMP_DMACH, 1);
	config.val = 0;
	config.st.DstHEn = 1;
	config.st.DstRS  = UART_SMP_DMACSEL;
	desc.Ctrl.val = 0;
	desc.Ctrl.st.DstCtrl = 2; /* Fixed */
	desc.SrcAddr  = (uint32_t)UartBuf;
	desc.DstAddr  = (uint32_t)(&AG903_UARTn(UART_SMP_CH)->THR);
	desc.Trns.val = UART_SMP_BUFSIZE;
	desc.Stride.val = 0;
	desc.next = 0;
	AG903_DMACMgrSetDescList(hdl_dmac, &config, &desc, 1); 								/* ディスクリプタ設定 */

	/* 送信開始〜完了待ち */
	PRINT(" * Echo Back %d[Byte]", UART_SMP_BUFSIZE);
	result = AG903_DMACMgrEnable(hdl_dmac); 											/* DMA実行 */
	if(AG903_ENONE != result) {
		UART_ERROR("Enable");
	}
	result = AG903_UARTMgrSend(hdl_uart, NULL, 0, true); 								/* UART送信開始(割込み許可) */
	if(AG903_ENONE != result) {
		UART_ERROR("Send");
	}
	result = Uart_WaitDmaTerm(10000); 													/* DMA転送完了待ち */
	if(AG903_ENONE != result) {
		UART_ERROR("WaitDmaTerm");
	}
	result = Uart_WaitSend(100); 														/* UART送信完了待ち */
	if(AG903_ENONE != result) {
		UART_ERROR("WaitSend");
	}
	result = AG903_UARTMgrStopSend(hdl_uart); 											/* 送信停止 */
	if(AG903_ENONE != result) {
		UART_ERROR("StopSend");
	}

	/* DMAC解放 */
	result = AG903_DMACMgrReleaseHandle(hdl_dmac);										/* ハンドル解放 */
	if(AG903_ENONE != result) {
		UART_ERROR("ReleaseDmacHandle");
	}

	/* UART解放 */
	result = AG903_UARTMgrReleaseHandle(hdl_uart);										/* ハンドル解放 */
	if(AG903_ENONE != result) {
		UART_ERROR("ReleaseUartHandle");
	}

	return;
}

/**
 * @brief		DMAループ送信処理
 * @param[in]	rs485en  RS485有効/無効 [true:有効]
 * @return		なし
 * @note		DMACの循環転送を使用したサンプルです。
 * @note		TimerのDMAリクエスト生成機能を使用したサンプルです。
 */
static void Uart_LoopSend_dma(_Bool rs485en)
{
	AG903_DMACMgrHandle*		hdl_dmac;
	AG903_UARTMgrHandle*		hdl_uart;
	AG903_TIMRMgrHandle*		hdl_timr;
	AG903_UARTMgrParam			com;
	AG903_UARTMgrRs485Param 	rs485;
	AG903_TIMRMgrTickCntParam 	tick;
    AG903_DMACMgrConfig     	config;
	AG903_DMACMgrDesc			desc[2];
	int32_t 	result;
	char		chara[4];
	int8_t		timsel;
	uint8_t		timch;

	UartDmaTerm=false;
	UartSendEnd=false;
	UartLoopCnt=0;

	if(true == rs485en) { /* RS485選択時 */
		PRINT(" Loop send any string. [RS485 Port]");
	}
	else {
		PRINT(" Loop send any string. [COM2 Port]");
	}

	while(1) { /* タイミング選択 */
		PRINT(" Select the transfer timing");
		PRINT(" 0 : no wait");
		PRINT(" 1 : 200ms wait / 1chara");
		PRINT(" 2 : 200ms wait / 4chara");
		PRINT(" 3 : 200ms wait / 8chara");
		EPRINT(" ");
		COM_GetNum_Wait(chara, 3); /* 3 = 1(Select No.)+CRLF */
		timsel = ASCtoBIN(chara[0]);
		if(3 < timsel) {
			PRINT(" Invalid number");
			continue;
		}
		break;
	}

	/* UART設定 */
	result = AG903_UARTMgrGetHandle(UART_SMP_CH, &hdl_uart); 							/* UARTハンドル取得 */
	if(AG903_ENONE != result) {
		UART_ERROR("GetUartHandle");
	}
	result = AG903_UARTMgrSetCallback(hdl_uart, (AG903_UARTMgrClbk)Uart_CallbackDma); 	/* UARTコールバック登録 */
	if(AG903_ENONE != result) {
		UART_ERROR("SetUartCallback");
	}
	com.baud	= UART_SMP_BAUDRATE;
	com.parity  = AG903_UART_PARITY_NON;
	com.stopbit = AG903_UART_STOPBIT_1;
	com.databit = AG903_UART_DATBIT_8;
	com.flow	= AG903_UART_FLOW_CTS;
	result = AG903_UARTMgrSetParam(hdl_uart, &com); 									/* UART通信パラメータ設定 */
	if(AG903_ENONE != result) {
		UART_ERROR("SetParam");
	}
	if(true == rs485en) { /* RS485選択時 */
		rs485.setuptime = 1;
		rs485.holdtime  = 1;
		rs485.rcvtime	= 10000;
		rs485.interval	= 10000;
		rs485.timeout	= 10000;
		rs485.event		= 0x00;
		result = AG903_UARTMgrSetRs485Param(hdl_uart, &rs485);							/* RS485パラメータ設定 */
		if(AG903_ENONE != result) {
			UART_ERROR("Set485Param");
		}
	}

	/* TIMR設定 */
	if(0 < timsel) {
		result = AG903_TIMRMgrGetHandle(&hdl_timr);
		if(AG903_ENONE != result) {
			UART_ERROR("GetTimrHandle");
		}
		result = AG903_TIMRMgrGetChannel(hdl_timr, &timch);
		if(AG903_ENONE != result) {
			UART_ERROR("GetTimrCH");
		}
		tick.period  = 40000000;  /* 200[ms] (clk 200M[Hz]時) */
		tick.match   = 0;
		tick.resolution = AG903_TIMR_CNT_SYSCLK;
		tick.oneshot = false;
		tick.output  = NULL;
		result = AG903_TIMRMgrSetTickCountMode(hdl_timr, &tick);
		if(AG903_ENONE != result) {
			UART_ERROR("SetTimr");
		}
		result = AG903_TIMRMgrEnableDmaRequest(hdl_timr, 0x01);
		if(AG903_ENONE != result) {
			UART_ERROR("EnableTimrDrq");
		}
	}

	/* DMAC設定 [Memory→UART] */
	result = AG903_DMACMgrGetHandle(UART_SMP_DMACH, &hdl_dmac);
	if(AG903_ENONE != result) {
		UART_ERROR("GetDmacHandle");
	}
	result = AG903_DMACMgrSetIntCallback(hdl_dmac, Uart_CallbackDmaTerm,
										Uart_CallbackDmaAbort, Uart_CallbackDmaErr);
	if(AG903_ENONE != result) {
		UART_ERROR("SetDmacCallback");
	}
	config.val = 0;
	config.st.DstHEn = 1;
	config.st.DstRS  = UART_SMP_DMACSEL;
	desc[0].Ctrl.val = 0;
	desc[0].Ctrl.st.DstCtrl = 2; /* Fixed */
	desc[0].SrcAddr  = (uint32_t)UartSampleStr1;
	desc[0].DstAddr  = (uint32_t)(&AG903_UARTn(UART_SMP_CH)->THR);
	desc[0].Trns.val = sizeof(UartSampleStr1);
	desc[0].Stride.val = 0;
	desc[0].next = (void*)&desc[1]; /* desc[1]へ */
	desc[1].Ctrl.val = 0;
	desc[1].Ctrl.st.DstCtrl = 2; /* Fixed */
	desc[1].SrcAddr  = (uint32_t)UartSampleStr2;
	desc[1].DstAddr  = (uint32_t)(&AG903_UARTn(UART_SMP_CH)->THR);
	desc[1].Trns.val = sizeof(UartSampleStr2);
	desc[1].Stride.val = 0;
	desc[1].next = (void*)&desc[0]; /* desc[0]へ */
	if(0 < timsel) {
		Sys_SetDmaInterface(UART_SMP_DMACSEL, (UART_SMP_DMASEL_TIMR+timch)); /* dma_req 選択(Timer) */
		AG903_DMACMgrSetSyncPeripheral(UART_SMP_DMACH, 1);
		desc[0].Ctrl.st.SrcTcnt = UartTimingParam[timsel];
		desc[1].Ctrl.st.SrcTcnt = UartTimingParam[timsel];
	}
	else {
		Sys_SetDmaInterface(UART_SMP_DMACSEL, (UART_SMP_DMASEL_BASE+(0x02*UART_SMP_CH)+1));
		AG903_DMACMgrSetSyncPeripheral(UART_SMP_DMACH, 1);
	}

	AG903_DMACMgrSetDescList(hdl_dmac, &config, desc, 2); /* ディスクリプタ設定 */

	/* 送信開始 */
	PRINT(" * Transfer Start");
	result = AG903_DMACMgrEnable(hdl_dmac);
	if(AG903_ENONE != result) {
		UART_ERROR("Enable");
	}
	result = AG903_UARTMgrSend(hdl_uart, NULL, 0, true); 								/* UART送信開始(割込み許可) */
	if(AG903_ENONE != result) {
		UART_ERROR("Send");
	}
	if(0 < timsel) {
		result = AG903_TIMRMgrStart(hdl_timr);
		if(AG903_ENONE != result) {
			UART_ERROR("Timer Start");
		}
	}

	/* 完了待ち */
	result = Uart_WaitDmaLoop(hdl_dmac, 100000);
	if(AG903_ENONE != result) {
		UART_ERROR("WaitDmaLoop");
	}
	else {
		PRINT(" * Transfer End");
	}

	/* UART解放 */
	result = AG903_UARTMgrStopSend(hdl_uart); 											/* 送信停止 */
	if(AG903_ENONE != result) {
		UART_ERROR("StopSend");
	}
	result = AG903_UARTMgrReleaseHandle(hdl_uart);										/* ハンドル解放 */
	if(AG903_ENONE != result) {
		UART_ERROR("ReleaseUartHandle");
	}

	/* DMAC解放 */
	result = AG903_DMACMgrReleaseHandle(hdl_dmac);
	if(AG903_ENONE != result) {
		UART_ERROR("ReleaseDmacHandle");
	}

	/* TIMR解放 */
	if(0 < timsel) {
		result = AG903_TIMRMgrStop(hdl_timr);
		if(AG903_ENONE != result) {
			UART_ERROR("Stop");
		}
		result = AG903_TIMRMgrReleaseHandle(hdl_timr);
		if(AG903_ENONE != result) {
			UART_ERROR("ReleaseHandle");
		}
	}

	return;
}

/**
 * @brief		HW設定
 * @param		ch [in] UARTチャンネル
 * @param		initype [in] 設定種別
 * @return		なし
 * @note		UART3の場合は131pin-134pinを使用します。
 */
static void Uart_InitHw(uint8_t ch, uint8_t initype)
{
	/* 端子設定はhw_init()で実施済み */

	if(3 == ch) {
		ch++;		/* UART3の場合は131pin-134pinを使用 [DB51903M] */
	}

	switch(initype) {
		case UART_SMP_HW_NORMAL:
			Board_SelectUartConnection(ch, AG903_UART_CONNECT_COM2);	/* COM2選択 */
			break;
		case UART_SMP_HW_RS485:
			Board_SelectUartConnection(ch, AG903_UART_CONNECT_RS485);	/* RS485選択 */
		default:
			/* 処理なし */
			break;
	}

	return;
}

/**
 * @brief		送信完了待ち
 * @param[in]	timout	タイムアウト[ms]
 * @return		なし
 * @note		なし
 */
static int32_t Uart_WaitSend(uint32_t timout)
{
	int32_t		retval = AG903_ENONE;
	uint32_t	cnt;
	uint32_t	loop;

	cnt = timout/10;
	if(timout%10) {
		cnt++;
	}
	for(loop=0; loop<cnt; loop++) {
		if(true == UartSendEnd) {
			UartSendEnd = false;
			break;
		}
		sys_dlytsk(10);
	}
	if(cnt<=loop) {
		retval = -AG903_ETIMEDOUT;
	}

	return retval;
}

/**
 * @brief		DMA完了待ち
 * @param[in]	timout	タイムアウト[ms]
 * @return		なし
 * @note		なし
 */
static int32_t Uart_WaitDmaTerm(uint32_t timout)
{
	int32_t		retval = AG903_ENONE;
	uint32_t	cnt;
	uint32_t	loop;

	cnt = timout/10;
	if(timout%10) {
		cnt++;
	}
	for(loop=0; loop<cnt; loop++) {
		if(true == UartDmaTerm) {
			UartDmaTerm = false;
			break;
		}
		sys_dlytsk(10);
	}
	if(cnt<=loop) {
		retval = -AG903_ETIMEDOUT;
	}

	return retval;
}

/**
 * @brief		DMA循環参照完了待ち
 * @param[in]	handle	DMACハンドル
 * @param[in]	timout	タイムアウト[ms]
 * @return		なし
 * @note		なし
 */

static int32_t Uart_WaitDmaLoop(AG903_DMACMgrHandle* handle, uint32_t timout)
{
	AG903_DMACMgrStatus  status;
	int32_t		retval = AG903_ENONE;
	uint32_t	cnt;
	uint32_t	loop;

	cnt = timout/10;
	if(timout%10) {
		cnt++;
	}
	for(loop=0; loop<cnt; loop++) {
		AG903_DMACMgrGetStatus(handle, &status);
		if(true != status.enable) {
			break;
		}
		sys_dlytsk(10);
	}
	if(cnt<=loop) {
		retval = -AG903_ETIMEDOUT;
	}

	return retval;
}

/**
 * @brief	コールバック (PIO転送).
 * @param[in]	handle  UARTハンドル.
 * @param[in]	event	コールバックイベント.
 * @return	なし.
 * @note	なし.
 */
static void Uart_CallbackPio(AG903_UARTMgrHandle* handle, uint32_t event)
{
	if(AG903_UART_EVENT_SNDEND & event) {
		UartSendEnd = true;
	}

	if((AG903_UART_EVENT_DATARDY|AG903_UART_EVENT_RCVTIMEOUT) & event) {
		UartRcvSize = AG903_UARTMgrGetReceiveData(handle, UartBuf, UART_SMP_BUFSIZE);
		Uart_SFifoWrite(UartBuf, UartRcvSize);
	}

	if((AG903_UART_EVENT_OVERRUN|AG903_UART_EVENT_PARITYERR|AG903_UART_EVENT_FRAMINGERR|
		AG903_UART_EVENT_FIFOERR) & event) {
		/* 処理なし */
	}

	return;
}

/**
 * @brief	コールバック (DMA転送).
 * @param[in]	handle  UARTハンドル.
 * @param[in]	event	コールバックイベント.
 * @return	なし.
 * @note	なし.
 */
static void Uart_CallbackDma(AG903_UARTMgrHandle* handle, uint32_t event)
{
	((void)handle);

	if(AG903_UART_EVENT_SNDEMPTY & event) {
		UartSendEnd = true;
	}

	if((AG903_UART_EVENT_DATARDY|AG903_UART_EVENT_RCVTIMEOUT) & event) {
		/* 処理なし */
	}

	if((AG903_UART_EVENT_OVERRUN|AG903_UART_EVENT_PARITYERR|AG903_UART_EVENT_FRAMINGERR|
		AG903_UART_EVENT_FIFOERR) & event) {
		/* 処理なし */
	}

	return;
}

/**
 * @brief		転送終了割込み
 * @param[in]	handle	ハンドル
 * @param[out]	desc	ディスクリプタ格納先
 * @param[out]	end		循環終了フラグ
 * @return		なし
 * @note		なし
 */
static void Uart_CallbackDmaTerm(AG903_DMACMgrHandle* handle, AG903_DMACMgrDesc** desc, uint8_t* end)
{
	((void)handle);

	if(NULL == desc) {
		UartDmaTerm = true;
	}
	else {
		(*desc) = NULL;
		if((UART_SMP_LOOP_NUM-2) <= ++UartLoopCnt) {
			(*end) = true;
		}
	}

	return;
}

/**
 * @brief		アボート割込み
 * @param[in]	handle	ハンドル
 * @return		なし
 * @note		なし
 */
static void Uart_CallbackDmaAbort(AG903_DMACMgrHandle* handle)
{
	((void)handle);
	return;
}

/**
 * @brief		エラー割込み
 * @param[in]	handle	ハンドル
 * @return		なし
 * @note		なし
 */
static void Uart_CallbackDmaErr(AG903_DMACMgrHandle* handle)
{
	((void)handle);
	return;
}


static void Uart_SFifoInit(void)
{
	struct uart_sfifo *self = &UartSFifo;
	self->iw = 0;
	self->ir = 0;
}

static int Uart_SFifoIsEmpty(void)
{
	struct uart_sfifo *self = &UartSFifo;

	int iw = self->iw;
	int ir = self->ir;
	return (iw == ir) ? 1 : 0;
}

static int Uart_SFifoIsFull(void)
{
	struct uart_sfifo *self = &UartSFifo;

	int ir = self->ir;
	int iw = self->iw;
	return ((iw + 1)%UART_SMP_SFIFOSIZE == ir) ? 1 : 0;
}


static int Uart_SFifoWrite(const uint8_t *dat, int size)
{
	struct uart_sfifo *self = &UartSFifo;
	int ii;

	for (ii = 0; ii < size; ii++) {
		if (!Uart_SFifoIsFull()) {
			self->buf[self->iw] = dat[ii];
			self->iw = (self->iw + 1) % UART_SMP_SFIFOSIZE;
		} else {
			break;
		}
	}

	return ii;
}

static int Uart_SFifoRead(uint8_t *dat, int size)
{
	struct uart_sfifo *self = &UartSFifo;
	int ii;

	for (ii = 0; ii < size; ii++) {
		if (!Uart_SFifoIsEmpty()) {
			dat[ii] = self->buf[self->ir];
			self->ir = (self->ir + 1) % UART_SMP_SFIFOSIZE;
		} else {
			break;
		}
	}

	return ii;
}
