/**
 * @brief       UART Manager
 * @author      AXELL CORPORATION
 * @description UART Manager Layer
 * @note        none
 * @history     2017_02_22  初版
 * @history     2017_10_26  Ver2.0
*/
/* DOM-IGNORE-BEGIN */
/*
 * This program was created by AXELL CORPORATION.
 * Copyright (C) 2017-2019 AXELL CORPORATION, all rights reserved.
 */
/* DOM-IGNORE-END */

#include "AG903_errno.h"
#include "AG903_intno.h"
#include "uart/uartmgr.h"
#include "uart/uartprm.h"
#include "int/intmgr.h"

typedef void (*AG903_UARTMgrIntHdr)(void);	/** コールバック関数型 */

typedef struct _AG903_UARTMgrSndStat{
	uint32_t	stat;		/** 状態 */
	uint8_t*	buf;		/** 送信バッファ */
	uint32_t	size;		/** 送信サイズ */
	uint32_t	cnt;		/** 送信カウンタ */
	uint8_t		dma;		/** DMA有無 */
	uint8_t		reserve[3];	/** 予約 */
} AG903_UARTMgrSndStat;

typedef struct _AG903_UARTMgrRcvStat{
	uint32_t	stat;		/** 状態 */
	uint8_t		dma;		/** DMA有無 */
	uint8_t		reserve[3];	/** 予約 */
} AG903_UARTMgrRcvStat;

typedef struct _AG903_UARTMgrChStat{
	AG903_UARTMgrSndStat snd;	/** 送信状態 */
	AG903_UARTMgrRcvStat rcv;	/** 受信状態 */
	uint32_t	hdlnum;			/** ハンドル番号 */
	int32_t		hdrid;			/** ハンドラID */
	uint8_t		rs485;			/** RS485 ON/OFF */
	uint8_t		reserve[3];		/** 予約 */
} AG903_UARTMgrChStat;

typedef struct _AG903_UARTMgrHandleStat{
	AG903_UARTMgrClbk	clbk;	/** コールバック */
	uint32_t	event;			/** 通知イベント */
	uint8_t		lock;			/** ロック */
	uint8_t		reserve[3];		/** 予約 */
} AG903_UARTMgrHandleStat;

enum _AG903_UartStatusNum{
	AG903_UART_STAT_IDLE = 0,
	AG903_UART_STAT_SEND,
	AG903_UART_STAT_RECEIVE,
};

static AG903_UARTMgrChStat		UartChStat[AG903_UART_CH_NUM];		/** ch状態 */
static AG903_UARTMgrHandleStat	UartHandleStat[AG903_UART_CH_NUM];	/** handle状態 */
static uint8_t	UartSendBuf[AG903_UART_CH_NUM][AG903_UART_BUFSIZE];		/** 送信バッファ */

static void UARTMgr_InitState(uint8_t ch);
static int32_t UARTMgr_CheckHandle(AG903_UARTMgrHandle* handle, uint8_t* ch);
static int32_t UARTMgr_SetParam(uint8_t ch, AG903_UARTMgrParam* param);
static int32_t UARTMgr_SetBaudrate(uint8_t ch, uint32_t baud);
static int32_t UARTMgr_SetForm(uint8_t ch, uint8_t parity, uint8_t stopbit, uint8_t databit);
static int32_t UARTMgr_SetFifo(uint8_t ch, uint8_t rx_trgl, uint8_t tx_trgl, _Bool enable);
static int32_t UARTMgr_SetFlow(uint8_t ch, uint8_t flow);
static void UARTMgr_Inthdr0(void);
static void UARTMgr_Inthdr1(void);
static void UARTMgr_Inthdr2(void);
static void UARTMgr_Inthdr3(void);
static void UARTMgr_IntProcess(uint8_t ch);
static int32_t UARTMgr_IntSend(uint8_t ch, uint8_t inttype, uint32_t* event);
static int32_t UARTMgr_IntReceive(uint8_t ch, uint8_t inttype, uint32_t* event);
static int32_t UARTMgr_IntLineStatus(uint8_t ch, uint32_t* event);
static int32_t UARTMgr_IntRs485Status(uint8_t ch, uint32_t* event);

static const AG903_UARTMgrIntHdr UartIntHdr[AG903_UART_CH_NUM] =
{ UARTMgr_Inthdr0, UARTMgr_Inthdr1, UARTMgr_Inthdr2, UARTMgr_Inthdr3 };


