/**
 * @brief           VID Manager
 * @author          AXELL CORPORATION
 * @description     VID 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 AXELL CORPORATION, all rights reserved.
 */
/* DOM-IGNORE-END */

#include <stdio.h>
#include "vid/vidprm.h"
#include "vid/vidmgr.h"
#include "pgp/pgpprm.h"

/* 前処理がアイドル状態であることを指します */
#define PGP_IDLE    (0)

/* デジタルビデオ入力のコンテキスト */
static struct {
    _Bool                       used_in_ports[AG903_VID_MGR_MAX_IN_PORTS];
    AG903_VidMgrInputHandle     in_ports[AG903_VID_MGR_MAX_IN_PORTS];
    _Bool                       used_out_ports[AG903_VID_MGR_MAX_OUT_PORTS];
    AG903_VidMgrOutputHandle    out_ports[AG903_VID_MGR_MAX_OUT_PORTS];
    _Bool                       vid_enable;
    int32_t                     vid_format;
} VidContext = {
    {false, false},
    {{0}},
    {false, false, false, false},
    {{0}},
    false,
    0
};

/**
 * @brief         デジタルビデオ入力の有効/無効設定
 * @param         enable [in] 有効時は　true、無効時は　false　を設定します。 
 * @return        設定結果 
 * @retval        AG903_ENONE 正常終了
 * @description   デジタルビデオ入力の有効を設定します。
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。
*/
int32_t AG903_VidMgrEnable(_Bool enable)
{
    VidContext.vid_enable = enable;

    return AG903_ENONE;
}


static _Bool CheckFormatCompatibility(uint32_t format)
{
    switch (format) {
        case AG903_VID_MGR_24BIT_TO_CH0:
        case AG903_VID_MGR_8BITCH0_TO_CH0:
            if (VidContext.used_in_ports[0] == false || VidContext.used_out_ports[0] == false || 
                VidContext.used_in_ports[1] == true || VidContext.used_out_ports[1] == true ||
                VidContext.used_out_ports[2] == true || VidContext.used_out_ports[3] == true) {
                return false;
            }
            break;
        case AG903_VID_MGR_8BITCH1_TO_CH1:
            if (VidContext.used_in_ports[0] == true || VidContext.used_out_ports[0] == true ||
                VidContext.used_in_ports[1] == false || VidContext.used_out_ports[1] == false ||
                VidContext.used_out_ports[2] == true || VidContext.used_out_ports[3] == true) {
                return false;
            }
            break;
        case AG903_VID_MGR_8BITCH01_TO_CH01:
            if (((VidContext.used_in_ports[0] == false || VidContext.used_out_ports[0] == false) &&
                (VidContext.used_in_ports[1] == false || VidContext.used_out_ports[1] == false)) ||
                VidContext.used_out_ports[2] == true || VidContext.used_out_ports[3] == true) {
                return false;
            }
            break;
        case AG903_VID_MGR_8BITCH0_TO_CH0123:
        default:
            if (VidContext.used_in_ports[0] == false || VidContext.used_in_ports[1] == true || 
                (VidContext.used_out_ports[0] == false && VidContext.used_out_ports[1] == false &&
                VidContext.used_out_ports[2] == false && VidContext.used_out_ports[3] == false)) {
                return false;
            }
            break;
    }

    return true;
}


/**
 * @brief         デジタルビデオ入力のフォーマット設定 
 * @param         format [in] 入力フォーマットを設定します。 
 * @return        設定結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL 入力フォーマットと現在取得されている入出力ハンドルに互換性が無い場合 
 * @description   デジタルビデオ入力フォーマットを指定します。<p> 
 *  							formatには「VIDフォーマット」を指定してください。<p>
 *  							指定されたフォーマットは、現在取得されている入力ポートハンドル、出力ポートハンドルと互換性があるかチェックします。<p>
 *  							フォーマットごとの互換性は「VIDフォーマット」を参照してください。
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。
*/
int32_t AG903_VidMgrSetInputFormat(uint32_t format)
{
    switch (format) {
        case AG903_VID_MGR_24BIT_TO_CH0:
        case AG903_VID_MGR_8BITCH0_TO_CH0:
        case AG903_VID_MGR_8BITCH1_TO_CH1:
        case AG903_VID_MGR_8BITCH01_TO_CH01:
        case AG903_VID_MGR_8BITCH0_TO_CH0123:
            break;
        default:
            return -AG903_EINVAL;
    }

    if (CheckFormatCompatibility(format) != true) {
        return -AG903_EINVAL;
    }

    VidContext.vid_format = format;

    return AG903_ENONE;
}


