/************************************************************
**
**     Object name : rasp-netapi-da
**
 **     Public      : WsDaHandleOpen
 **                   WsDaHandleClose
**                   
 **                   WsSetDaFreq
 **                   WsGetDaFreq
 **                   WsDaStart
 **                   WsDaStop
**
 **                   WsDaReady
 **                   WsDaStopWait
**                   
 **                   WsGetDaStatus
**                   
 **                   WsSetDaLoopBackChannel
 **                   WsGetDaLoopBackChannel
 **                   WsSetDaMode
 **                   WsGetDaMode
**
 **                   WsSetDaChannelMode
 **                   WsGetDaChannelMode
 **                   WsGetDaChannelNum
**
 **                   WsSetDaMute
 **                   WsGetDaMute
 **                   WsSetDaGain
 **                   WsGetDaGain
**
 **                   WsDaDataWrite
 **                   WsDaDefaultDataWrite
**                   RASP_WL_WsDaFloatDataWrite
 **                   WsSetDaDataFormat
 **                   WsGetDaDataFormat
**
**
**
**     Private     : 
**
**     Description
**     -- -- -- -- -- -- -- --
**     RASP-24をネットワーク経由で利用するためのAPI（D/A）
**
**     History
**     -- -- -- -- -- -- -- --
**     2011.05.06 K.Takagi WsDaHandleOpenを修正
**                           AS-RASP時の出力初期値を設定
**                           ループバックチャネルの状態を取得
**                         AS-RASPのGain設定で0dBの処理を修正
**     2011.04.14 K.Takagi WsDaHandleOpenを修正
**                         WsSetDaDataFormatを修正
**                         WsSetDaMuteを修正
**                         WsGetDaMuteを修正
**                         WsSetDaGainを修正
**                         WsGetDaGainを修正
**     2011.04.12 K.Takagi 統合化のために整理
**     2011.02.07 K.Takagi コメント類を整備
**     2010.10.21 K.Takagi 新規作成
**                         従来のシステムをベースに移植
**
**     Copyright (c) 2010-2011
**     System In Frontier,Inc.
**     All rights reserved. 
**
**     当社の許可なしに複製および転載を禁ず
**
*/


/*=========================================================*/
/*               Special Macro Definition                  */
/*=========================================================*/


/*=========================================================*/
/*                   Include Files                         */
/*=========================================================*/

/*=========================================================*/
/*                   Macro Definition                      */
/*=========================================================*/
#define DA_WORK_BUFFER_SIZE (128 * 1024)

#define DA_R_LOOP_CH_MASK         0x000000FF
#define DA_L_LOOP_CH_MASK         0x0000FF00
#define DA_R_LOOP_CH_SHIFT        0
#define DA_L_LOOP_CH_SHIFT        8

#define DA_R_LOOP_MODE_MASK       0x00010000
#define DA_L_LOOP_MODE_MASK       0x00020000
#define DA_R_LOOP_MODE_SHIFT      16
#define DA_L_LOOP_MODE_SHIFT      17

#define DA_R_OUTPUT_ENABLE_MASK   0x01000000
#define DA_L_OUTPUT_ENABLE_MASK   0x02000000
#define DA_R_OUTPUT_ENABLE_SHIFT  24
#define DA_L_OUTPUT_ENABLE_SHIFT  25

#define DA_OUTPUT_DEFAULT         ( (DA_OUTPUT_ENABLE << DA_L_OUTPUT_ENABLE_SHIFT) | \
                                    (DA_OUTPUT_ENABLE << DA_R_OUTPUT_ENABLE_SHIFT) | \
                                    (DA_NORMAL_MODE   << DA_L_LOOP_MODE_SHIFT)     | \
                                    (DA_NORMAL_MODE   << DA_R_LOOP_MODE_SHIFT)     | \
                                    (0                << DA_L_LOOP_CH_SHIFT)       | \
                                    (0                << DA_R_LOOP_CH_SHIFT) )


/*=========================================================*/
/*                 Structure Declaration                   */
/*=========================================================*/

/*=========================================================*/
/*                    Private Valiable                     */
/*=========================================================*/

/*=========================================================*/
/*                    Public Valiable                      */
/*=========================================================*/


/*=========================================================*/
/*                   Private Functions                     */
/*=========================================================*/
int WsDaDefaultDataWrite(WS_HANDLE_t *h_ws, char *buffer, size_t write_req_size);
int RASP_WL_WsDaFloatDataWrite(WS_HANDLE_t *h_ws, char *buffer, size_t write_req_size);

#ifdef WIN32
#else
int (*WsDaDataWrite)(WS_HANDLE_t *h_ws, char *buffer, size_t write_req_size) = &WsDaDefaultDataWrite;
#endif

/*----------------------------------------------------------*/
/*                          共通                            */
/*----------------------------------------------------------*/


/************************************************************
**
**  Public  : 
**
**  History : 2011.05.06 K.Takagi AS-RASP時の出力チャネルの初期化を追加
**                                ループバックチャネルの状態を取得（内部では使用しないが一応）
**            2011.04.14 K.Takagi AS-RASP対応
**            2010.10.21 K.Takagi 新規作成
**
**  Description
**  -----------
**  DA制御とDAデータ通信用のハンドルの作成
**
*/