/**
 * @brief           UARTManager初期化
 * @param           ch [in] UARTチャネル番号（0〜3）
 * @return          初期化結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @retval          -AG903_EFAULT  処理失敗 (割込みハンドラ登録失敗).
 * @description     内部状態の初期化と通信パラメータの設定をします。システム起動時にCALLして下さい。<p>
 *                  通信パラメータは以下に従って設定されます。<p>
 *                  AG903_UART_DFLT_BAUD , AG903_UART_DFLT_PARITY , AG903_UART_DFLT_STOPBIT , AG903_UART_DFLT_DATBIT , AG903_UART_DFLT_FLOW
*/
int32_t	AG903_UARTMgrInit(uint8_t ch)
{
	AG903_INTMgrHdrPrm inthdr;
	AG903_UARTMgrParam param;
	int32_t	 retval = AG903_ENONE;
	int32_t	 hdrid;
	
	if(AG903_UART_CH_NUM <= ch) {
		return -AG903_EINVAL;
	}
	
	UARTMgr_InitState(ch);  /* 内部状態初期化 */
	
	if(0 >= UartChStat[ch].hdrid) {
		inthdr.atr   = AG903_INT_HLNG;
		inthdr.intno = AG903_IRQ8_UART0+ch;
		inthdr.func  = (void*)UartIntHdr[ch];
		hdrid = AG903_INTMgrSetHandler(&inthdr);
		if(0 >= hdrid) {
			return -AG903_EFAULT;
		}
		UartChStat[ch].hdrid = hdrid;
	}
	
	AG903_INTMgrEnableInt(AG903_IRQ8_UART0+ch);
	
	param.baud    = AG903_UART_DFLT_BAUD;
	param.parity  = AG903_UART_DFLT_PARITY;
	param.stopbit = AG903_UART_DFLT_STOPBIT;
	param.databit = AG903_UART_DFLT_DATBIT;
	param.flow	  = AG903_UART_DFLT_FLOW;
	retval = UARTMgr_SetParam(ch, &param);	/* 初期設定 */
	
	return retval;
}

/**
 * @brief           UARTハンドル取得
 * @param           ch [in] UARTチャネル番号（0〜3）
 * @param           handle [out] 該当のUARTハンドル
 * @return          ハンドル取得結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @retval          -AG903_EBUSY   使用できるハンドルが不足.
 * @description     指定したCHのハンドルを取得します。
*/
int32_t	AG903_UARTMgrGetHandle(uint8_t ch, AG903_UARTMgrHandle** handle)
{
	int32_t	 retval = AG903_ENONE;

	if( (AG903_UART_CH_NUM <= ch) ||
		(NULL == handle) ) {
		return -AG903_EINVAL;
	}
	if(true == UartHandleStat[ch].lock) {
		return -AG903_EBUSY;
	}
	
	UARTMgr_InitState(ch);	/* 状態初期化 */
	
	UartHandleStat[ch].lock = true;
	
	(*handle) = (AG903_UARTMgrHandle*)&UartHandleStat[ch];
	
	return retval;
}

/**
 * @brief           UARTハンドル解放
 * @param           handle [in] UARTハンドル
 * @return          ハンドル解放結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @retval          -AG903_EBUSY   ハンドル使用中.
 * @description     ハンドルを解放します。<p>動作中にハンドルが解放された場合はエラーを返します。
 * @note            必要に応じアプリでAG903_INTMgrDisableIntによりUARTの割り込みを無効にして下さい。
*/
int32_t	AG903_UARTMgrReleaseHandle(AG903_UARTMgrHandle* handle)
{
	int32_t	 retval = AG903_ENONE;
	int32_t	 result;
	uint8_t	 ch;
	
	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	if( (AG903_UART_STAT_IDLE != UartChStat[ch].snd.stat) ||
		(AG903_UART_STAT_IDLE != UartChStat[ch].rcv.stat) ) {
		return -AG903_EBUSY;
	}
	
	UartHandleStat[ch].lock = false;
	
	return retval;
}

/**
 * @brief           コールバック登録
 * @param           handle [in] UARTハンドル
 * @param           clbk [in] コールバック関数ポインタ
 * @return          コールバック登録結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @description     コールバック関数を登録します。
*/
int32_t	AG903_UARTMgrSetCallback(AG903_UARTMgrHandle* handle, AG903_UARTMgrClbk clbk)
{
	int32_t	 retval = AG903_ENONE;
	int32_t	 result;
	uint8_t	 ch;
	
	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	
	UartHandleStat[ch].clbk = clbk;

	return retval;
}