/**
 * @brief         デジタルビデオ入力のハンドル取得 
 * @param         ports [in] 取得するポート番号を格納した配列。
 * @param         num_ports [in] portsの配列要素数（取得するハンドル数）。
 * @param         handles [out] 取得したハンドルを格納する配列。
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL portsに0-1の範囲外の値が指定された場合<p>num_portsに取得可能なハンドルの最大数以上の値が指定された場合<p>ports、handlesにNULLが指定された場合
 * @retval        -AG903_ENOMEM portsで指定されたポートに対応するハンドルが取得済の場合 
 * @description   入力ポート番号を指定して入力ポートハンドル(AG903_VidMgrInputHandle)を取得します。<p> 
 *  							指定された番号に対応するハンドルが未使用と判断された場合、handles にアドレスを返します。<p>
 *  							要求された番号のうち使用中の入力ポートが一つでも存在する場合、handles には何も格納しません。<p>
 *  							handles には ports で指定された番号順にハンドルを格納します。
*/
int32_t AG903_VidMgrGetInputHandle(int32_t *ports, int32_t num_ports, AG903_VidMgrInputHandle **handles)
{
    int32_t i;
    _Bool num_check[AG903_VID_MGR_MAX_IN_PORTS] = {false};

    if (num_ports > AG903_VID_MGR_MAX_IN_PORTS) {
        return -AG903_EINVAL;
    }
    if ((ports == NULL) || (handles == NULL)) {
        return -AG903_EINVAL;
    }
    for (i = 0; i < num_ports; i++) {
        if ((ports[i] < 0) || (ports[i] >= AG903_VID_MGR_MAX_IN_PORTS)) {
            return -AG903_EINVAL;
        }
        if (VidContext.used_in_ports[ports[i]] != false) {
            return -AG903_ENOMEM;
        }
        /* 同じ番号が指定された場合はエラー */
        if (num_check[ports[i]] == true) {
            return -AG903_EINVAL;
        }
        num_check[ports[i]] = true;
    }

    for (i = 0; i < num_ports; i++) {
        /* デジタルビデオ入力ハンドルをhandlesに格納して初期化 */
        handles[i] = (AG903_VidMgrInputHandle *)&VidContext.in_ports[ports[i]];
        handles[i]->id = AG903_VID_MGR_INPUT_HANDLE_ID;
        handles[i]->port_no = ports[i];
        handles[i]->is_dirty = false;
        handles[i]->sync_signal = 0;
        handles[i]->inout_vsync_pol = 0;
        handles[i]->inout_hsync_pol = 0;
        handles[i]->in_de_pol = 0;
        handles[i]->in_field_pol = 0;
        handles[i]->in_clk_pol = 0;
        handles[i]->h_pulse_width = 0x60;
        handles[i]->h_front_porch = 0x10;
        handles[i]->h_back_porch = 0x30;
        handles[i]->h_frame_size = 0x280;
        handles[i]->v_pulse_width = 0x2;
        handles[i]->v_front_porch = 0xA;
        handles[i]->v_back_porch = 0x21;
        handles[i]->v_frame_size = 0x1E0;
        /* 取得済のポートに状態遷移させる */
        VidContext.used_in_ports[ports[i]] = true;
    }
    return AG903_ENONE;
}


/**
 * @brief         デジタルビデオ入力のハンドル解放
 * @param         handle [in] 解放するデジタルビデオ入力ハンドル 
 * @return        解放結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ入力ハンドルが指定された場合 
 * @description   指定された入力ポートハンドルを解放します。<p> 
 *  							入力ポートハンドルは、port_no 以外全て 0 で初期化します。
 * @note          本関数をコールする場合は、前処理モジュールが停止していることを確認してください。 
*/
int32_t AG903_VidMgrReleaseInputHandle(AG903_VidMgrInputHandle *handle)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_INPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* 未得済のポートに状態遷移させる */
    VidContext.used_in_ports[handle->port_no] = false;

    /* port_no以外のメンバは0に初期化（idを0に初期化することで無効なハンドルに遷移させる） */
    handle->id = 0;
    handle->is_dirty = false;
    handle->sync_signal = 0;
    handle->inout_vsync_pol = 0;
    handle->inout_hsync_pol = 0;
    handle->in_de_pol = 0;
    handle->in_field_pol = 0;
    handle->in_clk_pol = 0;
    handle->h_pulse_width = 0;
    handle->h_front_porch = 0;
    handle->h_back_porch = 0;
    handle->h_frame_size = 0;
    handle->v_pulse_width = 0;
    handle->v_front_porch = 0;
    handle->v_back_porch = 0;
    handle->v_frame_size = 0;

    return AG903_ENONE;
}


/**
 * @brief         デジタルビデオ出力のハンドル取得 
 * @param         ports [in] 取得するポート番号を格納した配列。
 * @param         num_ports [in] portsの配列要素数（取得するハンドル数）。
 * @param         handles [out] 取得したハンドルを格納する配列。 
 * @return        取得結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL portsに0-3の範囲外の値が指定された場合<p>num_portsに取得可能なハンドルの最大数以上の値が指定された場合<p>ports、handlesにNULLが指定された場合
 * @retval        -AG903_ENOMEM portsで指定されたポートに対応するハンドルが取得済の場合 
 * @description   出力ポート番号を指定して出力ポートハンドル(AG903_VidMgrOutputHandle)を取得します。<p> 
 *  							指定された番号に対応するハンドルが未使用と判断された場合、handles にアドレスを返します。<p>
 *  							要求された番号のうち使用中の出力ポートが一つでも存在する場合、handles には何も格納しません。<p>
 *  							handles には ports で指定された番号順にハンドルを格納します。
 * @note    none
*/
int32_t AG903_VidMgrGetOutputHandle(int32_t *ports, int32_t num_ports, AG903_VidMgrOutputHandle **handles)
{
    int32_t i;
    _Bool num_check[AG903_VID_MGR_MAX_OUT_PORTS] = {false};

    if (num_ports > AG903_VID_MGR_MAX_OUT_PORTS) {
        return -AG903_EINVAL;
    }
    if ((ports == NULL) || (handles == NULL)) {
        return -AG903_EINVAL;
    }
    for (i = 0; i < num_ports; i++) {
        if ((ports[i] < 0) || (ports[i] >= AG903_VID_MGR_MAX_OUT_PORTS)) {
            return -AG903_EINVAL;
        }
        if (VidContext.used_out_ports[ports[i]] != false) {
            return -AG903_ENOMEM;
        }
        /* 同じ番号が指定された場合はエラー */
        if (num_check[ports[i]] == true) {
            return -AG903_EINVAL;
        }
        num_check[ports[i]] = true;
    }

    for (i = 0; i < num_ports; i++) {
        /* デジタルビデオ出力ハンドルをhandlesに格納して初期化 */
        handles[i] = (AG903_VidMgrOutputHandle *)&VidContext.out_ports[ports[i]];
        handles[i]->id = AG903_VID_MGR_OUTPUT_HANDLE_ID;
        handles[i]->port_no = ports[i];
        handles[i]->is_dirty = false;
        handles[i]->tdm = 0;
        handles[i]->delay = false;
        handles[i]->trs_dec_enable = false;
        handles[i]->trs_efp = 0;
        handles[i]->trs_ofp = 0;
        handles[i]->trs_vfp = 0x4;
        handles[i]->trs_href = 0;
        handles[i]->trs_hfp = 0;
        handles[i]->v_max = 8192;
        handles[i]->h_max = 8192;
        /* 取得済のポートに状態遷移させる */
        VidContext.used_out_ports[ports[i]] = true;
    }
    return AG903_ENONE;
}