WS_HANDLE_t *WsDaHandleOpen(char *ip_addr)
{
    int status;
    int get_val;
    int board_num;
    WS_HANDLE_t *h_ws;

#ifdef CONV_INET_ADDR_MODE
    in_addr_t server_ip_addr;
#else
    struct in_addr server_ip_addr;
#endif
    
    char buffer[CMD_STRING_LENGTH];
    char str[CMD_STRING_LENGTH];
    
#ifdef WIN32
    {
        WSADATA wsa_data;
        
        /* 初期化 */
        status = WSAStartup(MAKEWORD(WIN_SOCK_MAJOR_VERSION, WIN_SOCK_MINOR_VERSION), &wsa_data);
        if(status != 0) 
        {
            printf("WSAStartup Error. (%d)\n", status);
            return NULL;
        }
    }
#endif

    /* 制御サーバのIPアドレスを変換 */
#ifdef CONV_INET_ADDR_MODE
    server_ip_addr = inet_addr(ip_addr);
    if(server_ip_addr == -1)
    {
        printf("Server IP Address Error.\n");
        printf("  %s ??\n", ip_addr);
        goto HANDLE_OPEN_ERR1;
    }
#else
    status = inet_aton(ip_addr, &server_ip_addr);
    if(status == 0)
    {
        printf("Server IP Address Error.\n");
        printf("  %s ??\n", ip_addr);
        goto HANDLE_OPEN_ERR1;
    }
#endif

    /* ハンドル用のメモリを確保 */
    h_ws = (WS_HANDLE_t *)malloc(sizeof(WS_HANDLE_t));
    if(h_ws == NULL)
    {
        printf("Memory Allocate Error.\n");
        goto HANDLE_OPEN_ERR1;
    }
    memset(h_ws, 0, sizeof(WS_HANDLE_t));


    /* 制御用ソケットの作成 */
    h_ws->control_server_info.socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(h_ws->control_server_info.socket_fd == -1)
    {
        printf("Control Socket Create Error.\n");
        goto HANDLE_OPEN_ERR2;
    }


    /* 制御用ソケットの構造体を初期化 */
    h_ws->control_server_info.socket_addr_size = sizeof(struct sockaddr_in);

    h_ws->control_server_info.socket_addr.sin_family      = AF_INET;
    h_ws->control_server_info.socket_addr.sin_port        = htons(WS_DA_CONTROL_PORT);
#ifdef CONV_INET_ADDR_MODE
    h_ws->control_server_info.socket_addr.sin_addr.s_addr = server_ip_addr;
#else
    h_ws->control_server_info.socket_addr.sin_addr.s_addr = server_ip_addr.s_addr;
#endif


    /* 制御サーバに接続 */
    status = connect(h_ws->control_server_info.socket_fd, 
                     (struct sockaddr *)&(h_ws->control_server_info.socket_addr),
                     h_ws->control_server_info.socket_addr_size);
    if(status == -1)
    {
        printf("Control Socket Connection Error.\n");
        goto HANDLE_OPEN_ERR3;
    }


    /* 接続相手の判別                                       */
    /* このタイミングでコマンドを送信するとデータ用タスクが */
    /* 起動する前にコントロール用のタスクの起動が確実になる */

    /* 送信する文字列（コマンド）を作成 */
    sprintf(buffer, "0x%08x %d", WS_CMD_GET_SYSTEM_INFO, WS_SUB_CMD_GET_TARGET_INFO);

    /* 文字列（コマンド）を返信 */
    write(h_ws->control_server_info.socket_fd, buffer, strlen(buffer)+1);

    /* ステータス受信 */
    read(h_ws->control_server_info.socket_fd, buffer, CMD_STRING_LENGTH);
    
    sscanf(buffer, "%*s %d", &status);
    if(status == 0)
    {
        sscanf(buffer, "%*s %*s %s", str);
        LOG_PRINT("WS_CMD_GET_SYSTEM_INFO Support.\n");
        
        if(strstr(str, "AS-RASP2") != NULL)
        {
            /* 改修後のAS-RASP（コアバージョン 2.x.x） */
            LOG_PRINT("Connect AS-RASP2(0x%08x)\n", status);
            h_ws->target_type = TARGET_TYPE_AS_RASP;
            h_ws->target_sub_type = 2;
        }
        else if(strstr(str, "AS-RASP") != NULL)
        {
            LOG_PRINT("Connect AS-RASP(0x%08x)\n", status);
            h_ws->target_type = TARGET_TYPE_AS_RASP;
        }
        else if(strstr(str, "RASP24") != NULL)
        {
            LOG_PRINT("Connect RASP24(0x%08x)\n", status);
            h_ws->target_type = TARGET_TYPE_RASP24;
        }
        else
        {
            LOG_PRINT("Connect RASP Wireless\n");
            h_ws->target_type = TARGET_TYPE_RASP_WL;
        }
    }
    else
    {
        /* コマンドがサポートされていなければ無線RASP */
        LOG_PRINT("Connect RASP Wireless\n");

        h_ws->target_type = TARGET_TYPE_RASP_WL;
    }


    /* データ用ソケットの作成 */
    h_ws->data_server_info.socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if(h_ws->data_server_info.socket_fd == -1)
    {
        printf("Data Socket Create Error.\n");
        goto HANDLE_OPEN_ERR3;
    }


    /* データ用ソケットの構造体を初期化 */
    h_ws->data_server_info.socket_addr_size = sizeof(struct sockaddr_in);

    h_ws->data_server_info.socket_addr.sin_family      = AF_INET;
    h_ws->data_server_info.socket_addr.sin_port        = htons(WS_DA_DATA_PORT);
#ifdef CONV_INET_ADDR_MODE
    h_ws->data_server_info.socket_addr.sin_addr.s_addr = server_ip_addr;
#else
    h_ws->data_server_info.socket_addr.sin_addr.s_addr = server_ip_addr.s_addr;
#endif

    /* データサーバに接続 */
    status = connect(h_ws->data_server_info.socket_fd, 
                     (struct sockaddr *)&(h_ws->data_server_info.socket_addr),
                     h_ws->data_server_info.socket_addr_size);
    if(status == -1)
    {
        printf("Data Socket Connection Error.\n");
        goto HANDLE_OPEN_ERR4;
    }

    h_ws->server_ip_addr = server_ip_addr;

    
    h_ws->max_ch_num = 2;
    h_ws->ch_num     = 2;
    h_ws->board_num  = 1;
    h_ws->ch_mode    = DA_STEREO_MODE;
#if 0
    h_ws->da_l_loop_mode = DA_NORMAL_MODE;
    h_ws->da_r_loop_mode = DA_NORMAL_MODE;
#endif
    
    if(h_ws->target_type == TARGET_TYPE_AS_RASP)
    {
        if(h_ws->target_sub_type >= 2)
        {
            /* 改修後のAS-RASPは非対応 */
            printf("UnSupported Target(Type = %d, SubType = %d).\n", h_ws->target_type, h_ws->target_sub_type);
            goto HANDLE_OPEN_ERR4;
        }
        h_ws->data_format    = DATA_FORMAT_32BIT_PCM;
        h_ws->resolution_bit = 32;
        h_ws->work_buffer    = NULL;
        h_ws->enable_channels[0] = DA_OUTPUT_DEFAULT;
        
        /* ループ出力の有無 */
        WsGetDaMode(h_ws, DA_L_CH, &get_val);
        WsGetDaMode(h_ws, DA_R_CH, &get_val);
        WsGetDaLoopBackChannel(h_ws, DA_L_CH, &get_val);
        WsGetDaLoopBackChannel(h_ws, DA_R_CH, &get_val);
        
        /* Mute状態を確認（一方を取得すればローカル側は両方更新される） */
        WsGetDaMute(h_ws, DA_L_CH, &get_val);
        
        /* Gain設定を確認（一方を取得すればローカル側は両方更新される） */
        WsGetDaGain(h_ws, DA_L_CH, &get_val);
        
        /* 転送関数のコールバックを登録 */
        WsDaDataWrite = &WsDaDefaultDataWrite;
        
    }
    else if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        int ch;

        /* ボード枚数を取得 */
        WsGetBoardNum(h_ws, &board_num);
        h_ws->board_num = board_num;
        
        for(ch=0; ch<(h_ws->max_ch_num * h_ws->board_num); ch++)
        {
            h_ws->enable_channels[ch] = 0;

            /* 個々のチャネルのループ出力の有無 */
            WsGetDaMode(h_ws, ch, &get_val);
            
            /* 個々のチャネルの出力の有無 */
            WsGetDaOutputEnable(h_ws, ch, &get_val);
        }

        /* シングル／ステレオ／モノラルの判別 */
        WsGetDaChannelMode(h_ws, &get_val);

        /* データフォーマット取得 */
        WsGetDaDataFormat(h_ws, &get_val);
        
        /* 転送関数のコールバックを登録 */
        WsDaDataWrite = &WsDaDefaultDataWrite;
        
        /* 作業用バッファ確保 */
        h_ws->work_buffer = (void *)malloc(DA_WORK_BUFFER_SIZE);
        if(h_ws->work_buffer == NULL)
        {
            printf("Work Buffer Allocate Error.\n");
            goto HANDLE_OPEN_ERR4;
        }
    }
    else
    {
        /* 無線RASP */
        h_ws->data_format  = DATA_FORMAT_16BIT_PCM;
        h_ws->work_buffer  = NULL;

        /* ループ出力の有無 */
        WsGetDaMode(h_ws, DA_L_CH, &get_val);
        WsGetDaMode(h_ws, DA_R_CH, &get_val);
        
        if(h_ws->target_type == TARGET_TYPE_RASP_WL)
        {
            h_ws->resolution_bit = 16;
        }
        else
        {
            printf("Unknown Target(Type = %d).\n", h_ws->target_type);
            goto HANDLE_OPEN_ERR4;
        }

        /* 転送関数のコールバックを登録 */
        WsDaDataWrite = &WsDaDefaultDataWrite;
    }
    
    /* 正常終了 */
    return h_ws;

    
    /* エラー終了 */
 HANDLE_OPEN_ERR4:
    close(h_ws->data_server_info.socket_fd);

 HANDLE_OPEN_ERR3:
    close(h_ws->control_server_info.socket_fd);
 
 HANDLE_OPEN_ERR2:
    free(h_ws);
    
 HANDLE_OPEN_ERR1:
    