/**
 * @brief           通信パラメータ設定
 * @param           handle [in] UARTハンドル
 * @param           param [in] パラメータ
 * @return          通信パラメータ設定結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @retval          -AG903_EBUSY   ハンドル使用中.
 * @description     通信パラメータを設定します。
*/
int32_t AG903_UARTMgrSetParam(AG903_UARTMgrHandle*handle, AG903_UARTMgrParam* param)
{
	int32_t	 retval = AG903_ENONE;
	int32_t	 result;
	uint8_t	 ch;
	
	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	if(NULL == param) {
		return -AG903_EINVAL;
	}
	if( (AG903_UART_STAT_IDLE != UartChStat[ch].snd.stat) ||
		(AG903_UART_STAT_IDLE != UartChStat[ch].rcv.stat) ) {
		return -AG903_EBUSY;
	}

	retval = UARTMgr_SetParam(ch, param);

	return retval;
}

/**
 * @brief           RS485パラメータ設定
 * @param           handle [in] UARTハンドル
 * @param           param [in] パラメータ
 * @return          RS485パラメータ設定結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @retval          -AG903_EBUSY   ハンドル使用中.
 * @description     RS485パラメータの設定<p>
 *                  本関数の使用でRS485通信が有効になります。
*/
int32_t AG903_UARTMgrSetRs485Param(AG903_UARTMgrHandle*handle, AG903_UARTMgrRs485Param *param)
{
	int32_t	 retval = AG903_ENONE;
	int32_t	 result;
	uint8_t	 ch;
	
	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	if(NULL == param) {
		return -AG903_EINVAL;
	}
	if( (AG903_UART_STAT_IDLE != UartChStat[ch].snd.stat) ||
		(AG903_UART_STAT_IDLE != UartChStat[ch].rcv.stat) ) {
		return -AG903_EBUSY;
	}

	AG903_UARTPrmSetSetuptime(ch, param->setuptime);
	AG903_UARTPrmSetHoldtime(ch, param->holdtime);

	if(param->event & (AG903_UART_RCVTIMEOUT_BIT|AG903_UART_CHARATIMEOUT_BIT)) { /* タイムアウト検知有り */
		AG903_UARTPrmDisableTimeoutDetect(ch);	/* 一旦停止 */
		AG903_UARTPrmEnableTimeoutIntMask(ch, (AG903_UART_DETECT_RTO_BIT|AG903_UART_DETECT_CTO_BIT));
		
		AG903_UARTPrmEnableTimeoutIntMask(ch, AG903_UART_DETECT_ALL_BIT);
		AG903_UARTPrmClerTimeoutStatus(ch, AG903_UART_DETECT_ALL_BIT);
		
		AG903_UARTPrmSetReceivetime(ch, param->rcvtime);
		AG903_UARTPrmSetCharainterval(ch, param->interval);
		AG903_UARTPrmSetTimeout(ch, param->timeout);
	}

	AG903_UARTPrmSetAutoMode(ch, true, true);
	AG903_UARTPrmEnableRS485(ch);	/* RS485制御 有効 */

	UartHandleStat[ch].event = param->event;
	UartChStat[ch].rs485 = true;

	return retval;
}

/**
 * @brief           データ送信開始
 * @param           handle [in] UARTハンドル
 * @param           buf [in] 送信データ先頭アドレス
 * @param           size [in] 送信データサイズ
 * @param           dma [in] DMAの使用有無
 * @return          データ送信結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @retval          -AG903_EBUSY   ハンドル使用中.
 * @retval          -AG903_ENOBUFS バッファ不足.
 * @description     データ送信開始の設定をします。<p>
 *                  DMA未使用時は指定サイズ分のデータ送信完了でコールバックします。<p>
 *                  DMA使用時は送信FIFO空でコールバックします。<p>
 *                  DMA使用時はbuf,sizeの内容は無視されます。
 * @note            DMAを使用する場合は別途DMACの設定を行って下さい。
*/
int32_t AG903_UARTMgrSend(AG903_UARTMgrHandle* handle, uint8_t* buf, uint32_t size, _Bool dma)
{
	int32_t	retval = AG903_ENONE;
	int32_t	result;
	uint32_t sndsz;
	uint32_t loop;
	uint8_t	 ch;

	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	if(false == dma) {
		if((NULL == buf) || (0 >= size)) {
			return -AG903_EINVAL;
		}
		if(AG903_UART_BUFSIZE < size) {
			return -AG903_ENOBUFS;
		}
	}
	if(AG903_UART_STAT_IDLE != UartChStat[ch].snd.stat){
		/* 送信中 */
		return -AG903_EBUSY;
	}

	UartChStat[ch].snd.dma  = dma;
	UartChStat[ch].snd.stat = AG903_UART_STAT_SEND;
	if(true == dma) {
		AG903_UARTPrmEnableInt(ch, AG903_UART_IER_THREMP_BIT);	/* 割込み許可 (THR Empty割込発生) */
	}
	else  {
		UartChStat[ch].snd.buf  = &UartSendBuf[ch][0];
		UartChStat[ch].snd.size = size;
		for(loop=0; loop<UartChStat[ch].snd.size; loop++) {
			*(UartChStat[ch].snd.buf+loop) = *(buf+loop);
		}
		if(AG903_UART_FIFO_SIZE <= size) {
			sndsz = AG903_UART_FIFO_SIZE;
		}
		else {
			sndsz = size;
		}
		UartChStat[ch].snd.cnt  = sndsz;
		AG903_UARTPrmSendData(ch, buf, sndsz);
		AG903_UARTPrmEnableInt(ch, AG903_UART_IER_THREMP_BIT);	/* 割込み許可 */
	}
	
	
	return retval;
}