/**
 * @brief         デジタルビデオ出力のハンドル解放
 * @param         handle [in] 解放するデジタルビデオ出力ハンドル。 
 * @return        解放結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ出力ハンドルが指定された場合 
 * @description   指定された出力ポートハンドルを解放します。<p>出力ポートハンドルは、port_no 以外全て 0 で初期化します。
 * @note          本関数をコールする場合は、前処理モジュールが停止していることを確認してください。 
*/
int32_t AG903_VidMgrReleaseOutputHandle(AG903_VidMgrOutputHandle *handle)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_OUTPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* 未得済のポートに状態遷移させる */
    VidContext.used_out_ports[handle->port_no] = false;

    /* port_no以外のメンバは0に初期化（idを0に初期化することで無効なハンドルに遷移させる） */
    handle->id = 0;
    handle->is_dirty = false;
    handle->tdm = 0;
    handle->delay = false;
    handle->trs_dec_enable = false;
    handle->trs_efp = 0;
    handle->trs_ofp = 0;
    handle->trs_vfp = 0;
    handle->trs_href = 0;
    handle->trs_hfp = 0;
    handle->v_max = 0;
    handle->h_max = 0;

    return AG903_ENONE;
}

/* TDMのレジスタ設定値を取りだすマクロ */
#define GET_TDMBLK(v)   ((v) & 0x1)
#define GET_TDMTRS(v)   (((v) >> 1) & 0x1)

/* 入出力パラメータの設定値を決定するマクロ */
#define GET_H_PULSE(v)  ((v) == AG903_VID_MGR_MAX_OUT_HORIZONTAL_PULSE_WIDTH ? 0 : (v))
#define GET_H_FPORCH(v) ((v) == AG903_VID_MGR_MAX_OUT_HORIZONTAL_FRONT_PORCH ? 0 : (v))
#define GET_H_BPORCH(v) ((v) == AG903_VID_MGR_MAX_OUT_HORIZONTAL_BACK_PORCH ? 0 : (v))
#define GET_H_FSIZE(v)  ((v) == AG903_VID_MGR_MAX_OUT_HORIZONTAL_FRAME_SIZE ? 0 : (v))
#define GET_V_PULSE(v)  ((v) == AG903_VID_MGR_MAX_OUT_VERTICAL_PULSE_WIDTH ? 0 : (v))
#define GET_V_FPORCH(v) ((v) == AG903_VID_MGR_MAX_OUT_VERTICAL_FRONT_PORCH ? 0 : (v))
#define GET_V_BPORCH(v) ((v) == AG903_VID_MGR_MAX_OUT_VERTICAL_BACK_PORCH ? 0 : (v))
#define GET_V_FSIZE(v)  ((v) == AG903_VID_MGR_MAX_OUT_VERTICAL_FRAME_SIZE ? 0 : (v))

/* TRSデコードへの設定値を決定するマクロ */
#define GET_TRS_VFP(v)  ((v) == AG903_VID_MGR_MAX_TRS_VFP ? 0 : (v))
#define GET_TRS_HFP(v)  (v)

/* 同期信号検出の設定値を決定するマクロ */
#define GET_VMAX(v)     ((v) == AG903_VID_MGR_MAX_SD_VERTICAL_CYCLE ? 0 : (v))
#define GET_HMAX(v)     ((v) == AG903_VID_MGR_MAX_SD_HORIZONTAL_CYCLE ? 0 : (v))

