/**
 * @brief       OSP Manager
 * @author      AXELL CORPORATION
 * @description OSP Manager Layer.
 * @note        none
 * @history     2017_02_22  初版
 * @history     2017_10_26  Ver2.0
 * @history     2019_03_08  [SDK2.2] AG903_OSPMgrInitですべてのイベントをクリアするように修正 (#2194)
 * @history     2019_03_08  [SDK2.2] OSPでのコマンドバッファ操作の不具合を修正 (#2200)
*/
/* DOM-IGNORE-BEGIN */
/*
 * This program was created by AXELL CORPORATION.
 * Copyright (C) 2017-2019 AXELL CORPORATION, all rights reserved.
 */
/* DOM-IGNORE-END */

#include "AG903_common.h"

#include "osp/ospprm.h"
#include "osp/ospmgr.h"
#include "osp.h"


/* 	Build command ID
	ID:command ID(max length is 4bit) */
#define	OSP_CMDID(ID)				((ID) << 28)


/*	BAS(Bus Access Single)
	LEN:number of address and data pair(max length is 63(7bit)) */
#define	OSP_CMD_BAS(LEN)			(OSP_CMDID(OSP_CMDID_BAS) | (((LEN) & AG903_OSP_CMD_BAS_SIZE) << 0))

/* 	BAB(Buss Access Burst)
	LEN:number of address and data pair(max length is 63(7bit))
	F:Address 0:Fixed 1:Increment */
#define	OSP_CMD_BAB(LEN,F)			(OSP_CMDID(OSP_CMDID_BAB) | (((F) & 0x1) << 27) | (((LEN) & AG903_OSP_CMD_BAB_SIZE) << 0))

/*	Set address for Bus Access Command */
#define	OSP_CMD_ADDR(ADR)			((ADR) & 0xFFFFFFFC)

/*	Set data for Bus Access Command */
#define	OSP_CMD_DATA(DAT)			(DAT)

/*	BAW(Bus Access Wait) */
#define	OSP_CMD_BAW()				(OSP_CMDID(OSP_CMDID_BAW))

/*	INTR(Wait Interrupt)
	ID:number of IR */
#define	OSP_CMD_INTR(ID)			(OSP_CMDID(OSP_CMDID_INTR) | (((ID) & 0x3F) << 0))

/*	EVENT(Wait Event)
	ID:number of event */
#define	OSP_CMD_EVENT(ID)			(OSP_CMDID(OSP_CMDID_EVENT) | (((ID) & 0x3F) << 0))

/*	EVENTD(Event Decrement)
	ID:number of event */
#define	OSP_CMD_EVENTD(ID)			(OSP_CMDID(OSP_CMDID_EVENTD) | (((ID) & 0x3F) << 0))

/*	EVENTC(Event Clear)
	ID:number of event */
#define	OSP_CMD_EVENTC(ID)			(OSP_CMDID(OSP_CMDID_EVENTC) | (((ID) & 0x3F) << 0))

/*	SETF(Set Flag)
	FLAG:flag for wait control */
#define	OSP_CMD_SETF(FLAG)			(OSP_CMDID(OSP_CMDID_SETF) | (((FLAG) & 0x0FFFFFFF) << 0))

/*	CLRF(Clear Flag)
	FLAG:flag for wait control */
#define	OSP_CMD_CLRF(FLAG)			(OSP_CMDID(OSP_CMDID_CLRF) | (((FLAG) & 0x0FFFFFFF) << 0))

/*	NOP(No Operation)
	NOP is undefined operation */
#define	OSP_CMD_NOP()				(OSP_CMDID(OSP_CMDID_NOP))


/** コマンドバッファヘッダ構造 */
typedef struct _OSPCmdDesc {
	uint32_t	*Buf;			/** バッファポインタ */
	uint32_t	BufLen;			/** バッファ容量(コマンド数) */
	uint32_t	CurLen;			/** コマンド登録数 */
	uint32_t	*WrBuf;			/** 書込みバッファポインタ */
	uint32_t	*RdBuf;			/** 読込みバッファポインタ */
	uint32_t	BuffMode;		/** バッファモード (0:FIFO 1:RING) */
	uint32_t	Reserved[2];	/** 将来的にも構造体を32バイトに保つための予約領域 */
} OSPCmdDesc;

/** チャンネル状態保持構造 */
typedef struct _AG903_OSPMgrChStat{
	void*		cmdbuf;		/** コマンドバッファアドレス */
} AG903_OSPMgrChStat;

/** ハンドル状態保持構造 */
typedef struct _AG903_OSPMgrHandleStat{
	uint8_t		lock;		/** ロック */
	uint8_t		reserve[3];	/** 予約 */
} AG903_OSPMgrHandleStat;