/**
 * @brief           データ受信開始
 * @param           handle [in] UARTハンドル
 * @param           dma [in] DMAの使用有無
 * @return          データ受信結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @retval          -AG903_EBUSY   ハンドル使用中.
 * @description     データ受信開始の設定をします。<p>
 *                  DMA未使用はデータ受信でコールバックします<p>
 *                  DMA使用はエラー発生でコールバックします。
 * @note            DMAを使用する場合は別途DMACの設定を行って下さい。
*/
int32_t AG903_UARTMgrReceive(AG903_UARTMgrHandle* handle, _Bool dma)
{
	int32_t	 retval = AG903_ENONE;
	int32_t	 result;
	uint32_t dismsk = 0;
	uint8_t	 ch;

	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}

	if( (AG903_UART_STAT_IDLE != UartChStat[ch].rcv.stat) ||
		((true == UartChStat[ch].rs485) && (AG903_UART_STAT_IDLE != UartChStat[ch].snd.stat)) ){
		/* 受信中 or RS485送信中 */
		return -AG903_EBUSY;
	}

	UartChStat[ch].rcv.dma = dma;
	UartChStat[ch].rcv.stat = AG903_UART_STAT_RECEIVE;
	
	if(UartHandleStat[ch].event & AG903_UART_RCVTIMEOUT_BIT) {
		dismsk |= AG903_UART_DETECT_RTO_BIT;
	}
	if(UartHandleStat[ch].event & AG903_UART_CHARATIMEOUT_BIT) {
		dismsk |= AG903_UART_DETECT_CTO_BIT;
	}
	if(0 != dismsk) {
		AG903_UARTPrmDisableTimeoutIntMask(ch, dismsk);	/* マスク解除 */
		AG903_UARTPrmEnableTimeoutDetect(ch);			/* T.O.検知 有効 */
	}
	
	AG903_UARTPrmEnableInt(ch, (AG903_UART_IER_LINEST_BIT|AG903_UART_IER_DATARDY_BIT));	/* 割込み許可 */


	return retval;
}

/**
 * @brief           受信データ取得
 * @param           handle [in] UARTハンドル
 * @param           buf [out] 受信データ格納アドレス
 * @param           size [in] 受信データサイズ
 * @return          受信データ取得結果
 * @retval          収得サイズ
 * @retval          -AG903_EINVAL  引数異常
 * @description     受信データを取得します。<p>
 *                  受信データがない場合は0を返します。
*/
int32_t AG903_UARTMgrGetReceiveData(AG903_UARTMgrHandle* handle, uint8_t* buf, uint32_t size)
{
	int32_t	result;
	int32_t cnt;
	uint8_t	ch;
	uint8_t loop;
	uint8_t stat;

	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	if( (NULL == buf) || (0 >= size) ){
		return -AG903_EINVAL;
	}

	cnt = 0;
	for(loop=0; loop<AG903_UART_FIFO_SIZE; loop++) {
		AG903_UARTPrmGetLineStatus(ch, &stat);
		if(0 == (AG903_UART_LSR_DATARDY_BIT&stat)) {
			break;
		}
		AG903_UARTPrmGetReceiveData(ch, buf);
		buf++;
		cnt++;
		if(size <= (uint32_t)cnt) {
			break;
		}
	}

	return cnt;
}