/**
 * @brief         デジタルビデオ入出力のハードウェア設定
 * @param         void
 * @return        転送結果  
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL 入力フォーマットと現在取得されている入出力ハンドルに互換性が無い場合 
 * @description   デジタルビデオ入出力の設定値をハードウェアに設定します。<p> 
 *  							内部データとして保持している設定値を本関数がコールされた時点でハードウェアに書き込みます。<p>
 *  							現在取得されている入力ポート/出力ポートのハンドルと設定されている入力フォーマットに互換性が無い場合エラーを返します。<p>
 *  							フォーマットごとの互換性は「VIDフォーマット」を参照してください。
*/
int32_t AG903_VidMgrCommitSetting(void)
{
    int32_t i;

    /* フォーマットと現在の入出力ハンドル取得条件に互換性があるかチェックします */
    if (CheckFormatCompatibility(VidContext.vid_format) != true) {
        return -AG903_EINVAL;
    }

    /*共通設定のパラメータをHWに転送します*/
    AG903_VidPrmSetVIDCTRL(VidContext.vid_enable);
    AG903_VidPrmSetVIDFMT(VidContext.vid_format);

    /* パラメータ更新が行なわれている入力ハンドルの設定をHWに転送します */
    for (i = 0; i < AG903_VID_MGR_MAX_IN_PORTS; i++) {
        AG903_VidMgrInputHandle *handle = (AG903_VidMgrInputHandle *)&VidContext.in_ports[i];
        if (VidContext.used_in_ports[i] == true && handle->is_dirty == true) {
            AG903_VidPrmSetVIDIOnCTRL(i, handle->sync_signal);

            VIDPrmParamVIDIOnMOD mod;
            mod.vpol = handle->inout_vsync_pol;
            mod.hpol = handle->inout_hsync_pol;
            mod.dpol = handle->in_de_pol;
            mod.fpol = handle->in_field_pol;
            mod.cpol = handle->in_clk_pol;
            AG903_VidPrmSetVIDIOnMOD(i, &mod);

            AG903_VidPrmSetVIDIOnOHPRM0(i, GET_H_PULSE(handle->h_pulse_width));
            AG903_VidPrmSetVIDIOnOHPRM1(i, GET_H_FPORCH(handle->h_front_porch), GET_H_BPORCH(handle->h_back_porch));
            AG903_VidPrmSetVIDIOnOVPRM0(i, GET_V_PULSE(handle->v_pulse_width));
            AG903_VidPrmSetVIDIOnOVPRM1(i, GET_V_FPORCH(handle->v_front_porch), GET_V_BPORCH(handle->v_back_porch));
            AG903_VidPrmSetVIDIOnOSIZE(i, GET_H_FSIZE(handle->v_frame_size), GET_V_FSIZE(handle->h_frame_size));
        }
    }
    /* パラメータ更新が行なわれている出力ハンドルの設定をHWに転送します */
    for (i = 0; i < AG903_VID_MGR_MAX_OUT_PORTS; i++) {
        AG903_VidMgrOutputHandle *handle = (AG903_VidMgrOutputHandle *)&VidContext.out_ports[i];
        if (VidContext.used_out_ports[i] == true && handle->is_dirty == true) {

            VIDPrmParamVIDCOnMOD mod;
            mod.tdmblk = GET_TDMBLK(handle->tdm);
            mod.tdmtrs = GET_TDMTRS(handle->tdm);
            mod.delay  = handle->delay;
            mod.trsdec = handle->trs_dec_enable;
            AG903_VidPrmSetVIDCOnMOD(i, &mod);

            VIDPrmParamVIDCOnTRSPRM trsprm;
            trsprm.efp  = handle->trs_efp;
            trsprm.ofp  = handle->trs_ofp;
            trsprm.vfp  = GET_TRS_VFP(handle->trs_vfp);
            trsprm.href = handle->trs_href;
            trsprm.hfp  = GET_TRS_HFP(handle->trs_hfp);
            AG903_VidPrmSetVIDCOnTRSPRM(i, &trsprm);

            AG903_VidPrmSetVIDCOnSDPRM(i, GET_VMAX(handle->v_max), GET_HMAX(handle->h_max));
        }
    }

    return AG903_ENONE;
}


/**
 * @brief         指定したハンドルと現在の入力フォーマットとの互換性をチェック
 * @param         handle [in] 互換性をチェックする入力ハンドルまたは、出力ハンドルを指定します。
 * @param         handle_type [in] handleに指定したハンドルのタイプ(入力ハンドルまたは、出力ハンドル)を指定します。 
 * @return        互換性チェック結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なハンドルが指定された場合<p>handle_typeに不正な値が指定された場合<p>指定したハンドルが現在の入力フォーマットと互換性が無い場合
 * @description   現在設定されている入力フォーマットと指定されたハンドルの互換性をチェックします。<p> 
 *  							ハンドルタイプ(VIDハンドルタイプ)により入出力を判別します。<p>
 *  							フォーマットごとの互換性は「VIDフォーマット」を参照してください。<p>
 *  							互換性に適応している場合、有効なハンドルを返します。
*/
int32_t AG903_VidMgrCheckHandleValidation(void *handle, int32_t handle_type)
{
    uint32_t port_no;
    AG903_VidMgrInputHandle *input_handle = (AG903_VidMgrInputHandle *)handle;
    AG903_VidMgrOutputHandle *output_handle = (AG903_VidMgrOutputHandle *)handle;

    switch (handle_type) {
        case AG903_VID_MGR_INPUT_HANDLE:
            if ((handle == NULL) || (input_handle->id != AG903_VID_MGR_INPUT_HANDLE_ID)) {
                return -AG903_EINVAL;
            }
            port_no = input_handle->port_no;
            break;
        case AG903_VID_MGR_OUTPUT_HANDLE:
            if ((handle == NULL) || (output_handle->id != AG903_VID_MGR_OUTPUT_HANDLE_ID)) {
                return -AG903_EINVAL;
            }
            port_no = output_handle->port_no;
            break;
        default:
            return -AG903_EINVAL;
    }

    /* 現在のフォーマットとの互換性をチェックします */
    switch (VidContext.vid_format) {
        case AG903_VID_MGR_24BIT_TO_CH0:
        case AG903_VID_MGR_8BITCH0_TO_CH0:
            if ((handle_type == AG903_VID_MGR_INPUT_HANDLE && port_no != 0) ||
                (handle_type == AG903_VID_MGR_OUTPUT_HANDLE && port_no != 0)){
                return -AG903_EINVAL;
            }
            break;
        case AG903_VID_MGR_8BITCH1_TO_CH1:
            if ((handle_type == AG903_VID_MGR_INPUT_HANDLE && port_no != 1) ||
                (handle_type == AG903_VID_MGR_OUTPUT_HANDLE && port_no != 1)){
                return -AG903_EINVAL;
            }
            break;
        case AG903_VID_MGR_8BITCH01_TO_CH01:
            if ((handle_type == AG903_VID_MGR_OUTPUT_HANDLE && (port_no != 0 && port_no != 1))) {
                return -AG903_EINVAL;
            }
            break;
        case AG903_VID_MGR_8BITCH0_TO_CH0123:
        default:
            if ((handle_type == AG903_VID_MGR_INPUT_HANDLE && port_no != 0)) {
                return -AG903_EINVAL;
            }
            break;
    }
    return AG903_ENONE;
}