static AG903_OSPMgrChStat		OspChStat[AG903_OSP_CH_NUM];		/* ch状態 */
static AG903_OSPMgrHandleStat	OspHandleStat[AG903_OSP_CH_NUM];	/* handle状態 */


static int32_t OSPMgrCheckHandle(AG903_OSPMgrHandle *handle,uint8_t *ch);
static int32_t OSPMgrCheckOverflow(uint8_t ch);
static int32_t OSPMgrSetCommand(uint8_t ch, uint32_t c);
#if AG903_OSP_CMD_PARSE
static int32_t OSPMgrParseCommand(OSPCmdDesc *desc);
static uint16_t OSPMgrParseCommandCRC(uint8_t mode, uint8_t* data, uint32_t s_adr, uint32_t e_adr);
#endif/* if AG903_OSP_CMD_PARSE */


/**
 * @brief           OSPManager初期化
 * @param           void
 * @return          エラーコード
 * @retval          AG903_ENONE 正常終了
 * @description     モジュール内変数の初期化, およびレジスタの初期化を行います.
 * @note            OSPモジュール使用前に必ず実行してください.
 *                  この初期化はOSPのチャンネルに依存しない共通の初期化です.
 */
int32_t AG903_OSPMgrInit(void)
{
	int32_t ch, evt;

	/* OSP各チャネル初期化 */
	for (ch = 0;ch < AG903_OSP_CH_NUM;ch++) {
		AG903_OSPPrmFIFOCTRL(ch);
		AG903_OSPPrmPRIOR(ch, 0);
	}

	/* イベントクリア */
	for (evt=0; evt<AG903_OSP_EVENT_NUM; evt++)
		AG903_OSPPrmEnableEvent(evt, 0, 0);

	/* フラグクリア */
	AG903_OSPPrmFLAGCLR(0x0FFFFFFF);

	for (ch = 0;ch < AG903_OSP_CH_NUM;ch++) {
		OspChStat[ch].cmdbuf   = NULL;
		OspHandleStat[ch].lock = false;
	}

	return AG903_ENONE;
}

/**
 * @brief           OSPハンドル取得
 * @param           handle [out] OSPハンドル
 * @return          エラーコード
 * @retval          AG903_ENONE 正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @retval          -AG903_EBUSY ハンドル使用中
 * @description     OSPのハンドルを取得します.<p>
 *                  取得するハンドルのchは自動的に割り振られます.
 */
int32_t AG903_OSPMgrGetHandle(AG903_OSPMgrHandle **handle)
{
	int32_t	rc = AG903_ENONE;
	int32_t	loop;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	for(loop=0; loop<AG903_OSP_CH_NUM; loop++) {
		if(false == OspHandleStat[loop].lock) {
			OspHandleStat[loop].lock = true;
			break;
		}
	}
	if(AG903_OSP_CH_NUM <= loop) {
		/* ハンドル使用中 */
		return -AG903_EBUSY;
	}

	(*handle) = (AG903_OSPMgrHandle*)&OspHandleStat[loop];

	return rc;
}

/**
 * @brief           OSPハンドル解放
 * @param           handle [in] OSPハンドル
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @retval          -AG903_EBUSY  実行中
 * @description     OSPのハンドルを返却します.<p>
 *                  ハンドルに割当てられたOSPが実行中の場合は返却できません.
 */
int32_t AG903_OSPMgrReleaseHandle(AG903_OSPMgrHandle *handle)
{
	int32_t		rc = AG903_ENONE;
	uint8_t		ch;
	uint8_t		stat, cnt;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		rc = AG903_OSPMgrGetStat(handle, &stat, &cnt);
	}

	if (rc == AG903_ENONE) {
		if (stat != 0) {
			/* バス転送実行中 */
			rc = -AG903_EBUSY;
		}
	}

	if (rc == AG903_ENONE) {
		AG903_OSPMgrDisable(handle);
		OspHandleStat[ch].lock = false;
	}

	return rc;
}

/**
 * @brief           コマンドバッファ設定
 * @param           handle [in] OSPハンドル
 * @param           param [in] コマンドバッファパラメータ
 * @param           init [in] コマンドバッファ初期化指定（true：初期化）
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     コマンドバッファを登録します.
 * @note            コマンド必要数に応じたコマンドバッファをアプリケーションで確保して下さい.
 * @note            このコマンドバッファはハンドルを開放するまで確保し続けて下さい.
 *                  また直接アクセスしないで下さい.
 * @note            コマンドバッファはコマンドのためのサイズ(1コマンド32バイト)+32バイト以上確保して下さい.
 * @note            paramのsizeは４バイトを1単位として指定して下さい.
 */