#ifdef WIN32
    /* 終了処理 */
    WSACleanup();
#endif

    return NULL;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.09.10 K.Takagi WSACleanupの呼び出しを追加
**
**            2009.11.16 K.Takagi 作業領域の開放を追加
**
**            2007.05.15 K.Takagi 新規作成
**
**  Description
**  -----------
**  サーバとの接続を終了しハンドルを削除
**
*/

int WsDaHandleClose(WS_HANDLE_t *h_ws)
{
    if(h_ws == NULL)
    {
        return 0;
    }

    /* サーバに終了を通知 */
    WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_SYSTEM_END, NULL);

    
    /* DA制御用ソケットを閉じる */
    close(h_ws->control_server_info.socket_fd);
    
    /* DAデータ通信用ソケットを閉じる */
    close(h_ws->data_server_info.socket_fd);
    
    /* 作業領域を開放 */
    free(h_ws->work_buffer);

    /* ハンドル用のメモリを開放 */
    free(h_ws);

#ifdef WIN32
    /* 終了処理 */
    WSACleanup();
#endif
    return 0;
}


/*----------------------------------------------------------*/
/*                       DA制御関係                         */
/*----------------------------------------------------------*/

/************************************************************
**
**  Public  : 
**
**  History : 2007.05.15 K.Takagi 新規作成
**
**  Description
**  -----------
**  再生周波数の設定(Hzで指定)
**
*/

int WsSetDaFreq(WS_HANDLE_t *h_ws, int freq)
{
    int status;
    int set_val;

    set_val = freq;
    status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_SET_DA_FREQ, &set_val);

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2008.06.13 K.Takagi get_val初期化
**            2008.06.05 K.Takagi NULLポインタチェック
**
**            2007.05.15 K.Takagi 新規作成
**
**  Description
**  -----------
**  現在設定されている再生周波数の取得(Hz)
**
*/

int WsGetDaFreq(WS_HANDLE_t *h_ws, int *freq)
{
    int status;
    int get_val;

    if(freq == NULL)
    {
        return -1;
    }
    get_val = 0;

    status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_GET_DA_FREQ, &get_val);
    
    *freq = get_val;
    
    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2007.05.15 K.Takagi 新規作成
**
**  Description
**  -----------
**  AD & DA同時のためのDA準備
**
*/

int WsDaReady(WS_HANDLE_t *h_ws)
{
    int status;

    status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_DA_READY, NULL);

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2007.05.15 K.Takagi 新規作成
**
**  Description
**  -----------
**  DA開始
**
*/

int WsDaStart(WS_HANDLE_t *h_ws)
{
    int status;

    status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_DA_START, NULL);

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2005.05.15 K.Takagi 新規作成
**
**  Description
**  -----------
**  DA即時停止 or DA動作クリア
**
*/