/**
 * @brief           データ送信停止
 * @param           handle [in] UARTハンドル
 * @return          データ送信停止結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @description     送信処理を停止します。（コールバック通知が止まります。）
*/
int32_t AG903_UARTMgrStopSend(AG903_UARTMgrHandle* handle)
{
	int32_t	retval = AG903_ENONE;
	int32_t	result;
	uint8_t	 ch;

	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	
	AG903_UARTPrmDisableInt(ch, AG903_UART_IER_THREMP_BIT);
	UartChStat[ch].snd.stat = AG903_UART_STAT_IDLE;

	return retval;
}

/**
 * @brief           データ受信停止
 * @param           handle [in] UARTハンドル
 * @return          データ受信停止結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @description     受信処理を停止します。（コールバック通知が止まります。）
*/
int32_t AG903_UARTMgrStopReceive(AG903_UARTMgrHandle* handle)
{
	int32_t	retval = AG903_ENONE;
	int32_t	result;
	uint8_t	 ch;

	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	
	AG903_UARTPrmDisableInt(ch, (AG903_UART_IER_LINEST_BIT|AG903_UART_IER_DATARDY_BIT));
	AG903_UARTPrmEnableTimeoutIntMask(ch, AG903_UART_DETECT_ALL_BIT);
	UartChStat[ch].rcv.stat = AG903_UART_STAT_IDLE;

	return retval;
}

/**
 * @brief           FIFOリセット
 * @param           handle [in] UARTハンドル
 * @param           rstbit [in] リセットFIFO指定
 * @return          FIFOリセット結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @description     FIFOをリセットします
*/
int32_t AG903_UARTMgrResetFifo(AG903_UARTMgrHandle* handle, uint8_t rstbit)
{
	int32_t	retval = AG903_ENONE;
	int32_t	result;
	uint8_t	fifo = 0;
	uint8_t	ch;

	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	
	if(AG903_UART_RESET_RXFIFO&rstbit) {
		fifo |= AG903_UART_RXFIFO_BIT;
	}
	if(AG903_UART_RESET_TXFIFO&rstbit) {
		fifo |= AG903_UART_TXFIFO_BIT;
	}
	
	if(0 != fifo) {
		AG903_UARTPrmResetFifo(ch, fifo);
	}
	
	return retval;
}

/**
 * @brief           Breakの設定
 * @param           handle [in] UARTハンドル
 * @param           enable [in] 出力/非出力
 * @return          Breakの設定結果
 * @retval          AG903_ENONE    正常終了
 * @retval          -AG903_EINVAL  引数異常
 * @description     Breakの設定をします。
 * @note            Break中も送信ロジックは動作し続けます。
*/
int32_t AG903_UARTMgrSetBreak(AG903_UARTMgrHandle* handle, _Bool enable)
{
	int32_t	retval = AG903_ENONE;
	int32_t	result;
	uint8_t	 ch;
	
	result = UARTMgr_CheckHandle(handle, &ch);
	if(AG903_ENONE != result) {
		return -AG903_EINVAL;
	}
	
	AG903_UARTPrmSetBreak(ch, enable);
	
	return retval;
}

/*
	状態初期化
	ch：UARTチャネル番号
*/
static void UARTMgr_InitState(uint8_t ch)
{
	if(AG903_UART_CH_NUM <= ch) {
		return;
	}

	UartHandleStat[ch].clbk = NULL;
	UartHandleStat[ch].event = 0;
	UartHandleStat[ch].lock  = false;
	
	UartChStat[ch].snd.stat = AG903_UART_STAT_IDLE;
	UartChStat[ch].snd.buf  = NULL;
	UartChStat[ch].snd.size = 0;
	UartChStat[ch].snd.cnt	= 0;
	UartChStat[ch].snd.dma  = false;
	UartChStat[ch].rcv.stat = AG903_UART_STAT_IDLE;
	UartChStat[ch].rcv.dma  = false;
	UartChStat[ch].rs485  = false;
	UartChStat[ch].hdlnum = 0;

	AG903_UARTPrmDisableRS485(ch);	/* RS485 Disable */

	return;
}

/*
	ハンドルチェック.
	handle：UARTハンドル.
	ch：UARTチャネル番号.
*/
static int32_t UARTMgr_CheckHandle(AG903_UARTMgrHandle* handle, uint8_t* ch)
{
	uint32_t get_ch;
	
	get_ch = ((uint32_t)handle - (uint32_t)UartHandleStat) / sizeof(AG903_UARTMgrHandleStat);
	
	if( (AG903_UART_CH_NUM <= get_ch) ||
		(&UartHandleStat[get_ch] != (AG903_UARTMgrHandleStat*)handle) ) {
		return -AG903_EINVAL;
	}
	(*ch) = (uint8_t)get_ch;
	
	return AG903_ENONE;
}