int32_t AG903_OSPMgrSetCommandBuf(AG903_OSPMgrHandle *handle, AG903_OSPCmdBuf *param, bool init)
{
	int32_t				rc = AG903_ENONE;
	uint8_t				ch;
	OSPCmdDesc			*desc;

	if(NULL == handle || NULL == param) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		if ((AG903_OSP_BUFMODE_NUM <= param->mode) || (NULL == param->addr) || (0 == param->size)) {
			/* パラメータ異常 */
			rc = -AG903_EINVAL;
		}
	}

	if (rc == AG903_ENONE) {
		/*
		 * Commad Buffer:
		 * +--------------------+
		 * | Command Head       | sizeof(OSPCmdDesc)
		 * +--------------------+
		 * | Command Buff       | コマンド数×4Bytes
		 * |  +-----------------+
		 * |  | Commad 1        |
		 * |  +-----------------+
		 * |  | Commad 2        |
		 * |  +-----------------+
		 * |  |      :          |
		 * |  +-----------------+
		 * |  | Commad n        |
		 * +--------------------+
		 */
		OspChStat[ch].cmdbuf = (void*)param->addr;
		desc = (OSPCmdDesc*)param->addr;
		desc->Buf      = param->addr + sizeof(OSPCmdDesc) / sizeof(uint32_t);
		desc->BufLen   = (param->size - sizeof(OSPCmdDesc)) / sizeof(uint32_t);
		desc->CurLen   = 0;
		desc->WrBuf    = desc->Buf;
		desc->RdBuf    = desc->Buf;		
		desc->BuffMode = param->mode;
		if(true == init) {
			AG903_OSPMgrClearCommand(handle);
		}
	}

	return rc;
}

/**
 * @brief           コマンドクリア
 * @param           handle [in] OSPハンドル
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     コマンドバッファに登録したコマンドを破棄します.<p>
 *                  既にFIFOにセットされているコマンドはクリアされずに処理されます.
 */
int32_t AG903_OSPMgrClearCommand(AG903_OSPMgrHandle *handle)
{
	int32_t				rc = AG903_ENONE;
	uint8_t				ch;
	OSPCmdDesc			*desc;							/* コマンドデスクリプタ		*/

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		desc = (OSPCmdDesc*)OspChStat[ch].cmdbuf;

		desc->CurLen = 0;
		desc->RdBuf  = desc->Buf;
		desc->WrBuf  = desc->Buf;
	}

	return rc;
}

/**
 * @brief           コマンド登録数取得
 * @param           handle [in] OSPハンドル
 * @param           cnt [out] 登録コマンド数
 * @return          エラーコード
 * @retval           AG903_ENONE   正常終了
 * @retval          -AG903_EINVAL  パラメータ異常
 * @retval          -AG903_ENODATA コマンドバッファ異常
 * @description     コマンドバッファに登録されているコマンド数を返します.
 */
int32_t AG903_OSPMgrGetCommandCnt(AG903_OSPMgrHandle *handle, uint32_t *cnt)
{
	int32_t				rc = AG903_ENONE;
	uint8_t				ch;
	OSPCmdDesc			*desc;							/* コマンドデスクリプタ		*/

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		if (cnt == NULL) {
			/* パラメータ異常 */
			rc = -AG903_EINVAL;
		}
	}
	if (rc == AG903_ENONE) {
		if(NULL == OspChStat[ch].cmdbuf) {
			/* コマンドバッファ異常 */
			rc = -AG903_ENODATA;
		}
	}

	if (rc == AG903_ENONE) {
		desc   = (OSPCmdDesc*)OspChStat[ch].cmdbuf;
		(*cnt) = desc->CurLen;
	}

	return rc;
}

/**
 * @brief           優先度設定
 * @param           handle [in] OSPハンドル
 * @param           priority [in] 優先度（0〜3）
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     チャンネル別に優先度を設定します.<p>
 *                  複数チャンネルで同時にバスアクセスが発生した場合, 優先度に従ってコマンド実行します.<p>
 *                  優先度が同じ場合, ラウンドロビンで処理されます.
 * @seealso         _AG903_OSPMgrPri
 */
int32_t AG903_OSPMgrSetPriority(AG903_OSPMgrHandle *handle, uint8_t priority)
{
	int32_t		rc = AG903_ENONE;
	uint8_t		ch;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		if (priority >= AG903_OSP_PRI_NUM) {
			/* 優先度不正 */
			rc = -AG903_EINVAL;
		}
	}

	if (rc == AG903_ENONE) {
		AG903_OSPPrmPRIOR(ch, priority);
	}

	return rc;
}

/**
 * @brief           OSP動作開始
 * @param           handle [in] OSPハンドル
 * @return          エラーコード
 * @return           AG903_ENONE  正常終了
 * @return          -AG903_EINVAL パラメータ異常
 * @description     FIFOにセットされたコマンドを順次実行します.
 */
int32_t AG903_OSPMgrEnable(AG903_OSPMgrHandle *handle)
{
	int32_t		rc = AG903_ENONE;
	uint8_t		ch;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		AG903_OSPPrmCTRL(ch, true);
	}

	return rc;
}