/**
 * @brief         デジタルビデオ入力の同期信号入出力設定
 * @param         handle [in] デジタルビデオ入力ハンドル。
 * @param         inout [in] 同期信号の入力、出力を指定します。 
 * @return        入出力設定結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ入力ハンドルが指定された場合<p>inoutに不正な値が指定された場合 
 * @description   同期信号の入力/出力を設定します。<p>入出力設定は「VID信号入出力」を参照してください。 
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。
*/
int32_t AG903_VidMgrSetIOSignal(AG903_VidMgrInputHandle *handle, uint32_t inout)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_INPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* inoutに不正な値が指定された場合はエラーとします */
    switch (inout) {
        case AG903_VID_MGR_IO_SIGNAL_INPUT:
        case AG903_VID_MGR_IO_SIGNAL_OUTPUT:
            break;
        default:
            return -AG903_EINVAL;
    }

    /* パラメータを保持し、dirtyフラグをセットします */
    handle->sync_signal = inout;
    handle->is_dirty = true;

    return AG903_ENONE;
}


/**
 * @brief         デジタルビデオ入力の動作モード設定
 * @param         handle [in] デジタルビデオ入力ハンドル。
 * @param         v_pol [in] 入出力VSYNCの極性を指定します。
 * @param         h_pol [in] 入出力HSYNCの極性を指定します。
 * @param         d_pol [in] 入力DEの極性を指定します。
 * @param         f_pol [in] 入力FEILDの極性を指定します。
 * @param         c_pol [in] 入力クロックの極性を指定します。 
 * @return        設定結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ入力ハンドルが指定された場合<p>v_pol/h_pol/d_pol/f_pol/c_polに不正な値が指定された場合
 * @description   動作モードを設定します。<p> 
 *                指定パラメータについては以下を参照してください。 
 *                <table>
 *                <tr><th>対象パラメータ</th><th>参照先</th></tr>
 *                <tr><td>v_pol</td><td>VIDVSYNC極性</td></tr>
 *                <tr><td>h_pol</td><td>VIDHSYNC極性</td></tr>
 *                <tr><td>d_pol</td><td>VIDDE極性</td></tr>
 *                <tr><td>f_pol</td><td>VIDFIELD極性</td></tr>
 *                <tr><td>c_pol</td><td>VID入力クロック極性</td></tr>
 *                </table>
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。
*/
int32_t AG903_VidMgrSetIOMode(AG903_VidMgrInputHandle *handle, uint32_t v_pol, uint32_t h_pol, uint32_t d_pol, uint32_t f_pol, uint32_t c_pol)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_INPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* v_polに不正な値が指定された場合はエラーとします */
    switch (v_pol) {
        case AG903_VID_MGR_IO_VSYNC_POL_MINUS:
        case AG903_VID_MGR_IO_VSYNC_POL_PLUS:
            break;
        default:
            return -AG903_EINVAL;
    }
    /* h_polに不正な値が指定された場合はエラーとします */
    switch (h_pol) {
        case AG903_VID_MGR_IO_HSYNC_POL_MINUS:
        case AG903_VID_MGR_IO_HSYNC_POL_PLUS:
            break;
        default:
            return -AG903_EINVAL;
    }
    /* d_polに不正な値が指定された場合はエラーとします */
    switch (d_pol) {
        case AG903_VID_MGR_IN_DE_POL_MINUS:
        case AG903_VID_MGR_IN_DE_POL_PLUS:
            break;
        default:
            return -AG903_EINVAL;
    }
    /* f_polに不正な値が指定された場合はエラーとします */
    switch (f_pol) {
        case AG903_VID_MGR_IN_FIELD_POL_MINUS:
        case AG903_VID_MGR_IN_FIELD_POL_PLUS:
            break;
        default:
            return -AG903_EINVAL;
    }
    /* c_polに不正な値が指定された場合はエラーとします */
    switch (c_pol) {
        case AG903_VID_MGR_IN_CLK_POL_MINUS:
        case AG903_VID_MGR_IN_CLK_POL_PLUS:
            break;
        default:
            return -AG903_EINVAL;
    }

    /* パラメータを保持し、dirtyフラグをセットします */
    handle->inout_vsync_pol = v_pol;
    handle->inout_hsync_pol = h_pol;
    handle->in_de_pol = d_pol;
    handle->in_field_pol = f_pol;
    handle->in_clk_pol = c_pol;
    handle->is_dirty = true;

    return AG903_ENONE;
}