/*
	通信パラメータ設定（ch指定）.
	ch：UARTチャネル番号.
	param：パラメータ
*/
static int32_t	UARTMgr_SetParam(uint8_t ch, AG903_UARTMgrParam* param)
{
	int32_t	 retval = AG903_ENONE;

	if( (AG903_UART_CH_NUM <= ch) ||
		(NULL == param) ){
		return -AG903_EINVAL;
	}
	
	do {
		retval = UARTMgr_SetBaudrate(ch, param->baud);
		if(AG903_ENONE != retval) {
			break;
		}
		
		retval = UARTMgr_SetForm(ch, param->parity, param->stopbit, param->databit);
		if(AG903_ENONE != retval) {
			break;
		}
		
		retval = UARTMgr_SetFifo(ch, AG903_UART_RXTRGL_1, AG903_UART_TXTRGL_3, true);
		if(AG903_ENONE != retval) {
			break;
		}
		
		retval = UARTMgr_SetFlow(ch, param->flow);
		if(AG903_ENONE != retval) {
			break;
		}
		
		AG903_UARTPrmSetDmaMode(ch, AG903_UART_DMA_MODE0); /* DMA Mode0 */
		
	} while(0);
	
	return retval;
}

/*
	ボー・レート設定.
	ch：UARTチャネル.
	baud：ボー・レート.
*/
static int32_t UARTMgr_SetBaudrate(uint8_t ch, uint32_t baud)
{
	uint32_t limit;
	uint32_t div;
	uint8_t	 pscale;

	if(AG903_UART_CH_NUM <= ch) {
		return -AG903_EINVAL;
	}
	limit = (AG903_UART_CLK >> 4);
	if(limit < baud) {
		return -AG903_EINVAL;
	}
	
	if(115200 <= baud) {	/* 115200bps以上でPSR設定値を変更する */
		pscale = 1;
	}
	else {
		pscale = 4;
	}
	div = (AG903_UART_CLK/(pscale*baud*16));
	if(div & 0xFFFF0000) {
		return -AG903_EINVAL;
	}
	AG903_UARTPrmSetDivisor(ch, pscale, (uint16_t)div);

	return AG903_ENONE;
}

/*
	フォーマット設定.
	ch：UARTチャネル.
	parity：パリティ種別.
	stopbit：ストップビット数
	databit：データビット数
*/
static int32_t UARTMgr_SetForm(uint8_t ch, uint8_t parity, uint8_t stopbit, uint8_t databit)
{
	uint8_t	parity_type;
	uint8_t	length_type;

	if(AG903_UART_CH_NUM <= ch) {
		return -AG903_EINVAL;
	}

	if(AG903_UART_PARITY_NON == parity) {
		parity_type = AG903_UART_PARITY_TYPE_NON;
	}
	else if(AG903_UART_PARITY_EVEN == parity) {
		parity_type = AG903_UART_PARITY_TYPE_EVEN;
	}
	else if(AG903_UART_PARITY_ODD == parity) {
		parity_type = AG903_UART_PARITY_TYPE_ODD;
	}
	else {
		return -AG903_EINVAL;
	}
	
	if((AG903_UART_STOPBIT_1 == stopbit) && (AG903_UART_DATBIT_5 == databit)) {
		length_type = AG903_UART_WORDLEN5_STOP1;
	}
	else if((AG903_UART_STOPBIT_1 == stopbit) && (AG903_UART_DATBIT_6 == databit)) {
		length_type = AG903_UART_WORDLEN6_STOP1;
	}
	else if((AG903_UART_STOPBIT_1 == stopbit) && (AG903_UART_DATBIT_7 == databit)) {
		length_type = AG903_UART_WORDLEN7_STOP1;
	}
	else if((AG903_UART_STOPBIT_1 == stopbit) && (AG903_UART_DATBIT_8 == databit)) {
		length_type = AG903_UART_WORDLEN8_STOP1;
	}
	else if((AG903_UART_STOPBIT_1_5 == stopbit) && (AG903_UART_DATBIT_5 == databit)) {
		length_type = AG903_UART_WORDLEN5_STOP15;
	}
	else if((AG903_UART_STOPBIT_2 == stopbit) && (AG903_UART_DATBIT_6 == databit)) {
		length_type = AG903_UART_WORDLEN6_STOP2;
	}
	else if((AG903_UART_STOPBIT_2 == stopbit) && (AG903_UART_DATBIT_7 == databit)) {
		length_type = AG903_UART_WORDLEN7_STOP2;
	}
	else if((AG903_UART_STOPBIT_2 == stopbit) && (AG903_UART_DATBIT_8 == databit)) {
		length_type = AG903_UART_WORDLEN8_STOP2;
	}
	else {
		return -AG903_EINVAL;
	}

	AG903_UARTPrmSetWordLength(ch, parity_type, length_type);
	
	return AG903_ENONE;
}