/**
 * @brief           OSP動作停止
 * @param           handle [in] OSPハンドル
 * @return          エラーコード
 * @return           AG903_ENONE  正常終了
 * @return          -AG903_EINVAL パラメータ異常
 * @description     handleに割当てられたチャンネルのOSPを停止します.
 */
int32_t AG903_OSPMgrDisable(AG903_OSPMgrHandle *handle)
{
	int32_t		rc = AG903_ENONE;
	uint8_t		ch;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		AG903_OSPPrmCTRL(ch, false);
	}

	return rc;
}

/**
 * @brief           内部状態取得
 * @param           handle [in] OSPハンドル
 * @param           stat [out] OSP内部状態（0：停止中, 0以外：動作中）
 * @param           cnt [out] 現在実行中のFIFOカウント
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     OSPの内部状態, および現在実行中のFIFOカウントを返します.
 */
int32_t AG903_OSPMgrGetStat(AG903_OSPMgrHandle *handle, uint8_t *stat, uint8_t *cnt)
{
	int32_t		rc = AG903_ENONE;
	uint8_t		ch;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		if ((stat == NULL)
		||  (cnt  == NULL)) {
			/* パラメータ不正 */
			rc = -AG903_EINVAL;
		}
	}

	if (rc == AG903_ENONE) {
		AG903_OSPPrmSTAT(ch, stat, cnt);
	}

	return rc;
}

/**
 * @brief           FIFO状態取得
 * @param           handle [in] OSPハンドル
 * @param           ovf [out] オーバーフロー状態 (0:なし 1:あり)
 * @param           siz [out] FIFOの空き容量を取得する変数へのポインタ (0〜AG903_OSP_FIFO_NUM)
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     ハンドラに割り当てられたチャンネルのFIFO状態を取得します.
 */
int32_t AG903_OSPMgrGetFIFOStat(AG903_OSPMgrHandle *handle, uint8_t *ovf, uint8_t *siz)
{
	int32_t		rc = AG903_ENONE;
	uint8_t		ch;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		if ((ovf == NULL)
		||  (siz == NULL)) {
			/* パラメータ異常 */
			rc = -AG903_EINVAL;
		}
	}

	if (rc == AG903_ENONE) {
		AG903_OSPPrmFIFOSTAT(ch, ovf, siz);
	}

	return rc;
}

/**
 * @brief           フラグ設定
 * @param           flag [in] フラグ (各ビット)
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     ウェイト制御用のフラグをセットします.<p>
 *                  複数のフラグを指定可能です.
 * @note            フラグは全チャネルで共通です.
 */
int32_t AG903_OSPMgrSetFlag(uint32_t flag)
{
	int32_t		rc = AG903_ENONE;

	if ((flag & 0xF0000000)) {
		/* パラメータ異常 */
		rc = -AG903_EINVAL;
	}

	if (rc == AG903_ENONE) {
		AG903_OSPPrmFLAGSET(flag);
	}

	return rc;
}

/**
 * @brief           フラグクリア
 * @param           flag [in] フラグ (各ビット)
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     ウェイト制御用のフラグをクリアします.<p>
 *                  複数のフラグを指定可能です.
 * @note            フラグは全チャネルで共通です.
 */
int32_t AG903_OSPMgrClearFlag(uint32_t flag)
{
	int32_t		rc = AG903_ENONE;

	if ((flag & 0xF0000000)) {
		/* パラメータ異常 */
		rc = -AG903_EINVAL;
	}

	if (rc == AG903_ENONE) {
		AG903_OSPPrmFLAGCLR(flag);
	}

	return rc;
}

/**
 * @brief           フラグ状態取得
 * @param           flag [out] フラグ状態 (各ビット)
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     ウェイト制御用のフラグの状態を取得します.
 * @note            フラグは全チャネルで共通です.
 */
int32_t AG903_OSPMgrGetFlagStat(uint32_t *flag)
{
	int32_t		rc = AG903_ENONE;

	if (flag == NULL) {
		/* パラメータ異常 */
		rc = -AG903_EINVAL;
	}

	if (rc == AG903_ENONE) {
		AG903_OSPPrmFLAGSTAT(flag);
	}

	return rc;
}

/**
 * @brief           イベントカウント有効・無効設定
 * @param           evt [in] イベント番号（0〜63）
 * @param           enable [in] 有効・無効設定（0:無効 1:有効）
 * @param           cnt [in] イベントカウンタ（0〜15）
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     イベントカウントの有効・無効を設定します.<p>
 *                  イベントカウントの最大値（オーバーフロー検出）を設定します.<p>
 *                  イベントカウンタを有効にした場合, イベント発生によりカウンタをインクリメントします.<p>
 *                  インクリメントされた結果オーバーフローした場合, その状態が保持されます.
 * @note            フラグは全チャネルで共通です.<p>
 *                  イベント番号：0〜63<p>
 *                  有効・無効設定：0:無効 1:有効<p>
 *                  イベントカウント数：0〜15
 */