int WsDaStop(WS_HANDLE_t *h_ws)
{
    int status;
    int last_status;
    
    last_status = 0;
    status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_DA_STOP, &last_status);
    
    return last_status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2005.05.15 K.Takagi 新規作成
**
**  Description
**  -----------
**  DAの再生が終了するまで待機
**
*/

int WsDaStopWait(WS_HANDLE_t *h_ws)
{
    int status;
    int last_status;
    
    last_status = 0;
    status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_DA_STOP_WAIT, &last_status);
    
    return last_status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2008.06.13 K.Takagi get_val初期化
**            2007.05.31 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/Aのステータスを取得
**
*/

int WsGetDaStatus(WS_HANDLE_t *h_ws)
{
    int status;
    int get_val;

    get_val = 0;
    status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_GET_DA_STATUS, &get_val);
    
    return get_val;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/Aにループバック出力するA/Dのチャネルを指定
**
*/

int WsSetDaLoopBackChannel(WS_HANDLE_t *h_ws, int da_ch, int ad_ch)
{
    int status;
    int set_val1;
    int set_val2;

    set_val1 = da_ch;
    set_val2 = ad_ch;
    status   = WsControlClient2(h_ws->control_server_info.socket_fd,
                                WS_CMD_SET_DA_LOOP_BACK_CH,
                                &set_val1,
                                &set_val2);

    if(status == 0)
    {
        int board_no;

        board_no = da_ch / h_ws->max_ch_num;
        da_ch    = da_ch % h_ws->max_ch_num;

        if(da_ch == DA_L_CH)
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_L_LOOP_CH_MASK)) |
                                                ( (ad_ch << DA_L_LOOP_CH_SHIFT) & DA_L_LOOP_CH_MASK ) ) ;
        }
        else
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_R_LOOP_CH_MASK)) |
                                                ( (ad_ch << DA_R_LOOP_CH_SHIFT) & DA_R_LOOP_CH_MASK ) ) ;
        }
    }
    
    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  設定されているD/Aにループバック出力するA/Dのチャネルを取得
**
*/

int WsGetDaLoopBackChannel(WS_HANDLE_t *h_ws, int da_ch, int *ad_ch)
{
    int status;
    int set_val;
    int get_val;

    if(ad_ch == NULL)
    {
        return -1;
    }

    set_val = da_ch;
    get_val = 0;
    status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                               WS_CMD_GET_DA_LOOP_BACK_CH,
                               &set_val,
                               &get_val);

    if(status == 0)
    {
        int board_no;

        *ad_ch = get_val;
        board_no = da_ch / h_ws->max_ch_num;
        da_ch    = da_ch % h_ws->max_ch_num;

        if(da_ch == DA_L_CH)
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_L_LOOP_CH_MASK)) |
                                                ( (*ad_ch << DA_L_LOOP_CH_SHIFT) & DA_L_LOOP_CH_MASK ) ) ;
        }
        else
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_R_LOOP_CH_MASK)) |
                                                ( (*ad_ch << DA_R_LOOP_CH_SHIFT) & DA_R_LOOP_CH_MASK ) ) ;
        }
    }
    
    return status;
}


/************************************************************
**
**  Privated  : 
**
**  History : 2010.11.22 K.Takagi モノラル時のチャネル数算出を修正
**            2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/Aのチャネル数のチェック
**
*/

static int CheckDaChannelsNum(WS_HANDLE_t *h_ws)
{
    int board_no;
    int sub_ch_num;

    /* ホストPCから転送が必要なチャネル数を算出 */

    if(h_ws->ch_mode == DA_SINGLE_MODE)
    {
        /* すべてのチャネルに同じデータを出力 */
        h_ws->ch_num = 1;
    }
    else if(h_ws->ch_mode == DA_MONORAL_MODE)
    {
        /* ボードあたり1chのデータを出力（ボード上のL/R共通） */
        /*
        h_ws->ch_num = h_ws->board_num;
        */
        
        h_ws->ch_num = 0;
        for(board_no=0; board_no<h_ws->board_num; board_no++)
        {
            sub_ch_num = 0;
            if(h_ws->enable_channels[board_no] & DA_L_OUTPUT_ENABLE_MASK)
            {
                sub_ch_num++;
            }
            
            if(h_ws->enable_channels[board_no] & DA_R_OUTPUT_ENABLE_MASK)
            {
                sub_ch_num++;
            }

            if(sub_ch_num > 0)
            {
                h_ws->ch_num++;
            }
        }

    }
    else
    {
        /* 通常動作（ループバック使用時もここ） */
        h_ws->ch_num = 0;

        for(board_no=0; board_no<h_ws->board_num; board_no++)
        {
            if(h_ws->enable_channels[board_no] & DA_L_LOOP_MODE_MASK)
            {
                /* ループバックモードの場合はPCからの転送は不要 */
            }
            else
            {
                if(h_ws->enable_channels[board_no] & DA_L_OUTPUT_ENABLE_MASK)
                {
                    h_ws->ch_num++;
                }
            }

            if(h_ws->enable_channels[board_no] & DA_R_LOOP_MODE_MASK)
            {
                /* ループバックモードの場合はPCからの転送は不要 */
            }
            else
            {
                if(h_ws->enable_channels[board_no] & DA_R_OUTPUT_ENABLE_MASK)
                {
                    h_ws->ch_num++;
                }
            }
        }
    }

    return h_ws->ch_num;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.11.29 K.Takagi ステレオモード以外でのループバック設定は禁止
**            2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/Aの動作モード設定（通常出力 or A/Dループバック出力）
**
*/

int WsSetDaMode(WS_HANDLE_t *h_ws, int da_ch, int mode)
{
    int status;
    int set_val1;
    int set_val2;
    
    /* ステレオモード以外ではループバック設定は不可 */
    if(h_ws->ch_mode != DA_STEREO_MODE)
    {
        if(mode != DA_NORMAL_MODE)
        {
            return -1;
        }
    }
    
    set_val1 = da_ch;
    set_val2 = mode;
    status   = WsControlClient2(h_ws->control_server_info.socket_fd,
                                WS_CMD_SET_DA_LOOP_BACK_MODE,
                                &set_val1,
                                &set_val2);
    
    if(status == 0)
    {
        int board_no;

        board_no = da_ch / h_ws->max_ch_num;
        da_ch    = da_ch % h_ws->max_ch_num;

        if(da_ch == DA_L_CH)
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_L_LOOP_MODE_MASK)) |
                                                ( (mode << DA_L_LOOP_MODE_SHIFT) & DA_L_LOOP_MODE_MASK ) ) ;
        }
        else
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_R_LOOP_MODE_MASK)) |
                                                ( (mode << DA_R_LOOP_MODE_SHIFT) & DA_R_LOOP_MODE_MASK ) ) ;
        }

        /* ホストPCから転送が必要なチャネル数を算出 */
        CheckDaChannelsNum(h_ws);
    }


    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/Aの動作モード取得（通常出力 or A/Dループバック出力）