/*
	FIFO制御設定.
	ch：UARTチャネル.
	rx_trgl：受信FIFOトリガレベル.
	tx_trgl：送信FIFOトリガレベル.
	enable：FIFO有効/無効.
*/
static int32_t UARTMgr_SetFifo(uint8_t ch, uint8_t rx_trgl, uint8_t tx_trgl, _Bool enable)
{

	if(AG903_UART_CH_NUM <= ch) {
		return -AG903_EINVAL;
	}

	AG903_UARTPrmDisableFifo(ch);

	if(true == enable) {
		AG903_UARTPrmSetFifoTrigger(ch, rx_trgl, tx_trgl);
		AG903_UARTPrmEnableFifo(ch);
	}

	return AG903_ENONE;
}

/*
	フロー制御設定.
	ch：UARTチャネル.
	flow：フロー種別.
*/
static int32_t UARTMgr_SetFlow(uint8_t ch, uint8_t flow)
{
	if(AG903_UART_CH_NUM <= ch) {
		return -AG903_EINVAL;
	}
	if((AG903_UART_FLOW_CTS != flow) && (AG903_UART_FLOW_NON != flow)) {
		return -AG903_EINVAL;
	}

	AG903_UARTPrmDisableFlowControl(ch, AG903_UART_FLOW_ALL_BIT);
	
	if(flow == AG903_UART_FLOW_CTS) {
		AG903_UARTPrmEnableFlowControl(ch, (AG903_UART_FLOW_RTS_BIT|AG903_UART_FLOW_CTS_BIT));
	}
	
	return AG903_ENONE;
}

/*
	割込みハンドラ(CH0).
*/
static void UARTMgr_Inthdr0(void)
{
	UARTMgr_IntProcess(0);	/* CH0 */
	return;
}

/*
	割込みハンドラ(CH1).
*/
static void UARTMgr_Inthdr1(void)
{
	UARTMgr_IntProcess(1);	/* CH1 */
	return;
}

/*
	割込みハンドラ(CH2).
*/
static void UARTMgr_Inthdr2(void)
{
	UARTMgr_IntProcess(2);	/* CH2 */
	return;
}

/*
	割込みハンドラ(CH3).
*/
static void UARTMgr_Inthdr3(void)
{
	UARTMgr_IntProcess(3);	/* CH3 */
	return;
}

/*
	割込み処理.
	ch：UARTチャネル.
*/
static void UARTMgr_IntProcess(uint8_t ch)
{
	int32_t result = AG903_ENONE;
	uint32_t sndevent = 0;
	uint32_t rcvevent = 0;
	uint8_t	 inttype;
	
	AG903_UARTPrmGetIntType(ch, &inttype);
	
	if(AG903_UART_STAT_SEND == UartChStat[ch].snd.stat) {
		result = UARTMgr_IntSend(ch, inttype, &sndevent);
		if(AG903_ENONE != result) {
			/* 処理なし */
		}
	}
	if(AG903_UART_STAT_RECEIVE == UartChStat[ch].rcv.stat) {
		result = UARTMgr_IntReceive(ch, inttype, &rcvevent);
		if(AG903_ENONE != result) {
			/* 処理なし */
		}
	}

	if( (NULL != UartHandleStat[ch].clbk) &&
		((0 != sndevent) || (0 != rcvevent)) ) {
		UartHandleStat[ch].clbk((AG903_UARTMgrHandle*)&UartHandleStat[ch], (sndevent|rcvevent));
	}
	
	return;
}