int32_t AG903_OSPMgrSetEventCntEnable(uint32_t evt, uint8_t enable, uint8_t cnt)
{
	int32_t	rc = AG903_ENONE;

	if (evt >= AG903_OSP_EVENT_NUM) {
		/* イベント番号異常 */
		rc = -AG903_EINVAL;
	}

	if (rc == AG903_ENONE) {
		if ((enable & ~0x01)
		||  (cnt    & ~0x0F)) {
			/* パラメータ異常 */
			rc = -AG903_EINVAL;
		}
	}

	if (rc == AG903_ENONE) {
		AG903_OSPPrmEnableEvent(evt, enable, cnt);
	}

	return rc;
}

/**
 * @brief           イベント状態取得
 * @param           evt [in] イベント番号（0〜63）
 * @param           ovf [out] オーバーフロー状態格納バッファ
 * @param           cnt [out] イベントカウンタ格納バッファ
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     指定イベント番号のオーバーフロー状態, および現在のカウント値を返します.
 * @note            フラグは全チャネルで共通です.<p>
 *                  イベント番号：0〜63<p>
 *                  オーバーフロー状態：0:なし 1:あり<p>
 *                  イベントカウント数：0〜15
 */
int32_t AG903_OSPMgrGetEventStat(uint32_t evt, uint8_t *ovf, uint8_t *cnt)
{
	int32_t	rc = AG903_ENONE;

	if (evt >= AG903_OSP_EVENT_NUM) {
		/* イベント番号異常 */
		rc = -AG903_EINVAL;
	}

	if (rc == AG903_ENONE) {
		if ((ovf == NULL)
		||  (cnt == NULL)) {
			/* パラメータ異常 */
			rc = -AG903_EINVAL;
		}
	}

	if (rc == AG903_ENONE) {
		AG903_OSPPrmGetEventStat(evt, ovf, cnt);
	}

	return rc;
}

/**
 * @brief           FIFOへのコマンドのセット
 * @param           handle [in] OSPハンドル
 * @param           setcnt [in] セットするコマンド数
 * @return          エラーコード
 * @retval           AG903_ENONE     正常終了
 * @retval          -AG903_EINVAL    パラメータ異常
 * @retval          -AG903_ENODATA   コマンドバッファ異常
 * @retval          -AG903_EOVERFLOW オーバーフロー発生
 * @retval          -AG903_EBUSY
 * @description     コマンドバッファからsetcntのコマンドをFIFOにセットします.<p>
 *                  コマンドバッファが空の場合はエラーを返します(-AG903_ENODATA).<p>
 *                  setcntがFIFOの空き超えている場合はエラーを返します(-AG903_EOVERFLOW).<p>
 *                  setcntが登録済コマンド数を超えている場合はクリップします.
 * @note            登録数：1〜コマンドバッファ内登録数（最大数：AG903_OSP_FIFO_NUM）
 * @note            setcntだけコマンドをFIFOにセットするまで本APIから復帰しません.
 * @note            setcntはひとまとまりのコマンドを分断することがないように選んで下さい。
 */
int32_t AG903_OSPMgrSetFIFO(AG903_OSPMgrHandle *handle, uint32_t setcnt)
{
	int32_t				rc = AG903_ENONE;
	uint8_t				ch;
	OSPCmdDesc			*desc;							/* コマンドデスクリプタ		*/
	uint8_t				ovf = 0;
	uint8_t				siz = 0;
	uint32_t			MaxLen;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);
	if(AG903_ENONE != rc) {
		/* handle異常 */
		return -AG903_EINVAL;
	}
	if(NULL == OspChStat[ch].cmdbuf) {
		/* コマンドバッファ異常 */
		return -AG903_ENODATA;
	}

	desc = (OSPCmdDesc*)OspChStat[ch].cmdbuf;
	if(0 == desc->CurLen) {
		/* コマンド空登録 */
		return -AG903_ENODATA;
	}

	if (setcnt > desc->CurLen) {
		/* コマンド登録数以上のセットコマンド数を指定することは用法が間違っている */
		return -AG903_EINVAL;
	}

	AG903_OSPPrmFIFOSTAT(ch, &ovf, &siz);

	if (ovf == true) {
		/* FIFOオーバーフロー */
		return -AG903_EOVERFLOW;
	}
	if ((siz == 0) || (siz < setcnt)) {
		/* FIFOセット数(=setcnt)分の空きがFIFOにない場合エラー */
		return -AG903_EBUSY;
	}

#if AG903_OSP_CMD_PARSE
	if (rc == AG903_ENONE) {
		rc = OSPMgrParseCommand(desc);
	}