**
*/

int WsGetDaMode(WS_HANDLE_t *h_ws, int da_ch, int *mode)
{
    int status;
    int set_val;
    int get_val;

    if(mode == NULL)
    {
        return -1;
    }

    set_val = da_ch;
    get_val = 0;
    status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                               WS_CMD_GET_DA_LOOP_BACK_MODE,
                               &set_val,
                               &get_val);

    if(status == 0)
    {
        int board_no;

        *mode = get_val;
        board_no = da_ch / h_ws->max_ch_num;
        da_ch    = da_ch % h_ws->max_ch_num;

        if(da_ch == DA_L_CH)
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_L_LOOP_MODE_MASK)) |
                                                ( (*mode << DA_L_LOOP_MODE_SHIFT) & DA_L_LOOP_MODE_MASK ) ) ;
        }
        else
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_R_LOOP_MODE_MASK)) |
                                                ( (*mode << DA_R_LOOP_MODE_SHIFT) & DA_R_LOOP_MODE_MASK ) ) ;
        }

        /* ホストPCから転送が必要なチャネル数を算出 */
        CheckDaChannelsNum(h_ws);
    }

    
    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2011.04.14 K.Takagi RASP-24以外は非対応
**            2010.11.17 K.Takagi 関数名、引数、コマンド名を変更
**            2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/A出力の有無を設定
**
*/

int WsSetDaOutputEnable(WS_HANDLE_t *h_ws, int da_ch, int flag)
{
    int status;
    int set_val1;
    int set_val2;

    /* RASP24以外は何もしない */
    if(h_ws->target_type != TARGET_TYPE_RASP24)
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }
    
    set_val1 = da_ch;
    set_val2 = flag;
    status   = WsControlClient2(h_ws->control_server_info.socket_fd,
                                WS_CMD_SET_DA_OUTPUT_ENABLE,
                                &set_val1,
                                &set_val2);
    
    if(status == 0)
    {
        int board_no;

        board_no = da_ch / h_ws->max_ch_num;
        da_ch    = da_ch % h_ws->max_ch_num;
        /*
        printf("%s : %d %d %d\n", __func__, board_no, da_ch, flag);
        */
        if(da_ch == DA_L_CH)
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_L_OUTPUT_ENABLE_MASK)) |
                                                ( (flag << DA_L_OUTPUT_ENABLE_SHIFT) & DA_L_OUTPUT_ENABLE_MASK ) ) ;
        }
        else
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_R_OUTPUT_ENABLE_MASK)) |
                                                ( (flag << DA_R_OUTPUT_ENABLE_SHIFT) & DA_R_OUTPUT_ENABLE_MASK ) ) ;
        }

        /* ホストPCから転送が必要なチャネル数を算出 */
        CheckDaChannelsNum(h_ws);
    }


    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2011.04.14 K.Takagi RASP-24以外は非対応
**            2010.11.17 K.Takagi 関数名、引数、コマンド名を変更
**            2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/A出力の有無を取得
**
*/

int WsGetDaOutputEnable(WS_HANDLE_t *h_ws, int da_ch, int *flag)
{
    int status;
    int set_val;
    int get_val;

    /* RASP24以外は何もしない */
    if(h_ws->target_type != TARGET_TYPE_RASP24)
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }
    
    if(flag == NULL)
    {
        return -1;
    }

    set_val = da_ch;
    get_val = 0;
    status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                               WS_CMD_GET_DA_OUTPUT_ENABLE,
                               &set_val,
                               &get_val);

    if(status == 0)
    {
        int board_no;

        *flag    = get_val;
        board_no = da_ch / h_ws->max_ch_num;
        da_ch    = da_ch % h_ws->max_ch_num;
        /*
        printf("%s : %d %d %d\n", __func__, board_no, da_ch, *flag);
        */
        if(da_ch == DA_L_CH)
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_L_OUTPUT_ENABLE_MASK)) |
                                                ( (*flag << DA_L_OUTPUT_ENABLE_SHIFT) & DA_L_OUTPUT_ENABLE_MASK ) ) ;
        }
        else
        {
            h_ws->enable_channels[board_no] = ( (h_ws->enable_channels[board_no] & (~DA_R_OUTPUT_ENABLE_MASK)) |
                                                ( (*flag << DA_R_OUTPUT_ENABLE_SHIFT) & DA_R_OUTPUT_ENABLE_MASK ) ) ;
        }

        /* ホストPCから転送が必要なチャネル数を算出 */
        CheckDaChannelsNum(h_ws);
    }

    
    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2011.04.14 K.Takagi RASP-24以外は非対応
**            2010.11.29 K.Takagi ステレオモード以外を設定したらループバックは解除
**            2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/Aの出力チャネルモードを設定
**
*/

int WsSetDaChannelMode(WS_HANDLE_t *h_ws, int mode)
{
    int status;
    int set_val;
    int ch;

    /* RASP24以外は何もしない */
    if(h_ws->target_type != TARGET_TYPE_RASP24)
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }
    
    set_val = mode;
    status  = WsControlClient(h_ws->control_server_info.socket_fd,
                              WS_CMD_SET_DA_CHANNEL,
                              &set_val);
    
    if(status == 0)
    {
        h_ws->ch_mode = mode;
        
        /* ステレオモード以外にした場合はループバックを解除 */
        if(mode != DA_STEREO_MODE)
        {
            for(ch=0; ch<(h_ws->max_ch_num * h_ws->board_num); ch++)
            {
                WsSetDaMode(h_ws, ch, DA_NORMAL_MODE);
            }
        }

        /* ホストPCから転送が必要なチャネル数を算出 */
        CheckDaChannelsNum(h_ws);
    }

    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2011.04.14 K.Takagi RASP-24以外は非対応