/**
 * @brief         デジタルビデオ入力のパラメータ設定
 * @param         h_pw [in] 水平同期信号パルス幅を指定します。
 * @param         h_fp [in] 水平フロントポーチを指定します。
 * @param         h_bp [in] 水平バックポーチを指定します。
 * @param         h_fs [in] 水平フレームサイズを指定します。
 * @param         v_pw [in] 垂直同期信号パルス幅を指定します。
 * @param         v_fp [in] 垂直フロントポーチを指定します。
 * @param         v_bp [in] 垂直バックポーチを指定します。
 * @param         v_fs [in] 垂直フレームサイズを指定します。 
 * @return        パラメータ設定結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ入力ハンドルが指定された場合
 * @retval        -AG903_EINVAL h_pw/h_fp/h_bp/h_fsl/v_pw/v_fp/v_bp/v_fslに不正な値が指定された場合
 * @description   同期信号の出力パラメータを設定します。<p> 
 *                <table>
 *                <tr><th>設定パラメータ</th><th>有効範囲</th></tr>
 *                <tr><td>h_pw</td><td>1 ~ AG903_VID_MGR_MAX_OUT_HORIZONTAL_PULSE_WIDTH</td></tr>
 *  							<tr><td>h_fp</td><td>1 ~ AG903_VID_MGR_MAX_OUT_HORIZONTAL_FRONT_PORCH</td></tr>
 *  							<tr><td>h_bp</td><td>1 ~ AG903_VID_MGR_MAX_OUT_HORIZONTAL_BACK_PORCH</td></tr>
 *  							<tr><td>h_fsl</td><td>1 ~ AG903_VID_MGR_MAX_OUT_HORIZONTAL_FRAME_SIZE</td></tr>
 *  							<tr><td>v_pw</td><td>1 ~ AG903_VID_MGR_MAX_OUT_VERTICAL_PULSE_WIDTH</td></tr>
 *  							<tr><td>v_fp</td><td>1 ~ AG903_VID_MGR_MAX_OUT_VERTICAL_FRONT_PORCH</td></tr>
 *  							<tr><td>v_bp</td><td>1 ~ AG903_VID_MGR_MAX_OUT_VERTICAL_BACK_PORCH</td></tr>
 *  							<tr><td>v_fsl</td><td>1 ~ AG903_VID_MGR_MAX_OUT_VERTICAL_FRAME_SIZE</td></tr>
 *  							</table>
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。
*/
int32_t AG903_VidMgrSetIOParameter(AG903_VidMgrInputHandle *handle, uint32_t h_pw, uint32_t h_fp, uint32_t h_bp, uint32_t h_fs, uint32_t v_pw, uint32_t v_fp, uint32_t v_bp, uint32_t v_fs)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_INPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* h_pwに不正な値が指定された場合はエラーとします */
    if (h_pw == 0 || h_pw > AG903_VID_MGR_MAX_OUT_HORIZONTAL_PULSE_WIDTH) {
        return -AG903_EINVAL;
    }
    /* h_fpに不正な値が指定された場合はエラーとします */
    if (h_fp == 0 || h_fp > AG903_VID_MGR_MAX_OUT_HORIZONTAL_FRONT_PORCH) {
        return -AG903_EINVAL;
    }
    /* h_bpに不正な値が指定された場合はエラーとします */
    if (h_bp == 0 || h_bp > AG903_VID_MGR_MAX_OUT_HORIZONTAL_BACK_PORCH) {
        return -AG903_EINVAL;
    }
    /* h_fsに不正な値が指定された場合はエラーとします */
    if (h_fs == 0 || h_fs > AG903_VID_MGR_MAX_OUT_HORIZONTAL_FRAME_SIZE) {
        return -AG903_EINVAL;
    }
    /* v_pwに不正な値が指定された場合はエラーとします */
    if (v_pw == 0 || v_pw > AG903_VID_MGR_MAX_OUT_VERTICAL_PULSE_WIDTH) {
        return -AG903_EINVAL;
    }
    /* v_pwに不正な値が指定された場合はエラーとします */
    if (v_fp == 0 || v_fp > AG903_VID_MGR_MAX_OUT_VERTICAL_FRONT_PORCH) {
        return -AG903_EINVAL;
    }
    /* v_bpに不正な値が指定された場合はエラーとします */
    if (v_bp == 0 || v_bp > AG903_VID_MGR_MAX_OUT_VERTICAL_BACK_PORCH) {
        return -AG903_EINVAL;
    }
    /* v_fsに不正な値が指定された場合はエラーとします */
    if (v_fs == 0 || v_fs > AG903_VID_MGR_MAX_OUT_VERTICAL_FRAME_SIZE) {
        return -AG903_EINVAL;
    }

    /* パラメータを保持し、dirtyフラグをセットします */
    handle->h_pulse_width = h_pw;
    handle->h_front_porch = h_fp;
    handle->h_back_porch = h_bp;
    handle->h_frame_size = h_fs;
    handle->v_pulse_width = v_pw;
    handle->v_front_porch = v_fp;
    handle->v_back_porch = v_bp;
    handle->v_frame_size = v_fs;
    handle->is_dirty = true;

    return AG903_ENONE;
}