#endif/* if AG903_OSP_CMD_PARSE */

	if (AG903_OSP_BUFMODE_RING == desc->BuffMode) {
		MaxLen = desc->BufLen;	/* RINGバッファモード */
	}
	else {
		MaxLen = desc->CurLen;	/* FIFOバッファモード */
	}

	if ((desc->RdBuf + setcnt) > (desc->Buf + MaxLen)) {
		uint32_t	Len;
		/*
		 * +-----------+ <- Buf
		 * | 0         |
		 * +-----------+
		 * | :         |
		 * +-----------+ <- RdBuf
		 * | :         |
		 * +-----------+ <- (Buf + MaxLen)
		 * |           |
		 * +-----------+ <- (RdBuf + setcnt)
		 * | :         |
		 * +-----------+
		 */
		Len = (desc->Buf + MaxLen) - desc->RdBuf;
		AG903_OSPPrmFIFODT(ch, desc->RdBuf, Len);

		desc->RdBuf = desc->Buf;
		setcnt     -= Len;

		if (AG903_OSP_BUFMODE_RING == desc->BuffMode) {
			desc->CurLen -= Len;
		}
	}

	AG903_OSPPrmFIFODT(ch, desc->RdBuf, setcnt);
	desc->RdBuf += setcnt;

	if (AG903_OSP_BUFMODE_RING == desc->BuffMode) {
		desc->CurLen -= setcnt;
	}

	if (desc->RdBuf >= (desc->Buf + MaxLen)) {
		desc->RdBuf  = desc->Buf;
	}

	return rc;
}

/**
 * @brief           FIFOクリア
 * @param           handle [in] OSPハンドル
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     FIFOにセットしたコマンドをクリアします.<p>
 *                  FIFOの空き容量, オーバーフロー状態も初期化されます.
 * @note            コマンド処理中に実行した場合, 処理中のデータは破棄されます.
 */
int32_t AG903_OSPMgrClearFIFO(AG903_OSPMgrHandle *handle)
{
	int32_t		rc = AG903_ENONE;
	uint8_t		ch;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		AG903_OSPPrmFIFOCTRL(ch);
	}

	return rc;
}

/**
 * @brief           コマンド登録
 * @param           handle [in] OSPハンドル
 * @param           cmd [in] コマンド
 * @param           param [in] パラメータ（コマンド別）
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @retval          -AG903_EOVERFLOW オーバーフロー発生
 * @description     コマンドを登録します.
 */
int32_t AG903_OSPMgrSetCommand(AG903_OSPMgrHandle *handle, AG903_OSPMgrCmd cmd, uint32_t param)
{
	int32_t		rc = AG903_ENONE;
	uint32_t	cmddt;
	uint8_t		ch = -1;

	if(NULL == handle) {
		rc = -AG903_EINVAL;
	}

	rc = OSPMgrCheckHandle(handle, &ch);

	if (rc == AG903_ENONE) {
		rc = OSPMgrCheckOverflow(ch);
	}

	switch(cmd) {
		case AG903_OSP_CMD_BUS_SINGLE:	/* BAS */
			if( (0==param) || (AG903_OSP_CMD_BAS_SIZE<param) ) {
				/* 登録データ数異常 */
				rc = -AG903_EINVAL;
			}
			else {
				cmddt = OSP_CMD_BAS(param);
			}
			break;
		case AG903_OSP_CMD_BUS_BURST_FIX:	/* BAB [F=1] */
			if( (0==param) || (AG903_OSP_CMD_BAB_SIZE<param) ) {
				/* 登録データ数異常 */
				rc = -AG903_EINVAL;
			}
			else {
				cmddt = OSP_CMD_BAB(param, 1);
			}
			break;
		case AG903_OSP_CMD_BUS_BURST_INC:	/* BAB [F=0] */
			if( (0==param) || (AG903_OSP_CMD_BAB_SIZE<param) ) {
				/* 登録データ数異常 */
				rc = -AG903_EINVAL;
			}
			else {
				cmddt = OSP_CMD_BAB(param, 0);
			}
			break;
		case AG903_OSP_CMD_BUS_ADDR:	/* ADDR */
			if( (0==param) || (param%4) ) {
				/* バスアドレス異常 */
				rc = -AG903_EINVAL;
			}
			else {
				cmddt = OSP_CMD_ADDR(param);
			}
			break;
		case AG903_OSP_CMD_BUS_DATA:	/* DATA */
			cmddt = OSP_CMD_DATA(param);
			break;
		case AG903_OSP_CMD_BUS_WAIT:	/* BAW */
			cmddt = OSP_CMD_BAW();
			break;
		case AG903_OSP_CMD_INTR_WAIT:	/* INTR */
			cmddt = OSP_CMD_INTR(param);
			break;
		case AG903_OSP_CMD_EVNT_WAIT:	/* EVENT */
			if(AG903_OSP_EVENT_NUM<=param) {
				/* イベントID異常 */
				rc = -AG903_EINVAL;
			}
			else {
				cmddt = OSP_CMD_EVENT(param);
			}
			break;
		case AG903_OSP_CMD_EVNT_DEC:	/* EVENTD */
			if(AG903_OSP_EVENT_NUM<=param) {
				/* イベントID異常 */
				rc = -AG903_EINVAL;
			}
			else {
				cmddt = OSP_CMD_EVENTD(param);
			}
			break;
		case AG903_OSP_CMD_EVNT_CLR:	/* EVENTC */
			if(AG903_OSP_EVENT_NUM<=param) {
				/* イベントID異常 */
				rc = -AG903_EINVAL;
			}
			else {
				cmddt = OSP_CMD_EVENTC(param);
			}
			break;
		case AG903_OSP_CMD_FLAG_SET:	/* SETF */
			cmddt = OSP_CMD_SETF(param);
			break;
		case AG903_OSP_CMD_FLAG_CLR:	/* CLRF */
			cmddt = OSP_CMD_CLRF(param);
			break;
		case AG903_OSP_CMD_NOP:
			cmddt = OSP_CMD_NOP();
			break;
		default:
			/* コマンド異常 */
			rc = -AG903_EINVAL;
			break;
	}

	if (rc == AG903_ENONE) {
		rc = OSPMgrSetCommand(ch, cmddt);
	}

	return rc;

}