**            2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/Aの出力チャネルモードを取得
**
*/

int WsGetDaChannelMode(WS_HANDLE_t *h_ws, int *mode)
{
    int status;
    int get_val;

    /* RASP24以外は何もしない */
    if(h_ws->target_type != TARGET_TYPE_RASP24)
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }
    
    if(mode == NULL)
    {
        return -1;
    }

    get_val = 0;
    status  = WsControlClient(h_ws->control_server_info.socket_fd,
                              WS_CMD_GET_DA_CHANNEL,
                              &get_val);
    if(status == 0)
    {
        *mode         = get_val;
        h_ws->ch_mode = get_val;
        
        /* ホストPCから転送が必要なチャネル数を算出 */
        CheckDaChannelsNum(h_ws);
    }
    
    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.25 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/Aの出力チャネル数を取得
**
*/

int WsGetDaChannelNum(WS_HANDLE_t *h_ws, int *ch_num)
{
    if(ch_num == NULL)
    {
        return -1;
    }

    *ch_num = h_ws->ch_num;
    
    return 0;
}


/************************************************************
**
**  Public  : 
**
**  History : 2011.04.14 K.Takagi AS-RASP対応／従来のAS-RASPと引数は異なる
**            2010.10.25 K.Takagi 引数の扱いを変更
**            2010.10.21 K.Takagi 新規作成
**                                複数枚ボードに対応
**
**  Description
**  -----------
**  D/AのMute設定
**
*/

static int l_mute_flag;
static int r_mute_flag;

int WsSetDaMute(WS_HANDLE_t *h_ws, int da_ch, int mute_flag)
{
    int status;
    int set_val;

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                   WS_CMD_SET_DA_MUTE_MODE,
                                   &da_ch,
                                   &mute_flag);
    }
    else if(h_ws->target_type == TARGET_TYPE_AS_RASP)
    {
        if(da_ch == DA_L_CH)
        {
            set_val = ((mute_flag & 0x1) << 1) | (r_mute_flag & 0x1);
        }
        else
        {
            set_val = ((l_mute_flag & 0x1) << 1) | (mute_flag & 0x1);
        }
        
        status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                  WS_CMD_SET_DA_MUTE_MODE,
                                  &set_val);
        
        if(status == 0)
        {
            l_mute_flag = (set_val >> 1) & 0x1;
            r_mute_flag =  set_val       & 0x1;
        }
    }
    else
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }
    
    return status;
}

#if 0 /* 旧版はRASP-24のみ */
int WsSetDaMute(WS_HANDLE_t *h_ws, int da_ch, int mute_flag)
{
    int status;

    /* RASP24以外は何もしない */
    if(h_ws->target_type != TARGET_TYPE_RASP24)
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }


    status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                               WS_CMD_SET_DA_MUTE_MODE,
                               &da_ch,
                               &mute_flag);
    
    return status;
}
#endif

/************************************************************
**
**  Public  : 
**
**  History : 2011.04.14 K.Takagi AS-RASP対応／従来のAS-RASPと引数は異なる
**            2010.10.25 K.Takagi 引数の扱いを変更
**            2010.10.21 K.Takagi 新規作成
**                                複数枚ボードに対応
**
**  Description
**  -----------
**  D/AのMute状態を取得
**
*/

int WsGetDaMute(WS_HANDLE_t *h_ws, int da_ch, int *mute_flag)
{
    int status;
    int get_val;

    if(mute_flag == NULL)
    {
        return -1;
    }

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        get_val = 0;
        status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                   WS_CMD_GET_DA_MUTE_MODE,
                                   &da_ch,
                                   &get_val);
    }
    else if(h_ws->target_type == TARGET_TYPE_AS_RASP)
    {
        status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                  WS_CMD_GET_DA_MUTE_MODE,
                                  &get_val);
        
        l_mute_flag = (get_val >> 1) & 0x1;
        r_mute_flag =  get_val       & 0x1;
        
        if(da_ch == DA_L_CH)
        {
            get_val = l_mute_flag;
        }
        else
        {
            get_val = r_mute_flag;
        }
    }
    else
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }

    
    if(status == 0)
    {
        *mute_flag = get_val & 0x1;
    }

    return status;
}

#if 0 /* 旧版はRASP-24のみ */
int WsGetDaMute(WS_HANDLE_t *h_ws, int da_ch, int *mute_flag)
{
    int status;
    int get_val;

    if(mute_flag == NULL)
    {
        return -1;
    }

    /* RASP24以外は何もしない */
    if(h_ws->target_type != TARGET_TYPE_RASP24)
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }

    get_val = 0;
    status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                               WS_CMD_GET_DA_MUTE_MODE,
                               &da_ch,
                               &get_val);
    
    if(status == 0)
    {
        *mute_flag = get_val & 0x1;
    }

    return status;
}
#endif

/************************************************************
**
**  Public  : 
**
**  History : 2011.05.06 K.Takagi AS-RASP時の0dB設定を修正
**            2011.04.14 K.Takagi AS-RASP対応／従来のAS-RASPと引数は異なる
**            2010.10.25 K.Takagi 引数の扱いを変更
**            2010.10.21 K.Takagi 新規作成
**                                複数枚ボードに対応
**
**  Description
**  -----------
**  D/AのGain設定
**  範囲は -63 to 0 [dB]
**
*/

static int da_l_gain;
static int da_r_gain;