/**
 * @brief         デジタルビデオ入力のドットクロックステータス取得 
 * @param         handle [in] デジタルビデオ入力ハンドル。
 * @param         cwt [out] ドットクロックのステータスを格納するポインタを指定します。 
 * @return        ステータス取得結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ入力ハンドルが指定された場合 
 * @description   ドットクロックのステータスを取得します。<p> 
 *  							取得したデータを cwt に格納します。<p>
 *  							cwt==NULL の場合は何もしません。
*/
int32_t AG903_VidMgrGetIODotClk(AG903_VidMgrInputHandle *handle, uint32_t *cwt)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_INPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* Primitive Layerの関数を使用して取得します */
    if (cwt != NULL) {
        AG903_VidPrmGetVIDIOnSTAT(handle->port_no, cwt);
    }

    return AG903_ENONE;
}


/**
 * @brief         デジタルビデオ出力チャンネルモードの4bitTDM設定
 * @param         handle [in] デジタルビデオ入力ハンドル。
 * @param         tdm [in] 出力チャンネルのTDMモードを指定します。 
 * @return        設定結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ出力ハンドルが指定された場合<p>tdmに不正な値が指定された場合 
 * @description   キャプチャ出力チャンネル動作モードの 4bit TDM を設定します。<p> 
 *                モード設定は「VIDTDMモード」を参照してください。 
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。
*/
int32_t AG903_VidMgrSetCaptureTDMMode(AG903_VidMgrOutputHandle *handle, uint32_t tdm)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_OUTPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* tdmに不正な値が指定された場合はエラーとします */
    switch (tdm) {
        case AG903_VID_MGR_TDM_NONE:
        case AG903_VID_MGR_TDM_FIT_BLANK_SIGNAL:
        case AG903_VID_MGR_TDM_FIT_TRS_SIGNAL:
            break;
        default:
            return -AG903_EINVAL;
    }

    /* パラメータを保持し、dirtyフラグをセットします */
    handle->tdm = tdm;
    handle->is_dirty = true;

    return AG903_ENONE;
}


/**
 * @brief         入力データ遅延の有効/無効設定
 * @param         handle [in] デジタルビデオ入力ハンドル。
 * @param         delay [in] 遅延設定の有効無効を指定します。 
 * @return        設定結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ出力ハンドルが指定された場合 
 * @description   入力データ遅延の有効/無効を設定します。 
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。
*/
int32_t AG903_VidMgrEnableCaptureDelay(AG903_VidMgrOutputHandle *handle, _Bool delay)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_OUTPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* パラメータを保持し、dirtyフラグをセットします */
    handle->delay = delay;
    handle->is_dirty = true;

    return AG903_ENONE;
}


/**
 * @brief         TRS デコードの有効/無効設定
 * @param         handle [in] デジタルビデオ入力ハンドル。
 * @param         trs_dec [in] TRS デコードの有効/無効を指定します。 
 * @return        設定結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ出力ハンドルが指定された場合 
 * @description   出力ポートの TRS デコードの有効/無効を設定します。 
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。
*/
int32_t AG903_VidMgrEnableTRSDecode(AG903_VidMgrOutputHandle *handle, _Bool trs_dec)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_OUTPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* パラメータを保持し、dirtyフラグをセットします */
    handle->trs_dec_enable = trs_dec;
    handle->is_dirty = true;

    return AG903_ENONE;
}


/**
 * @brief         出力ポートの TRS デコードのパラメータ設定
 * @param         handle [in] デジタルビデオ入力ハンドル。
 * @param         efp [in] インタレースモードでEVENフレームのVPFの調整を指定します。
 * @param         ofp [in] インタレースモードでODDフレームのVPFの調整を指定します。
 * @param         vfp [in] ブランク期間開始のSAV/EAVからVSYNC立ち上がりFIELD値反映までのサイクル数を指定します。
 * @param         href [in] HSYNC生成の基準を指定します。
 * @param         hfp [in] SAV/EAVからHSYNC立ち上がりまでのサイクル数を指定します。
 * @return        設定結果
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handle/efp/ofp/vfp/href/hfpに不正なデジタルビデオ出力ハンドルが指定された場合
 * @description   出力ポートの TRS　デコードのパラメータを設定します。<p> 
 *                指定可能な値の範囲については、以下を参照してください。<p> 
 *                <table>
 *                <tr><th>設定パラメータ</th><th>有効範囲</th></tr>
 *                <tr><td>efp</td><td>VIDEvenFrame</td></tr>
 *  							<tr><td>ofp</td><td>VIDOddFrame</td></tr>
 *  							<tr><td>vfp</td><td>1 ~ AG903_VID_MGR_MAX_TRS_VFP</td></tr>
 *  							<tr><td>href</td><td>VIDHReference</td></tr>
 *  							<tr><td>hfp</td><td>1 ~ AG903_VID_MGR_MAX_TRS_HFP</td></tr>
 *  							</table>
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。<P>
 *                8ビット入力の場合、hfpへの奇数設定は禁止です。
*/
int32_t AG903_VidMgrSetTRSParameter(AG903_VidMgrOutputHandle *handle, uint32_t efp, uint32_t ofp, uint32_t vfp, uint32_t href, uint32_t hfp)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_OUTPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* efに不正な値が指定された場合はエラーとします */
    switch (efp) {
        case AG903_VID_MGR_TRS_EFP_ZERO:
        case AG903_VID_MGR_TRS_EFP_ONE:
            break;
        default:
            return -AG903_EINVAL;
    }
    /* ofに不正な値が指定された場合はエラーとします */
    switch (ofp) {
        case AG903_VID_MGR_TRS_OFP_ZERO:
        case AG903_VID_MGR_TRS_OFP_ONE:
            break;
        default:
            return -AG903_EINVAL;
    }
    /* vfpに不正な値が指定された場合はエラーとします */
    if (vfp == 0 || vfp > AG903_VID_MGR_MAX_TRS_VFP) {
        return -AG903_EINVAL;
    }
    /* hrefに不正な値が指定された場合はエラーとします */
    switch (href) {
        case AG903_VID_MGR_TRS_HREF_EAV:
        case AG903_VID_MGR_TRS_HREF_SAV:
            break;
        default:
            return -AG903_EINVAL;
    }
    /* hfpに不正な値が指定された場合はエラーとします */
    if (hfp > AG903_VID_MGR_MAX_TRS_HFP) {
        return -AG903_EINVAL;
    }

    /* パラメータを保持し、dirtyフラグをセットします */
    handle->trs_efp = efp;
    handle->trs_ofp = ofp;
    handle->trs_vfp = vfp;
    handle->trs_href = href;
    handle->trs_hfp = hfp;
    handle->is_dirty = true;

    return AG903_ENONE;
}