/**
 * @brief           ハンドルチェック
 * @param           handle [in] OSPハンドル
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @description     ハンドル値, チャンネルの正当性をチェックします.
 */
static int32_t OSPMgrCheckHandle(AG903_OSPMgrHandle *handle, uint8_t *ch)
{
	int32_t		rc = AG903_ENONE;
	uint32_t	channel;


	channel = ((uint32_t)handle - (uint32_t)OspHandleStat) / sizeof(AG903_OSPMgrHandleStat);

	if( (AG903_OSP_CH_NUM <= channel) ||
		(&OspHandleStat[channel] != (AG903_OSPMgrHandleStat*)handle) ) {
		/* ハンドル異常 */
		rc = -AG903_EINVAL;
	}
	else {
		(*ch) = (uint8_t)channel;
	}

	return rc;
}

/**
 * @brief           オーバーフローチェック
 * @param           handle [in] OSPハンドル
 * @return          エラーコード
 * @return           AG903_ENONE  正常終了
 * @retval          -AG903_EINVAL パラメータ異常
 * @retval          -AG903_EOVERFLOW オーバーフロー発生
 * @description     オーバーフローの発生有無をチェックします.<p>
 *                  handleに渡されるハンドルは OSPMgrCheckHandle にてチェック済みであることを想定しています.
 */
static int32_t OSPMgrCheckOverflow(uint8_t ch)
{
	int32_t				rc = AG903_ENONE;
	OSPCmdDesc			*desc;							/* コマンドデスクリプタ		*/


	desc = (OSPCmdDesc*)OspChStat[ch].cmdbuf;

	if ((desc->Buf == (uint32_t *)NULL                     )
	||  (desc->BufLen == 0                                 )
	||  (desc->CurLen > desc->BufLen                       )
	||	(desc->RdBuf < desc->Buf                           )
	||	(desc->Buf + desc->BufLen <= desc->RdBuf           )
	||	(desc->WrBuf < desc->Buf                           )
	||	(desc->Buf + desc->BufLen <= desc->WrBuf           )) {
		/* コマンドバッファ異常 */
		rc = -AG903_EINVAL;
	}

	if (rc == AG903_ENONE) {
		if ((desc->CurLen + 1) > desc->BufLen) {
			/* コマンドバッファオーバーフロー */
			rc = -AG903_EOVERFLOW;
		}
	}

	return rc;
}

/**
 * @brief           コマンド設定
 * @param           handle [in] OSPハンドル
 * @param           cmd [in] コマンド
 * @return          エラーコード
 * @retval          AG903_ENONE 正常終了
 * @description     コマンド設定用ルーチンです.
 */
static int32_t OSPMgrSetCommand(uint8_t ch, uint32_t c)
{
	int32_t				rc = AG903_ENONE;
	OSPCmdDesc			*desc;						/* コマンドデスクリプタ		*/


	desc = (OSPCmdDesc*)OspChStat[ch].cmdbuf;

	*(desc->WrBuf) = c;
	desc->WrBuf++;
	desc->CurLen++;

	if (desc->BuffMode) {							/* RINGバッファモード		*/
		if (desc->WrBuf >= (desc->Buf + desc->BufLen)) {
			desc->WrBuf = desc->Buf;
		}
	}

	return rc;
}