int WsSetDaGain(WS_HANDLE_t *h_ws, int da_ch, int gain)
{
    int status;
    int set_val;

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                   WS_CMD_SET_DA_GAIN,
                                   &da_ch,
                                   &gain);
    }
    else if(h_ws->target_type == TARGET_TYPE_AS_RASP)
    {
        if(da_ch == DA_L_CH)
        {
            set_val = ((gain & 0xFF) << 16) | (da_r_gain & 0xFF);
        }
        else
        {
            set_val = ((da_l_gain & 0xFF) << 16) | (gain & 0xFF);
        }
        
        status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                  WS_CMD_SET_DA_GAIN,
                                  &set_val);
        
        if(status == 0)
        {
            /* 負の値にするため上位24bitは1 */
            /*
            da_l_gain = (set_val >> 16) | 0xFFFFFF00;
            da_r_gain =  set_val        | 0xFFFFFF00;
            */
            da_l_gain = (set_val >> 16) & 0xFF;
            if(da_l_gain != 0x0)
            {
                da_l_gain |= 0xFFFFFF00;
            }
            
            da_r_gain =  set_val & 0xFF;
            if(da_r_gain != 0x0)
            {
                da_r_gain |= 0xFFFFFF00;
            }
        }
    }
    else
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }
    
    return status;
}

#if 0 /* 旧版はRASP-24のみ */
int WsSetDaGain(WS_HANDLE_t *h_ws, int da_ch, int gain)
{
    int status;

    /* RASP24以外は何もしない */
    if(h_ws->target_type != TARGET_TYPE_RASP24)
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }

    status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                               WS_CMD_SET_DA_GAIN,
                               &da_ch,
                               &gain);
    
    return status;
}
#endif

/************************************************************
**
**  Public  : 
**
**  History : 2011.05.06 K.Takagi AS-RASP時の0dB設定を修正
**            2011.04.14 K.Takagi AS-RASP対応／従来のAS-RASPと引数は異なる
**            2010.10.25 K.Takagi 引数の扱いを変更
**            2010.10.21 K.Takagi 新規作成
**                                複数枚ボードに対応
**
**  Description
**  -----------
**  D/AのGainを取得
**  範囲は -63 to 0 [dB]
**
*/

int WsGetDaGain(WS_HANDLE_t *h_ws, int da_ch, int *gain)
{
    int status;
    int get_val;

    if(gain == NULL)
    {
        return -1;
    }

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        get_val = 0;
        status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                   WS_CMD_GET_DA_GAIN,
                                   &da_ch,
                                   &get_val);
    }
    else if(h_ws->target_type == TARGET_TYPE_AS_RASP)
    {
        get_val = 0;
        status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                  WS_CMD_GET_DA_GAIN,
                                  &get_val);
        
        /* 負の値にするため上位24bitは1 */
        /*
        da_l_gain = (get_val >> 16) | 0xFFFFFF00;
        da_r_gain =  get_val        | 0xFFFFFF00;
        */
        da_l_gain = (get_val >> 16) & 0xFF;
        if(da_l_gain != 0x0)
        {
            da_l_gain |= 0xFFFFFF00;
        }
        
        da_r_gain =  get_val & 0xFF;
        if(da_r_gain != 0x0)
        {
            da_r_gain |= 0xFFFFFF00;
        }

        if(da_ch == DA_L_CH)
        {
            get_val = da_l_gain;
        }
        else
        {
            get_val = da_r_gain;
        }
    }
    else
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }
    
    if(status == 0)
    {
        *gain = get_val;
    }

    return status;
}

#if 0 /* 旧版はRASP-24のみ */
int WsGetDaGain(WS_HANDLE_t *h_ws, int da_ch, int *gain)
{
    int status;
    int get_val;

    if(gain == NULL)
    {
        return -1;
    }

    /* RASP24以外は何もしない */
    if(h_ws->target_type != TARGET_TYPE_RASP24)
    {
        LOG_PRINT("No Support Func : %s\n", __func__);
        return ERR_UNSUPPORTED_CMD;
    }

    get_val = 0;
    status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                               WS_CMD_GET_DA_GAIN,
                               &da_ch,
                               &get_val);
    
    if(status == 0)
    {
        *gain = get_val;
    }

    return status;
}
#endif

/*----------------------------------------------------------*/
/*                     データ通信関係                       */
/*----------------------------------------------------------*/

/************************************************************
**
**  Public  : 
**
**  History : 2006.12.22 K.Takagi 新規作成
**
**  Description
**  -----------
**  データ転送を実行するwrite()のラッパ関数
**
*/

int WsDaDefaultDataWrite(WS_HANDLE_t *h_ws, char *buffer, size_t write_req_size)
{
    int write_size;

    LOG_PRINT("Called %s.\n", __func__);

    /* サーバーにデータを転送 */
    write_size = write(h_ws->data_server_info.socket_fd, buffer, write_req_size);
    
    return write_size;
}

/************************************************************
**
**  Public  : 
**
**  History : 2011.02.07 K.Takagi 新規作成
**
**  Description
**  -----------
**  データ転送を実行するwrite()のラッパ関数
**  float対応
**
*/

int RASP24_WsDaFloatDataWrite(WS_HANDLE_t *h_ws, char *buffer, size_t write_req_size)
{
    int total_data_length;
    int send_data_length;
    int send_data_size;
    int write_size;

    float gain;
    char *work_buffer;
    
    int offset;
    int count;
    float *in_data;
    int   *out_data;

    LOG_PRINT("Called %s.\n", __func__);

    /* 転送するデータの総数 */
    total_data_length = write_req_size / sizeof(float);

    /* float --> int(24bit)への係数 */
    gain = 1.0 * 0x7fffff;


    in_data     = (float *)buffer;
    work_buffer = (char *)h_ws->work_buffer;

    while(total_data_length > 0)
    {
        if(total_data_length < (DA_WORK_BUFFER_SIZE / sizeof(int)))
        {
            send_data_length = total_data_length;
        }
        else
        {
            send_data_length = DA_WORK_BUFFER_SIZE / sizeof(int);
        }
        
        /* データ変換 */
        out_data = (int *)h_ws->work_buffer;
        for(count=0; count<send_data_length; count++)
        {
            out_data[count] = (int)(gain * (*in_data));
            in_data++;
        }
        
        /* サーバーにデータを転送 */
        offset = 0;
        send_data_size = send_data_length * sizeof(int);
        while(send_data_size > 0)
        {
            write_size = write(h_ws->data_server_info.socket_fd, 
                               &work_buffer[offset],
                               send_data_size);

            if(write_size < 0)
            {
                goto RASP24_WsDaFloatDataWriteEnd;
            }

            send_data_size -= write_size;
            offset += write_size;
        };
        LOG_PRINT("Send size = %d.\n", offset);
        
        total_data_length -= send_data_length;
    };

    /* 正常終了 */
    return write_req_size;

    /* エラー終了 */
 RASP24_WsDaFloatDataWriteEnd:
    return write_size;
}