/**
 * @brief         出力ポートの同期信号検出パラメータ設定
 * @param         handle [in] デジタルビデオ入力ハンドル。
 * @param         v_max [in] 垂直同期の最大サイクル数を指定します。
 * @param         h_max [in] 水平同期の最大サイクル数を指定します。 
 * @return        設定結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handle/v_max/h_maxに不正なデジタルビデオ出力ハンドルが指定された場合
 * @description   出力ポートの同期信号検出パラメータを設定します。<p> 
 *                指定可能な値の範囲については、以下を参照してください。<p> 
 *                <table>
 *                <tr><th>設定パラメータ</th><th>有効範囲</th></tr>
 *  							<tr><td>v_max</td><td>1 ~ AG903_VID_MGR_MAX_SD_VERTICAL_CYCLE</td></tr>
 *  							<tr><td>h_max</td><td>1 ~ AG903_VID_MGR_MAX_SD_HORIZONTAL_CYCLE</td></tr>
 *  							</table>
 * @note          本関数をコールした時点ではハードウェアアクセスは行わず、内部データとして保持します。
*/
int32_t AG903_VidMgrSetDetectionCycle(AG903_VidMgrOutputHandle *handle, uint32_t v_max, uint32_t h_max)
{
    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_OUTPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* v_maxに不正な値が指定された場合はエラーとします */
    if (v_max == 0 || v_max > AG903_VID_MGR_MAX_SD_VERTICAL_CYCLE) {
        return -AG903_EINVAL;
    }
    /* h_maxに不正な値が指定された場合はエラーとします */
    if (h_max == 0 || h_max > AG903_VID_MGR_MAX_SD_HORIZONTAL_CYCLE) {
        return -AG903_EINVAL;
    }

    /* パラメータを保持し、dirtyフラグをセットします */
    handle->v_max = v_max;
    handle->h_max = h_max;
    handle->is_dirty = true;

    return AG903_ENONE;
}


/**
 * @brief         出力ポートの各種ステータス取得 
 * @param         handle [in] デジタルビデオ入力ハンドル。
 * @param         blk_val [out] 出力チャンネルのEAV直後のブランク信号を格納するポインタを指定します。
 * @param         trs_val [out] 出力チャンネルのTRSの4byte目を格納するポインタを指定します。
 * @param         v_blank [out] 垂直同期信号入力状態を格納するポインタを指定します。
 * @param         h_blank [out] 水平同期信号入力状態を格納するポインタを指定します。
 * @param         tdm_ch [out] 4chTDM入力でチャンネル自動設定の結果を格納するポインタを指定します。 
 * @return        取得結果 
 * @retval        AG903_ENONE 正常終了
 * @retval        -AG903_EINVAL handleに不正なデジタルビデオ出力ハンドルが指定された 
 * @description   出力ポートの各種ステータスを取得します。<p> 
 *  							ステータスは各種引数のポインタに格納します。<p>
 *  							NULL の場合は格納しません。
*/
int32_t AG903_VidMgrGetOutputState(AG903_VidMgrOutputHandle *handle, uint32_t *blk_val, uint32_t *trs_val, uint32_t *v_blank, uint32_t *h_blank, uint32_t *tdm_ch)
{
    VIDPrmParamVIDCOnSTAT stat;

    /* ハンドルのIDが不正な場合は無効なハンドルとして処理します */
    if ((handle == NULL) || (handle->id != AG903_VID_MGR_OUTPUT_HANDLE_ID)) {
        return -AG903_EINVAL;
    }

    /* Primitive Layerの関数を使用して取得します */
    AG903_VidPrmGetVIDCOnSTAT(handle->port_no, &stat);

    /* NULL以外の引数に値を格納します */
    if (blk_val != NULL) {
        *blk_val = stat.blkval;
    }
    if (trs_val != NULL) {
        *trs_val = stat.trsval;
    }
    if (v_blank != NULL) {
        *v_blank = stat.vblank;
    }
    if (h_blank != NULL) {
        *h_blank = stat.hblank;
    }
    if (tdm_ch != NULL) {
        *tdm_ch = stat.tdmch;
    }

    return AG903_ENONE;
}