#if AG903_OSP_CMD_PARSE
/**
 * @brief           コマンド解析
 * @param           desc [in] コマンドデスクリプタ
 * @return          エラーコード
 * @retval           AG903_ENONE  正常終了
 * @retval          -AG903_EFAULT コマンド異常
 * @description     登録されたコマンドを解析します.
 */
static int32_t OSPMgrParseCommand(OSPCmdDesc *desc)
{
	int32_t				rc = AG903_ENONE;
	uint32_t			*buf, *endbuf;
	uint8_t				cmdid;
	uint32_t			len;
	uint32_t			ii;


	buf    = desc->RdBuf;								/* 先頭コマンドバッファ		*/
	endbuf = desc->Buf + desc->BufLen;					/* 終端コマンドバッファ		*/

	for (ii = 0;ii < desc->CurLen;ii++) {
		cmdid = (*buf >> 28);							/* コマンドID取得			*/

		switch (cmdid) {
			case OSP_CMDID_BAS:
				len  = ((*buf & AG903_OSP_CMD_BAS_SIZE) << 1) + 1/*Bus Address*/;
				buf += len;
				ii  += len;
				break;

			case OSP_CMDID_BAB:
				len  = (*buf & AG903_OSP_CMD_BAB_SIZE) + 1/*Bus Address*/;
				buf += len;
				ii  += len;
				break;

			case OSP_CMDID_BAW:
			case OSP_CMDID_INTR:
			case OSP_CMDID_EVENT:
			case OSP_CMDID_EVENTD:
			case OSP_CMDID_EVENTC:
			case OSP_CMDID_SETF:
			case OSP_CMDID_CLRF:
			case OSP_CMDID_NOP:
				break;

			default:
				/* コマンドバッファアドレス異常 */
				rc = -AG903_EFAULT;
				goto err;
		}

		buf++;
		if (buf > endbuf) { buf = desc->Buf; }
	}

err:
	return rc;
}

/**
 * @brief           CRC生成／チェック
 * @param           mode [in] CRCモード(0:CRC生成 1:CRCチェック)
 * @param           data [in] データのベースアドレス
 * @param           s_adr [in] CRC計算の開始オフセット
 * @param           e_adr [in] CRC計算の終了オフセット
 * @return          モードに対する結果
 * @retval          >0 CRC計算結果(CRC生成モード)
 * @retval          >=0 チェック結果(CRCチェックモード)
 * @description     modeによって、CRCの生成 または CRCのチェックを行います.
 */
static uint16_t OSPMgrParseCommandCRC(uint8_t mode, uint8_t* data, uint32_t s_adr, uint32_t e_adr)
{
	uint32_t	crc;												/* CRCを計算する変数			*/
	uint8_t		*d_adr;												/* 計算データへのポインタ		*/
	uint32_t	d_len;												/* 計算するデータの長さ			*/
	uint16_t	ret;												/* 戻り値を格納する変数			*/

	/*
	 * データ領域直後の2バイトをCRC書き込み位置とする
	 * +--------------------+
	 * | データ領域			|
	 * |			+---+---+
	 * |			|  CRC	|
	 * +---+---+----+---+---+
	 */

	/* 初期化 */
	crc	  = 0;														/* CRCの初期化					*/
	d_adr = (data + s_adr);											/* 計算開始位置へのポインタ代入	*/
	d_len = e_adr - s_adr + 2;										/* 計算するデータの数+2(CRC書きこみ用)	*/

	if (mode == 0) {												/* CRC生成モード				*/
		/* CRC書き込み位置の初期化 */
		*(data + e_adr + 0) = 0;
		*(data + e_adr + 1) = 0;
	}
	else {															/* CRCチェックモード			*/
	}

	for (uint32_t ii = 0;ii < d_len;ii++) {							/* CRC書き込み位置含めループ	*/
		crc = crc | *(d_adr++);										/* 1Byte読みこみ				*/

		/* CRC1Byte計算 */
		for (int8_t jj = 0;jj < 8;jj++) {
			crc = crc << 1;											/* CRCとデータを一度にシフト	*/

			if ((crc & 0x01000000) != 0) {							/* CRC計算変数がシフトで桁あふれしたか確認	*/
				crc = crc ^ 0x00102100;								/* 生成多項式のXOR				*/
			}
		}
	}

	ret = (uint16_t)((crc & 0x00ffff00) >> 8);

	if (mode == 0) {												/* CRC生成モード				*/
		*(d_adr - 2) = (uint8_t)((ret >> 8) & 0x00ff);				/* CRCの上位書き込み			*/
		*(d_adr - 1) = (uint8_t)((ret >> 0) & 0x00ff);				/* CRCの下位書き込み			*/
	}
	else {															/* CRCチェックモード			*/
		/* ret = 0なら正常 */
	}

	return ret;
}
#endif/* if AG903_OSP_CMD_PARSE */