/************************************************************
**
**  Public  : 
**
**  History : 2009.11.16 K.Takagi 新規作成
**
**  Description
**  -----------
**  データ転送を実行するwrite()のラッパ関数
**  float対応
**
*/

int RASP_WL_WsDaFloatDataWrite(WS_HANDLE_t *h_ws, char *buffer, size_t write_req_size)
{
    int total_data_length;
    int send_data_length;
    int send_data_size;
    int write_size;

    float gain;
    char *work_buffer;
    
    int offset;
    int count;
    float *in_data;
    short *out_data;

    LOG_PRINT("Called %s.\n", __func__);

    /* 転送するデータの総数 */
    total_data_length = write_req_size / sizeof(float);

    /* float --> shortへの係数 */
    gain = h_ws->gain * 0x7fff;


    in_data     = (float *)buffer;
    work_buffer = (char *)h_ws->work_buffer;

    while(total_data_length > 0)
    {
        if(total_data_length < (DA_WORK_BUFFER_SIZE / sizeof(short)))
        {
            send_data_length = total_data_length;
        }
        else
        {
            send_data_length = DA_WORK_BUFFER_SIZE / sizeof(short);
        }
        
        /* データ変換 */
        out_data = (short *)h_ws->work_buffer;
        for(count=0; count<send_data_length; count++)
        {
            out_data[count] = (short)(gain * (*in_data));
            in_data++;
        }
        
        /* サーバーにデータを転送 */
        offset = 0;
        send_data_size = send_data_length * sizeof(short);
        while(send_data_size > 0)
        {
            write_size = write(h_ws->data_server_info.socket_fd, 
                               &work_buffer[offset],
                               send_data_size);

            if(write_size < 0)
            {
                goto RASP_WL_WsDaFloatDataWriteEnd;
            }

            send_data_size -= write_size;
            offset += write_size;
        };
        LOG_PRINT("Send size = %d.\n", offset);
        
        total_data_length -= send_data_length;
    };

    /* 正常終了 */
    return write_req_size;

    /* エラー終了 */
 RASP_WL_WsDaFloatDataWriteEnd:
    return write_size;
}



/************************************************************
**
**  Public  : 
**
**  History : 2011.04.14 K.Takagi AS-RASP対応
**            2010.10.21 K.Takagi 新規作成
**
**  Description
**  -----------
**  データ転送関数のコールバックを各フォーマット対応の関数にする
**
*/

int WsSetDaDataFormat(WS_HANDLE_t *h_ws, int format_type)
{
    int status;
    int set_val;

    status = 0;
    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        /* 32bit or 16bitデータフォーマット選択 */
        if(format_type == DATA_FORMAT_SYSTEM_DEFAULT)
        {
            format_type = DATA_FORMAT_32BIT_PCM;
        }

        set_val = format_type;
        status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                  WS_CMD_SET_DA_FORMAT,
                                  &set_val);
        
        if(status == 0)
        {
            if(format_type == DATA_FORMAT_32BIT_PCM)
            {
                h_ws->resolution_bit = 32;
            }
            else if(format_type == DATA_FORMAT_16BIT_PCM)
            {
                h_ws->resolution_bit = 16;
            }
            else
            {
                /* このケースはないはず */
                return -1;
            }
            h_ws->data_format = format_type;

            /* デフォルトのコールバックを設定 */
            WsDaDataWrite = &WsDaDefaultDataWrite;
        }
    }
    else if(h_ws->target_type == TARGET_TYPE_AS_RASP)
    {
        /* AS-RASPでは32bitモードのみ */
        h_ws->data_format = DATA_FORMAT_32BIT_PCM;

        WsDaDataWrite = &WsDaDefaultDataWrite;
    }
    else
    {
        /* 無線RASPでは16bitモードのみ */
        h_ws->data_format = DATA_FORMAT_16BIT_PCM;

        WsDaDataWrite = &WsDaDefaultDataWrite;
    }

    return 0;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.21 K.Takagi 新規作成
**
**  Description
**  -----------
**  D/Aデータフォーマットを取得
**
*/

int WsGetDaDataFormat(WS_HANDLE_t *h_ws, int *format_type)
{
    int status;
    int get_val;

    if(format_type == NULL)
    {
        return -1;
    }

    status = 0;
    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                  WS_CMD_GET_DA_FORMAT,
                                  &get_val);
        
        if(status == 0)
        {
            /* システム標準は32bit符号拡張 */
            if(get_val == DATA_FORMAT_SYSTEM_DEFAULT)
            {
                get_val = DATA_FORMAT_32BIT_PCM;
            }

            if(get_val == DATA_FORMAT_32BIT_PCM)
            {
                h_ws->resolution_bit = 32;

            }
            else if(get_val == DATA_FORMAT_16BIT_PCM)
            {
                h_ws->resolution_bit = 16;
            }
            else
            {
                /* このケースはないはず */
                return -1;
            }
            h_ws->data_format = get_val;
            *format_type      = get_val;

            /* デフォルトのコールバックを設定 */
            WsDaDataWrite = &WsDaDefaultDataWrite;
        }
    }
    else
    {
        /* 
         * 従来の方式ではホストPC側でのみ処理しているので
         * コールバックの再設定等は不要
         */
        
        *format_type = h_ws->data_format;
    }

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2007.05.31 K.Takagi 新規作成
**
**  Description
**  -----------
**  データ転送用ソケットの送信タイムアウト時間を設定
**
*/

int WsDaSetWriteTimeout(WS_HANDLE_t *h_ws, int timeout_sec)
{
    int status;
    struct timeval tv;
    
    /* 負の値はエラー */
    if(timeout_sec < 0)
    {
        return -1;
    }
    
    tv.tv_sec  = timeout_sec;
    tv.tv_usec = 0;
    
    status = setsockopt(h_ws->data_server_info.socket_fd,
                        SOL_SOCKET,
                        SO_SNDTIMEO,
                        (char *)&tv,
                        sizeof(tv));
    
    return 0;
}


/* EOF */