/*
	データ送信（割込み）.
	ch：UARTチャネル番号.
	inttype：割込み種別.
	event：発生イベント.
*/
static int32_t UARTMgr_IntSend(uint8_t ch, uint8_t inttype, uint32_t* event)
{
	int32_t	 retval = AG903_ENONE;
	uint32_t sndsz;

	(*event) = 0;

	if( (AG903_UART_CH_NUM <= ch) ||
		(NULL == event) ) {
		return -AG903_EINVAL;
	}

	if(AG903_UART_INT_THREMPTY == inttype) {
		if(true == UartChStat[ch].snd.dma) {
			(*event) |= AG903_UART_EVENT_SNDEMPTY;
		}
		else {
			if(UartChStat[ch].snd.size <= UartChStat[ch].snd.cnt) {
				AG903_UARTPrmDisableInt(ch, AG903_UART_IER_THREMP_BIT);
				UartChStat[ch].snd.stat = AG903_UART_STAT_IDLE;	/* 送信完了 */
				(*event) |= AG903_UART_EVENT_SNDEND;
			}
			else {
				sndsz = (UartChStat[ch].snd.size - UartChStat[ch].snd.cnt);
				if(AG903_UART_FIFO_SIZE < sndsz) {
					sndsz = AG903_UART_FIFO_SIZE;
				}
				AG903_UARTPrmSendData(ch, (uint8_t*)(UartChStat[ch].snd.buf+UartChStat[ch].snd.cnt), sndsz);
				UartChStat[ch].snd.cnt += sndsz;
			}
		}
	}

	return retval;
}

/*
	データ受信（割込み）.
	ch：UARTチャネル番号.
	inttype：割込み種別.
	event：発生イベント.
*/
static int32_t UARTMgr_IntReceive(uint8_t ch, uint8_t inttype, uint32_t* event)
{
	int32_t	 retval = AG903_ENONE;
	int32_t  result;
	uint32_t rs485event;
	

	(*event) = 0;

	if( (AG903_UART_CH_NUM <= ch) ||
		(NULL == event) ) {
		return -AG903_EINVAL;
	}

	switch(inttype) {
		case AG903_UART_INT_LINESTATUS:
			result = UARTMgr_IntLineStatus(ch, event);
			if(AG903_ENONE != result) {
				/* 処理なし */
			}
			break;
		case AG903_UART_INT_DATAREADY:
			if(false == UartChStat[ch].rcv.dma) {
				(*event) |= AG903_UART_EVENT_DATARDY;
			}
			break;
		case AG903_UART_INT_RCVTIMEOUT:
			(*event) |= AG903_UART_EVENT_RCVTIMEOUT;
			break;
		default:
			/* 処理なし */
			break;
	}

	if(true == UartChStat[ch].rs485) {
		result = UARTMgr_IntRs485Status(ch, &rs485event);
		if(AG903_ENONE == result) {
			(*event) |= rs485event;
		}
	}

	return retval;
}

/*
	Line Staus割込み処理.
	ch：UARTチャネル.
	event：発生イベント.
*/
static int32_t UARTMgr_IntLineStatus(uint8_t ch, uint32_t* event)
{
	int32_t	 retval = AG903_ENONE;
	uint8_t  linest;

	(*event) = 0;

	if( (AG903_UART_CH_NUM <= ch) ||
		(NULL == event) ) {
		return -AG903_EINVAL;
	}

	AG903_UARTPrmGetLineStatus(ch, &linest);	/* LSR Read */

	if(AG903_UART_LSR_FIFOERR_BIT & linest) {
		(*event) |= AG903_UART_EVENT_FIFOERR;
	}
	if(AG903_UART_LSR_BREAK_BIT & linest) {
		(*event) |= AG903_UART_EVENT_BREAK;
	}
	if(AG903_UART_LSR_FRAMING_BIT & linest) {
		(*event) |= AG903_UART_EVENT_FRAMINGERR;
	}
	if(AG903_UART_LSR_PARITY_BIT & linest) {
		(*event) |= AG903_UART_EVENT_PARITYERR;
	}
	if(AG903_UART_LSR_OVERRUN_BIT & linest) {
		(*event) |= AG903_UART_EVENT_OVERRUN;
	}
	if(AG903_UART_LSR_DATARDY_BIT & linest) {
		(*event) |= AG903_UART_EVENT_DATARDY;
	}
	
	return retval;
}

/*
	RS485ステータス割込み処理.
	ch：UARTチャネル.
	event：発生イベント.
*/
static int32_t UARTMgr_IntRs485Status(uint8_t ch, uint32_t* event)
{
	int32_t	 retval = AG903_ENONE;
	uint32_t stat;

	(*event) = 0;

	if( (AG903_UART_CH_NUM <= ch) ||
		(NULL == event) ) {
		return -AG903_EINVAL;
	}
	
	AG903_UARTPrmGetRs485Status(ch, &stat);
	
	if(AG903_UART_DETECT_RTO_BIT & stat) {
		(*event) |= AG903_UART_EVENT_RS485_RTO;
	}
	if(AG903_UART_DETECT_CTO_BIT & stat) {
		(*event) |= AG903_UART_EVENT_RS485_CTO;
	}
	AG903_UARTPrmClerTimeoutStatus(ch, AG903_UART_DETECT_ALL_BIT);

	return retval;
}
