/************************************************************
**
**     Object name : rasp-netapi
**
**     Public      : WsHandleOpen
**                   WsHandleClose
**                   
**                   WsGetSystemInfo
**                   WsGetTargetType
**                   WsGetTargetSubType
**                   WsGetBytePerSample
**                   WsGetFrameSize
**                   WsGetHeaderSize
**                   WsGetChannelNum
**                   WsGetResolutionBit
**
**                   WsSetSamplingFreq
**                   WsGetSamplingFreq
**                   WsSetChannelMode
**                   WsGetChannelMode
**                   WsSetCaptureChannels
**                   WsGetCaptureChannels
**                   WsSetCaptureChannelsList
**                   WsGetCaptureChannelsList
**
**                   WsADStart
**                   WsADStop
**                   WsAdDaStart
**                   
**                   WsSetAdMode
**                   WsGetAdMode
**                   WsSetAdSleepMode
**                   WsGetAdSleepMode
**                   
**                   WsDataRead
**                   WsSampleDataRead
**                   WsFrameRead
**                   RASP24_WsFrameRead
**                   RASP_WL_WsFrameRead
**                   AS_RASP_WsFrameRead
**                   RASP_WL_WsFrameReadFloatFormat
**                   WsFrameReadDummy
**
**                   WsSetAdDataFormat
**                   WsGetAdDataFormat
**                   
**                   WsWordClockOutput
**
**     Private     : WsControlClient
**                   WsControlClient2
**
**     Description
**     -- -- -- -- -- -- -- --
**     RASP-24をネットワーク経由で利用するためのAPI
**
**     History
**     -- -- -- -- -- -- -- --
**     2013.06.14 K.Takagi 改版 RASP-ZX 対応
**                           RASP-24互換で動作するように修正
**                           CH数は最大32
**     2013.01.29 A.Koike  RASP-ZX対応
**     2012.12.06 K.Takagi RASP-LC無線版のライブラリを取り込み
**
**     2011.05.06 K.Takagi WsHandleShowから時間表示を削除
**     2011.04.21 K.Takagi WsSetAdSleepModeを追加
**                         WsGetAdSleepModeを追加
**     2011.04.13 K.Takagi WsGetBoardNumを修正
**                         WsSetAdDataFormatを修正
**                         WsSystemPowerDownを修正
**                         WsSetAdModeを追加
**                         WsGetAdModeを追加
**     2011.04.12 K.Takagi 統合化のために整理
**                         WsHandleOpenを修正
**                         AS-RASPの識別を追加
**                         AS_RASP_WsFrameReadを追加
**                         WsGetSystemInfo修正
**
**     2011.02.07 K.Takagi コメント類を整備
**     2010.10.16 K.Takagi 新規作成
**                         従来のシステムをベースに移植
**
**     Copyright (c) 2010-2011
**     System In Frontier,Inc.
**     All rights reserved. 
**
**     当社の許可なしに複製および転載を禁ず
**
*/


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

#ifdef WIN32

#pragma warning(disable:4996)

#endif

#undef DEBUG

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

#ifdef WIN32

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "WinSockVersion.h"

#ifdef _DEBUG
#define DEBUG
#endif

#else

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/types.h>
//#include <sys/io.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <sys/select.h>

#include <fcntl.h>
#include <errno.h>

#endif


/* RASPシリーズ固有のヘッダファイル */
#include "librasp-netapi.h"

#include "rasp-netapi-cmd.h"

#include "as-rasp.h"

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

#define RASP24_SAMPLE_PER_FRAME        1024
#define AS_RASP_SAMPLE_PER_FRAME       1024
#define RASP_WL_SAMPLE_PER_FRAME_8CH   1024
#define RASP_WL_SAMPLE_PER_FRAME_16CH  512
#define RASP_ZX_SAMPLE_PER_FRAME       1024

#define RASP24_HEADER_SIZE  (sizeof(int) * 2)

#ifdef DEBUG

#define DEBUG_PRINT printf

#else

#define DEBUG_PRINT(...)  

#endif

#ifdef DEBUG_LOG

#define LOG_PRINT printf

#else

#define LOG_PRINT(...)  

#endif

#define CONNECT_TIMEOUT 3000

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

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

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

/*=========================================================*/
/*                   Private Functions                     */
/*=========================================================*/
static int WsControlClient(SOCKET socket_fd, int cmd, int *arg);
static int WsControlClient2(SOCKET socket_fd, int cmd, int *arg1, int *arg2);
static int UpdateChannelModeInfo(WS_HANDLE_t *h_ws, int ch_mode);
static int CheckCaptureChannels(WS_HANDLE_t *h_ws, int capture_channels, int print_flag);
static int ConnectWithTimeout(const int socket, const struct sockaddr *address, const socklen_t address_len, const int timeout_ms);

int RASP24_WsFrameRead(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size);
int RASP_WL_WsFrameRead(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size);
int AS_RASP_WsFrameRead(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size);
int WsFrameReadDummy(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size);

#ifdef WIN32
#else
int (*WsFrameRead)(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size) = &WsFrameReadDummy;
#endif



/*----------------------------------------------------------*/
/*                          共通                            */
/*----------------------------------------------------------*/
/************************************************************
 **
 **  Private :
 **
 **  History : 2013.7.24 Y.Iwasaki 新規作成
 **
 **  Description
 **  -----------
 **  タイムアウト付きconnect
 **
 */
static int ConnectWithTimeout(const int socket, const struct sockaddr *address, const socklen_t address_len, const int timeout_ms)
{

    // ソケットを非ブロッキングモードに
    int retval;
#ifdef WIN32
    unsigned long arg = 1;
    retval = ioctlsocket(socket, FIONBIO, &arg);
    if (retval != 0) {
        fprintf(stderr, "ERROR: set socket nonblock, filename = %s, line = %d\n", __FILE__, __LINE__);
        return(-1);
    }
#else // WIN32
    retval = fcntl(socket, F_SETFL, O_NONBLOCK);
    if (retval == -1) {
        fprintf(stderr, "ERROR: set socket nonblock, filename = %s, line = %d\n", __FILE__, __LINE__);
        return(-1);
    }
#endif // WIN32
    
    retval = connect(socket, address, address_len);
    if(retval != 0) {
#ifdef WIN32
        if (WSAGetLastError() == WSAEWOULDBLOCK) {
#else // WIN32
        if (errno == EINPROGRESS) {
#endif // WIN32

            fd_set wfds;
            struct timeval tv;

            tv.tv_sec = timeout_ms / 1000;
            tv.tv_usec = (timeout_ms % 1000) * 1000;
            
            FD_ZERO(&wfds);
            FD_SET(socket, &wfds);
            
            retval = select(socket + 1, NULL, &wfds, NULL, &tv);
            if (retval < 0) {
                fprintf(stderr, "ERROR: select, filename = %s, line = %d\n", __FILE__, __LINE__);
                return(-1);
            } else if (retval > 0) {
                // 書き込み可能になっているので結果判定
                int val;
                socklen_t len = sizeof(val);
                if(getsockopt(socket, SOL_SOCKET, SO_ERROR, &val, &len) == 0) {
                    if (val != 0) {
                        fprintf(stderr, "ERROR: connect, val = %d filename = %s, line = %d\n", val, __FILE__, __LINE__);
                        return(-1);
                    }
                } else {
                    fprintf(stderr, "ERROR: getsockopt, filename = %s, line = %d\n", __FILE__, __LINE__);
                    return(-1);
                }
            } else {
                // timeout
                fprintf(stderr, "ERROR: connection timeout, filename = %s, line = %d\n", __FILE__, __LINE__);
                return(-1);
            }
            
        } else {
            // 接続中以外のエラー
            fprintf(stderr, "ERROR: connect, filename = %s, line = %d\n", __FILE__, __LINE__);
            return(-1);
        }
        
    }
    
    // ソケットをブロッキングモードにもどす
#ifdef WIN32
    arg = 0;
    retval = ioctlsocket(socket, FIONBIO, &arg);
    if (retval != 0) {
        fprintf(stderr, "ERROR: set socket block, filename = %s, line = %d\n", __FILE__, __LINE__);
        return(-1);
    }
#else // WIN32
    retval = fcntl(socket, F_SETFL, 0);
    if (retval == -1) {
        fprintf(stderr, "ERROR: set socket block, filename = %s, line = %d\n", __FILE__, __LINE__);
        return(-1);
    }
#endif // WIN32
    
    return(0);
}


/************************************************************
**
**  Private : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  サーバのコマンドを送信して、ステータスを受信
**
**  送信 コマンド ＋ 値
**  受信 コマンド ＋ ステータス ＋ 値
**
*/

static int WsControlClient(SOCKET socket_fd, int cmd, int *arg)
{
    int  status;
    int  value;
    char buffer[CMD_STRING_LENGTH];


    /* 送信する文字列（コマンド）を作成 */
    value = 0;
    if(arg != NULL)
    {
        value = *arg;
    }

    sprintf(buffer, "0x%08x %d", cmd, value);
    DEBUG_PRINT("Send : %s\n", buffer);


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


    /* ステータス受信 */
    read(socket_fd, buffer, CMD_STRING_LENGTH);
    
    sscanf(buffer, "%*s %d %d", &status, &value);
    if(arg != NULL)
    {
        *arg = value;
    }
    DEBUG_PRINT("Recv : %s\n", buffer);

    return status;
}


/************************************************************
**
**  Private : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  サーバのコマンドを送信して、ステータスを受信
**  引数2つ版／サーバからの戻り値はarg2に格納
**
**  送信 コマンド ＋ 値 ＋ 値
**  受信 コマンド ＋ ステータス ＋ 値
**
*/

static int WsControlClient2(SOCKET socket_fd, int cmd, int *arg1, int *arg2)
{
    int  status;
    int  value1;
    int  value2;
    char buffer[CMD_STRING_LENGTH];


    /* 送信する文字列（コマンド）を作成 */
    value1 = 0;
    if(arg1 != NULL)
    {
        value1 = *arg1;
    }

    value2 = 0;
    if(arg2 != NULL)
    {
        value2 = *arg2;
    }

    sprintf(buffer, "0x%08x %d %d", cmd, value1, value2);
    DEBUG_PRINT("Send : %s\n", buffer);


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


    /* ステータス受信 */
    read(socket_fd, buffer, CMD_STRING_LENGTH);
    
    sscanf(buffer, "%*s %d %d", &status, &value2);
    if(arg2 != NULL)
    {
        *arg2 = value2;
    }
    DEBUG_PRINT("Recv : %s\n", buffer);

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2011.04.12 K.Takagi AS-RASP対応
**            2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  AD制御とデータ取得用のハンドルの作成
**
*/

WS_HANDLE_t *WsHandleOpen(char *ip_addr)
{
    int status;
    WS_HANDLE_t *h_ws;

#ifdef CONV_INET_ADDR_MODE
    in_addr_t server_ip_addr;
#else
    struct in_addr server_ip_addr;
#endif

    int ch_mode;

    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_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 = ConnectWithTimeout(h_ws->control_server_info.socket_fd,
                     (struct sockaddr *)&(h_ws->control_server_info.socket_addr),
                     h_ws->control_server_info.socket_addr_size, CONNECT_TIMEOUT);
    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, "RASP24ZX") != NULL)
        {
            /* 製品版のRASP-ZX(RASP-24互換動作に対応) */
            LOG_PRINT("Connect RASPZX(0x%08x)\n", status);
            h_ws->target_type = TARGET_TYPE_RASPZX;
            h_ws->target_sub_type = 1;
        }
        else if(strstr(str, "RASP24") != NULL)
        {
            LOG_PRINT("Connect RASP24(0x%08x)\n", status);
            h_ws->target_type = TARGET_TYPE_RASP24;
        }
        else if(strstr(str, "RASPZX") != NULL)
        {
            /* 試作版のRASP-ZX */
            LOG_PRINT("Connect RASPZX(0x%08x)\n", status);
            h_ws->target_type = TARGET_TYPE_RASPZX;
            h_ws->target_sub_type = 0;
        }
        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_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 = ConnectWithTimeout(h_ws->data_server_info.socket_fd,
                     (struct sockaddr *)&(h_ws->data_server_info.socket_addr),
                     h_ws->data_server_info.socket_addr_size, CONNECT_TIMEOUT);
    if(status == -1)
    {
        printf("Data Socket Connection Error.\n");
        goto HANDLE_OPEN_ERR4;
    }

    h_ws->server_ip_addr = server_ip_addr;

    h_ws->header_count   = 0;
    h_ws->board_num      = 1;

    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->max_ch_num     = AS_RASP_MAX_CH_NUM;
        h_ws->data_format    = DATA_FORMAT_32BIT_PCM;
        h_ws->resolution_bit = 32;
        h_ws->work_buffer    = NULL;
        h_ws->header_flag    = 1;
        
        /* WsFrameRead関数のコールバックを設定 */
        WsFrameRead = &AS_RASP_WsFrameRead;
        
        /* CHモード取得 */
        status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_GET_CHANNEL, &ch_mode);
        UpdateChannelModeInfo(h_ws, ch_mode);
    }
    else if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        int channels;
        int data_format;
        int board_num;
        int board_no;
        int flag;

        h_ws->max_ch_num     = RASP24_MAX_CH_NUM;
        h_ws->data_format    = DATA_FORMAT_32BIT_PCM; /* 仮 */
        h_ws->resolution_bit = 32;                    /* 仮 */
        h_ws->work_buffer    = NULL;
        h_ws->header_flag    = 0;

        board_num   = 0;
        data_format = 0;

        /* ボード枚数を取得 */
        WsGetBoardNum(h_ws, &board_num);
        h_ws->board_num = board_num;

        /* 下記関数にてフレームサイズ等は更新される */
        
        /* 取り込み有効チャネル取得 */
        for(board_no=0; board_no<h_ws->board_num; board_no++)
        {
            channels = 0;
            WsGetCaptureChannels(h_ws, board_no, &channels);
        }
        
        /* フォーマット取得 */
        WsGetAdDataFormat(h_ws, &data_format);
        
        /* ヘッダ付加状況取得 */
        WsGetHeaderFlag(h_ws, &flag);
            
        /* コールバック関数を設定 */
        WsFrameRead = &RASP24_WsFrameRead;
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        if(h_ws->target_sub_type == 0)
        {
            h_ws->max_ch_num     = RASPZX_MAX_CH_NUM;
            h_ws->data_format    = DATA_FORMAT_32BIT_PCM;
            h_ws->resolution_bit = 32;
            h_ws->work_buffer    = NULL;
            h_ws->header_flag    = 0;
            
            /* ボード枚数を設定 */
            h_ws->board_num = 1;
            
            /* コールバック関数を設定 */
            WsFrameRead = &RASP24_WsFrameRead;
            
            /* CHモード設定 */
            UpdateChannelModeInfo(h_ws, AD_8CH_MODE);
        }
        else
        {
            int channels;
            int data_format;
            int board_num;
            int board_no;
            
            h_ws->max_ch_num     = RASP24_MAX_CH_NUM;
            h_ws->data_format    = DATA_FORMAT_32BIT_PCM; /* 仮 */
            h_ws->resolution_bit = 32;                    /* 仮 */
            h_ws->work_buffer    = NULL;
            h_ws->header_flag    = 0;
            
            board_num   = 0;
            data_format = 0;
            
            /* ボード枚数を取得 */
            WsGetBoardNum(h_ws, &board_num);
            h_ws->board_num = board_num;
            
            /* 下記関数にてフレームサイズ等は更新される */
            
            /* 取り込み有効チャネル取得 */
            for(board_no=0; board_no<h_ws->board_num; board_no++)
            {
                channels = 0;
                WsGetCaptureChannels(h_ws, board_no, &channels);
            }
            
            /* フォーマット取得 */
            WsGetAdDataFormat(h_ws, &data_format);
            
            /* コールバック関数を設定 */
            WsFrameRead = &RASP24_WsFrameRead;
        }
    }
    else
    {
        /* 無線RASP */
        h_ws->data_format  = DATA_FORMAT_16BIT_PCM;
        h_ws->work_buffer  = NULL;
        h_ws->header_flag  = 1;
        
        if(h_ws->target_type == TARGET_TYPE_RASP_WL)
        {
            WsFrameRead          = &RASP_WL_WsFrameRead;
            h_ws->max_ch_num     = RASP_WL_MAX_CH_NUM;
            h_ws->resolution_bit = 16;
        }
        else
        {
            printf("Unknown Target(Type = %d).\n", h_ws->target_type);
            goto HANDLE_OPEN_ERR4;
        }
        
        /* CHモード取得 */
        status = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_GET_CHANNEL, &ch_mode);
        UpdateChannelModeInfo(h_ws, ch_mode);
    }


    /* 正常終了 */
    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.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  サーバとの接続を終了しAD制御とデータ取得用のハンドルを削除
**
*/

int WsHandleClose(WS_HANDLE_t *h_ws)
{
    if(h_ws == NULL)
    {
        return 0;
    }
    
    /* サーバに終了を通知 */
    WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_SYSTEM_END, NULL);

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

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

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

    return 0;
}


/************************************************************
**
**  Public  : 
**
**  History : 2011.04.12 K.Takagi AS-RASP対応
**            2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  システム情報の取得と表示
**
*/

int WsGetSystemInfo(WS_HANDLE_t *h_ws, int *target_type)
{
    int  status;
    int  value;
    char buffer[CMD_STRING_LENGTH];
    char str[CMD_STRING_LENGTH];

    int core_num;
    int core_count;

    char *ptr;


    /* ターゲット情報を取得して表示 */

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


    /* 文字列（コマンド）を返信 */
    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);
        printf("\n[Target Info]\n");
        printf("%s\n", str);
        
        if(target_type != NULL)
        {
            if(strstr(str, "RASP24") != NULL)
            {
                *target_type = TARGET_TYPE_RASP24;
            }
            else if(strstr(str, "AS-RASP") != NULL)
            {
                *target_type = TARGET_TYPE_AS_RASP;
            }
            else if(strstr(str, "RASPZX") != NULL)
            {
                *target_type = TARGET_TYPE_RASPZX;
            }
            else
            {
                *target_type = TARGET_TYPE_RASP_WL;
            }
        }
    }
    else
    {
        return -1;
    }


    /* FPGA内部のコアの情報を取得して表示 */
    
    /* 送信する文字列（コマンド）を作成 */
    sprintf(buffer, "0x%08x %d", WS_CMD_GET_SYSTEM_INFO, WS_SUB_CMD_GET_CORE_INFO);
    DEBUG_PRINT("Send : %s\n", buffer);


    /* 文字列（コマンド）を返信 */
    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 %d", &status, &core_num);
    if(status == 0)
    {
        printf("\n[Core Info]\n");
        
        ptr = strtok(buffer, " "); /* command  */
        ptr = strtok(NULL, " ");   /* status   */
        ptr = strtok(NULL, " ");   /* core_num */
        
        for(core_count=0; core_count<core_num; core_count++)
        {
            ptr = strtok(NULL, " ");
            sscanf(ptr, "%x", &value);

            printf("Module ID = %05x\n",       (value >> 12) & 0xfffff);
            printf("Version   = %x.%x.%x\n\n", (value >>  8) & 0xf, (value >> 4) & 0xf, value & 0xf);
        }
    }

    /* ファームウェアのビルド情報を取得して表示 */

    /* 送信する文字列（コマンド）を作成 */
    sprintf(buffer, "0x%08x %d", WS_CMD_GET_SYSTEM_INFO, WS_SUB_CMD_GET_BUILD_INFO);
    DEBUG_PRINT("Send : %s\n", buffer);


    /* 文字列（コマンド）を返信 */
    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)
    {
        printf("\n[Build Info]\n");

        ptr = strtok(buffer, " "); /* command  */
        ptr = strtok(NULL, " ");   /* status   */
        ptr = strtok(NULL, ".");   /* build    */
        printf("%s\n", ptr);
    }

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  ターゲットの識別情報を取得
**
*/

int WsGetTargetType(WS_HANDLE_t *h_ws, int *target_type)
{
    if(target_type == NULL)
    {
        return -1;
    }
    *target_type = h_ws->target_type;

    return 0;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  ターゲットの追加の識別情報を取得
**
*/

int WsGetTargetSubType(WS_HANDLE_t *h_ws, int *target_sub_type)
{
    if(target_sub_type == NULL)
    {
        return -1;
    }
    *target_sub_type = h_ws->target_sub_type;

    return 0;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  1サンプルあたりのバイト数を取得
**
*/

int WsGetBytePerSample(WS_HANDLE_t *h_ws, int *byte_per_sample)
{
    if(byte_per_sample == NULL)
    {
        return -1;
    }
    *byte_per_sample = h_ws->byte_per_sample;

    return 0;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  1フレームあたりのバイト数を取得
**
*/

int WsGetFrameSize(WS_HANDLE_t *h_ws, int *frame_size)
{
    if(frame_size == NULL)
    {
        return -1;
    }
    *frame_size = h_ws->frame_size;

    return 0;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  ヘッダサイズを取得
**
*/

int WsGetHeaderSize(WS_HANDLE_t *h_ws, int *header_size)
{
    if(header_size == NULL)
    {
        return -1;
    }
    *header_size = h_ws->header_size;

    return 0;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  同時サンプリングするCH数を取得
**
*/

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

    return 0;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  A/Dデータのサイズ(bit数)を取得する
**
*/

int WsGetResolutionBit(WS_HANDLE_t *h_ws, int *resolution_bit)
{
    if(resolution_bit == NULL)
    {
        return -1;
    }
    *resolution_bit = h_ws->resolution_bit;

    return 0;
}


/************************************************************
**
**  Public  : 
**
**  History : 2013.06.17 K.Takagi ZXでも問い合わせるように修正
**            2011.04.13 K.Takagi RASP-24以外は非サポート
**            2010.11.08 K.Takagi get_valの初期化を追加
**            2010.10.21 K.Takagi 新規作成
**
**  Description
**  -----------
**  RASP24に搭載しているアナログボードの枚数を取得
**
**  ハンドル作成時に呼び出すのでユーザアプリから呼び出したとしても
**  取り込みチャネルの再計算は不要
**
*/

int WsGetBoardNum(WS_HANDLE_t *h_ws, int *board_num)
{
    int status;
    int get_val;

    if(board_num == NULL)
    {
        return -1;
    }
    
    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        /* RASP-24は問い合わせする */
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        /* 初期のRASP-ZXは問い合わせしない */
        if(h_ws->target_sub_type == 0)
        {
            return ERR_UNSUPPORTED_CMD;
        }
    }
    else
    {
        return ERR_UNSUPPORTED_CMD;
    }
    get_val = 0;

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

/************************************************************
**
**  Public  : 
**
**  History : 2011.05.06 K.Takagi 時間表示を削除
**            2010.11.17 K.Takagi enable_channelの表示を変更
**            2010.10.25 K.Takagi 不要なデータを削除
**            2010.10.21 K.Takagi 有効チャネルの情報表示追加
**            2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  ハンドルの情報を表示（デバック用）
**
*/

int WsHandleShow(WS_HANDLE_t *h_ws)
{
    int board_no;

    printf("\n==============================\n");

    printf("ch_mode          = %d\n",h_ws->ch_mode);
    printf("ch_num           = %d\n",h_ws->ch_num);
    printf("board_num        = %d\n",h_ws->board_num);
    printf("max_ch_num       = %d\n",(h_ws->max_ch_num * h_ws->board_num));
    printf("header_flag      = %d\n",h_ws->header_flag);
    printf("header_count     = %d\n",h_ws->header_count);
    printf("header_size      = %d\n",h_ws->header_size);

    printf("enable_channels\n");
    for(board_no=0; board_no<h_ws->board_num; board_no++)
    {
        printf("  board[%2d]      = 0x%08x\n", board_no, h_ws->enable_channels[board_no]);
    }

    printf("resolution_bit   = %d\n",h_ws->resolution_bit);
    printf("sample_per_frame = %d\n",h_ws->sample_per_frame);
    printf("byte_per_sample  = %d\n",h_ws->byte_per_sample);
    printf("frame_size       = %d\n",h_ws->frame_size);
    printf("ad_shift         = %d\n",h_ws->ad_shift);

    printf("target_type      = %d\n",h_ws->target_type);
    printf("target_sub_type  = %d\n",h_ws->target_sub_type);
    
    printf("data_format      = 0x%x\n",h_ws->data_format);
    printf("gain             = %f\n", h_ws->gain);

#if 0
    printf("time_sec         = %d\n",h_ws->time_sec);
    printf("time_usec        = %d\n",h_ws->time_usec);

    printf("da_l_loop_mode   = %d\n",h_ws->da_l_loop_mode);
    printf("da_r_loop_mode   = %d\n",h_ws->da_r_loop_mode);
#endif
    
    printf("\n==============================\n");

    return 0;
}

/*----------------------------------------------------------*/
/*                       AD制御関係                         */
/*----------------------------------------------------------*/

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  サンプリング周波数の設定(Hzで指定)
**
*/

int WsSetSamplingFreq(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_FREQ, &set_val);

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  現在設定されているサンプリング周波数の取得(Hz)
**
*/

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

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

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


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  同期サンプリングするCH数を設定
**
**  Get側とアクセス方法を統一
**
**
*/

int WsSetChannelMode(WS_HANDLE_t *h_ws, int channel_mode)
{
    int status;
    int set_val;

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        /* RASP24では非サポート */
        status = ERR_UNSUPPORTED_CMD;
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        /* RASPZXでは非サポート */
        status = ERR_UNSUPPORTED_CMD;
    }
    else
    {
        /* フラグによるCH数選択 */
        set_val = channel_mode;
        status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_SET_CHANNEL, &set_val);
        
        if(status == 0)
        {
            UpdateChannelModeInfo(h_ws, channel_mode);
        }
    }

    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  同期サンプリングするCH数を取得
**
**  ファーム側で個別設定するようにした場合、
**  カスタム時のCH数が不明となるため
**  ライブラリ側で個別設定に変換
**
*/

int WsGetChannelMode(WS_HANDLE_t *h_ws, int *channel_mode)
{
    int status;
    int get_val;

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

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        /* RASP24では非サポート */
        status = ERR_UNSUPPORTED_CMD;
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        /* RASPZXでは非サポート */
        status = ERR_UNSUPPORTED_CMD;
    }
    else
    {
        /* フラグによるCH数設定 */
        status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_GET_CHANNEL, &get_val);
        *channel_mode = get_val;
        
        if(status == 0)
        {
            UpdateChannelModeInfo(h_ws, get_val);
        }
    }

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2013.06.17 K.Takagi ZX対応
**            2010.11.15 K.Takagi 取り込みチャネル総数の確認を修正
**            2010.10.21 K.Takagi 複数枚ボードに対応
**            2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  同期サンプリングするCHを個別に設定
**
*/

int WsSetCaptureChannels(WS_HANDLE_t *h_ws, int board_no, int channels)
{
    int status;
    int ch_num;
    int count;

    if((h_ws->target_type == TARGET_TYPE_RASP24) || ((h_ws->target_type == TARGET_TYPE_RASPZX) && (h_ws->target_sub_type > 0)))
    {
        if((board_no < 0) || (board_no >= h_ws->board_num))
        {
            /* 指定したボード番号のエラー */
            return ERR_BAD_PARAMETER;
        }

        channels = channels & 0x1ff;

        /* 取り込みチャネル総数の確認 */
        ch_num = 0;
        for(count=0; count<h_ws->board_num; count++)
        {
            if(count == board_no)
            {
                ch_num += CheckCaptureChannels(h_ws, channels, 0);
            }
            else
            {
                ch_num += CheckCaptureChannels(h_ws, h_ws->enable_channels[count], 0);
            }
        }
        
        if( (ch_num <= 0) || (ch_num > (h_ws->max_ch_num * h_ws->board_num)) )
        {
            /* 不正なチャネル構成 */
            return ERR_BAD_PARAMETER;
        }
        
        /* 個別CH設定コマンドを使って指定 */
        status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                   WS_CMD_SET_CAPTURE_CHANNELS,
                                   &board_no,
                                   &channels);

        if(status == 0)
        {
            h_ws->enable_channels[board_no] = channels;

            UpdateChannelModeInfo(h_ws, AD_CUSTOM_CH_MODE);
        }
    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2013.06.17 K.Takagi ZX対応
**            2010.11.15 K.Takagi 取り込みチャネル総数の確認を修正
**            2010.10.21 K.Takagi 複数枚ボードに対応
**            2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  同期サンプリングするCH情報を取得
**
*/

int WsGetCaptureChannels(WS_HANDLE_t *h_ws, int board_no, int *channels)
{
    int status;
    int get_val;
    int ch_num;
    int count;

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

    if((h_ws->target_type == TARGET_TYPE_RASP24) || ((h_ws->target_type == TARGET_TYPE_RASPZX) && (h_ws->target_sub_type > 0)))
    {
        if((board_no < 0) || (board_no >= h_ws->board_num))
        {
            /* 指定したボード番号のエラー */
            return ERR_BAD_PARAMETER;
        }
        get_val = 0;
        
        /* 個別CH設定コマンドを使って指定 */
        status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                   WS_CMD_GET_CAPTURE_CHANNELS,
                                   &board_no,
                                   &get_val);

        if(status == 0)
        {
            get_val = get_val & 0x1ff;

            /* 取り込みチャネル総数の確認 */
            ch_num = 0;
            for(count=0; count<h_ws->board_num; count++)
            {
                if(count == board_no)
                {
                    ch_num += CheckCaptureChannels(h_ws, get_val, 0);
                }
                else
                {
                    ch_num += CheckCaptureChannels(h_ws, h_ws->enable_channels[count], 0);
                }
            }
            
            /* 不正なチャネル数になることはないが一応チェック */
            if( (ch_num <= 0) || (ch_num > (h_ws->max_ch_num * h_ws->board_num)) )
            {
                /* 不正なチャネル構成 */
                return -1;
            }

            *channels = get_val;

            h_ws->enable_channels[board_no] = *channels;
            
            UpdateChannelModeInfo(h_ws, AD_CUSTOM_CH_MODE);
        }
    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }

    return status;
}

/************************************************************
**
**  Private : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  取り込みCHを個別設定した場合の状況確認
**
*/

static int CheckCaptureChannels(WS_HANDLE_t *h_ws, int capture_channels, int print_flag)
{
    int ch;
    int capture_ch_num;
    int capture_flag;

    capture_ch_num = 0;
    
    /* ボード1枚あたりの確認 */
    for(ch=0; ch<h_ws->max_ch_num; ch++)
    {
        capture_flag = (capture_channels >> ch) & 0x1;

        capture_ch_num += capture_flag;
        
        if(print_flag)
        {
            printf("CH[%02d] Capture : ", ch);
            if(capture_flag)
            {
                printf("Enable\n");
            }
            else
            {
                printf("Disable\n");
            }
        }
    }
    
    
    return capture_ch_num;
}

/************************************************************
**
**  Private : 
**
**  History : 2011.04.12 K.Takagi AS-RASP対応
**            2011.01.18 K.Takagi 無線RASP時のbyte_per_sampleの計算を修正
**                                RASP-24のヘッダサイズ記述をマクロ化
**            2010.11.08 K.Takagi ch_numの更新が抜けていたので修正
**            2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  接続相手と同時サンプリングCH数からフレームサイズ等を計算
**
*/

static int UpdateChannelModeInfo(WS_HANDLE_t *h_ws, int ch_mode)
{
    int ch_num;
    int board_no;


    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        /* RASP24の場合、ボードごとに取り込み有効のチャネルを確認 */
        ch_num = 0;
        for(board_no=0; board_no<h_ws->board_num; board_no++)
        {
            ch_num += CheckCaptureChannels(h_ws, h_ws->enable_channels[board_no], 0);
        }
        h_ws->ch_num = ch_num;

        /* ハードウェアによるヘッダ情報の付加状態 */
        if(h_ws->header_flag)
        {
            h_ws->header_size  = RASP24_HEADER_SIZE; 
        }
        else
        {
            h_ws->header_size  = 0; 
        }
        h_ws->byte_per_sample  = h_ws->resolution_bit * ch_num / 8;

        h_ws->sample_per_frame = RASP24_SAMPLE_PER_FRAME - 1;
        h_ws->frame_size       = h_ws->header_size + h_ws->byte_per_sample * h_ws->sample_per_frame; 
    }
    else if(h_ws->target_type == TARGET_TYPE_AS_RASP)
    {
        /* AS-RASPの場合、モードをCH数に変換 */
        switch(ch_mode)
        {
            case AD_8CH_MODE:
            {
                h_ws->ch_num             = 8;
                h_ws->enable_channels[0] = 0x00ff;
            }
            break;

            case AD_10CH_MODE:
            {
                h_ws->ch_num             = 10;
                h_ws->enable_channels[0] = 0x3ff;
            }
            break;

            default:
            {
                /* モードエラー */
                return -1;
            }
            break;
        }
        h_ws->sample_per_frame = AS_RASP_SAMPLE_PER_FRAME;
        h_ws->ch_mode          = ch_mode;
        h_ws->byte_per_sample  = h_ws->ch_num * sizeof(int);

        h_ws->header_size = h_ws->byte_per_sample; /* ヘッダは1サンプル分 */
        h_ws->frame_size  = h_ws->byte_per_sample * h_ws->sample_per_frame;
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        if(h_ws->target_sub_type == 0)
        {
            h_ws->ch_num             = 8;
            h_ws->enable_channels[0] = 0x00ff;
            
            h_ws->sample_per_frame = RASP_ZX_SAMPLE_PER_FRAME;
            
            h_ws->ch_mode          = AD_8CH_MODE;
            h_ws->byte_per_sample  = h_ws->ch_num * sizeof(int);
            
            h_ws->header_size = 0;
            h_ws->frame_size  = h_ws->byte_per_sample * h_ws->sample_per_frame;
        }
        else
        {
            /* RASP-ZXの場合、ボードごとに取り込み有効のチャネルを確認 */
            ch_num = 0;
            for(board_no=0; board_no<h_ws->board_num; board_no++)
            {
                ch_num += CheckCaptureChannels(h_ws, h_ws->enable_channels[board_no], 0);
            }
            h_ws->ch_num = ch_num;
            
            /* RASP-ZXはヘッダ情報なし */
            h_ws->header_size  = 0; 
            h_ws->byte_per_sample  = h_ws->resolution_bit * ch_num / 8;
            
            h_ws->sample_per_frame = RASP_ZX_SAMPLE_PER_FRAME;
            h_ws->frame_size       = h_ws->header_size + h_ws->byte_per_sample * h_ws->sample_per_frame; 
        }
    }
    else
    {
        /* 無線RASPの場合、モードをCH数に変換 */
        switch(ch_mode)
        {
            case AD_8CH_MODE:
            {
                h_ws->ch_num             = 8;
                h_ws->enable_channels[0] = 0x00ff;

                /* ヘッダ + データ1023サンプル分 */
                h_ws->sample_per_frame = RASP_WL_SAMPLE_PER_FRAME_8CH;
            }
            break;

            case AD_16CH_MODE:
            {
                h_ws->ch_num             = 16;
                h_ws->enable_channels[0] = 0xffff;

                /* ヘッダ + データ511サンプル分 */
                h_ws->sample_per_frame = RASP_WL_SAMPLE_PER_FRAME_16CH;
            }
            break;

            default:
            {
                /* モードエラー */
                return -1;
            }
            break;
        }
        h_ws->ch_mode          = ch_mode;
        h_ws->byte_per_sample  = h_ws->ch_num * sizeof(short);

        h_ws->header_size = h_ws->byte_per_sample; /* ヘッダは1サンプル分 */
        h_ws->frame_size  = h_ws->byte_per_sample * h_ws->sample_per_frame;
    }

    return 0;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.22 K.Takagi 新規作成
**
**  Description
**  -----------
**  同期サンプリングするCHを設定
**
*/

int WsSetCaptureChannelList(WS_HANDLE_t *h_ws, int *channel_list)
{
    int status;
    int count;
    int board_no;
    int ch;
    int set_val;
    int enable_channels[RASP24_MAX_BOARD];

    status = ERR_BAD_PARAMETER;

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        for(board_no=0; board_no<RASP24_MAX_BOARD; board_no++)
        {
            enable_channels[board_no] = 0;
        }
        
        for(count=0; count<(h_ws->board_num * RASP24_MAX_CH_NUM); count++)
        {
            ch = channel_list[count];
            if(ch < 0)
            {
                /* 負の番号で終端 */
                break;
            }
            board_no = ch / RASP24_MAX_CH_NUM;
            ch       = ch % RASP24_MAX_CH_NUM;
            
            if(board_no > h_ws->board_num)
            {
                /* 不正なCHが含まれているのでエラー */
                return ERR_BAD_PARAMETER;
            }
            
            enable_channels[board_no] |= (0x1 << ch);
        }

        if(count == 0)
        {
            /* 有効なCHが含まれていないのでエラー */
            return ERR_BAD_PARAMETER;
        }

        for(board_no=0; board_no<h_ws->board_num; board_no++)
        {
            /* 個別CH設定コマンドを使って指定 */
            set_val = enable_channels[board_no];
            status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                       WS_CMD_SET_CAPTURE_CHANNELS,
                                       &board_no,
                                       &set_val);
            
            if(status == 0)
            {
                h_ws->enable_channels[board_no] = enable_channels[board_no];
            }
            UpdateChannelModeInfo(h_ws, AD_CUSTOM_CH_MODE);
        }
    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.22 K.Takagi 新規作成
**
**  Description
**  -----------
**  同期サンプリングするCHを取得
**
*/

int WsGetCaptureChannelList(WS_HANDLE_t *h_ws, int *channel_list)
{
    int status;
    int count;
    int board_no;
    int ch;
    int enable_channels[RASP24_MAX_BOARD];

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        for(board_no=0; board_no<h_ws->board_num; board_no++)
        {
            /* 個別CH設定コマンドを使って取得 */
            status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                       WS_CMD_GET_CAPTURE_CHANNELS,
                                       &board_no,
                                       &enable_channels[board_no]);
            
            if(status == 0)
            {
                h_ws->enable_channels[board_no] = enable_channels[board_no];
                
            }
        }
        UpdateChannelModeInfo(h_ws, AD_CUSTOM_CH_MODE);

        /* 取り込むCHのフラグをCH番号に変換 */
        count = 0;
        for(board_no=0; board_no<h_ws->board_num; board_no++)
        {
            for(ch=0; ch<RASP24_MAX_CH_NUM; ch++)
            {
                if( (enable_channels[board_no] >> ch) & 0x1 )
                {
                    channel_list[count] = board_no * RASP24_MAX_CH_NUM + ch;
                    count++;
                }
            }
        }

    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2013.06.14 K.Takagi ZX対応
**            2010.10.22 K.Takagi 新規作成
**
**  Description
**  -----------
**  A/Dのゲインを設定
**
*/

int WsSetCaptureGain(WS_HANDLE_t *h_ws, int channel, int gain)
{
    int status;

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        if((channel < 0) || (channel >= (h_ws->board_num * h_ws->max_ch_num)) )
        {
            /* 不正なCHなのでエラー */
            return ERR_BAD_PARAMETER;
        }
        
        /* ゲイン指定 */
        status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                   WS_CMD_SET_CAPTURE_GAIN,
                                   &channel,
                                   &gain);
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        /* RASP-ZXにゲインはないがRASP-24互換のため正常終了と処理 */
        status = STATUS_OK;
    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }

    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2013.06.14 K.Takagi ZX対応
**            2010.10.22 K.Takagi 新規作成
**
**  Description
**  -----------
**  A/Dのゲインを取得
**
*/

int WsGetCaptureGain(WS_HANDLE_t *h_ws, int channel, int *gain)
{
    int status;
    int get_val;

    if(gain == NULL)
    {
        return -1;
    }
    
    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        if((channel < 0) || (channel >= (h_ws->board_num * h_ws->max_ch_num)) )
        {
            /* 不正なCHなのでエラー */
            return ERR_BAD_PARAMETER;
        }
        
        /* ゲイン取得 */
        status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                   WS_CMD_GET_CAPTURE_GAIN,
                                   &channel,
                                   &get_val);

        if(status == 0)
        {
            *gain = get_val;
        }
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        /* RASP-ZXにゲインはないがRASP-24互換のため正常終了と処理 */
        *gain  = 0;
        status = STATUS_OK;
    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2013.06.14 K.Takagi ZX対応
**            2010.10.22 K.Takagi 新規作成
**
**  Description
**  -----------
**  A/Dのゲインをまとめて設定
**
*/

int WsSetCaptureGainList(WS_HANDLE_t *h_ws, int *gain_list)
{
    int status;
    int channel;
    int gain;
    int count;

    status = ERR_BAD_PARAMETER;

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        for(count=0; count<(h_ws->board_num * h_ws->max_ch_num); count++)
        {
            channel = count;
            gain    = gain_list[channel];
            
            /* ゲイン指定 */
            status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                       WS_CMD_SET_CAPTURE_GAIN,
                                       &channel,
                                       &gain);

            if(status != 0)
            {
                /* エラーが発生したら終了 */
                break;
            }
        }

    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        /* RASP-ZXにゲインはないがRASP-24互換のため正常終了と処理 */
        status = STATUS_OK;
    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }

    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2013.06.14 K.Takagi ZX対応
**            2010.10.22 K.Takagi 新規作成
**
**  Description
**  -----------
**  A/Dのゲインをまとめて取得
**
*/

int WsGetCaptureGainList(WS_HANDLE_t *h_ws, int *gain_list)
{
    int status;
    int channel;
    int gain = 0;
    int count;

    status = ERR_BAD_PARAMETER;

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        for(count=0; count<(h_ws->board_num * h_ws->max_ch_num); count++)
        {
            channel = count;

            /* ゲイン取得 */
            status  = WsControlClient2(h_ws->control_server_info.socket_fd,
                                       WS_CMD_GET_CAPTURE_GAIN,
                                       &channel,
                                       &gain);

            if(status == 0)
            {
                gain_list[channel] = gain;
            }
            else
            {
                /* エラーが発生したら終了 */
                break;
            }
        }

    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        /* RASP-ZXにゲインはないがRASP-24互換のため正常終了と処理 */
        for(count=0; count<(h_ws->board_num * h_ws->max_ch_num); count++)
        {
            gain_list[count] = gain;
        }
        status = STATUS_OK;
    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2013.06.14 K.Takagi ZX対応
**            2011.01.18 K.Takagi RASP24のヘッダサイズをマクロ化
**            2010.10.21 K.Takagi 新規作成
**
**  Description
**  -----------
**  RASP24にてハードウェアでヘッダを付加するかの設定
**
*/

int WsSetHeaderFlag(WS_HANDLE_t *h_ws, int header_flag)
{
    int status;
    int set_val;

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        set_val = header_flag;
        status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                  WS_CMD_SET_AD_HEADER_FLAG,
                                  &set_val);
        if(status == 0)
        {
            h_ws->header_flag = header_flag;

            /* ハードウェアによるヘッダ情報の付加状態 */
            if(h_ws->header_flag)
            {
                h_ws->header_size  = RASP24_HEADER_SIZE; 
            }
            else
            {
                h_ws->header_size  = 0; 
            }
            h_ws->frame_size       = h_ws->header_size + h_ws->byte_per_sample * h_ws->sample_per_frame; 
        }
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        /* RASP-ZXは常に無効 */
        if(header_flag == 0)
        {
            status = STATUS_OK;
        }
        else
        {
            status = ERR_BAD_PARAMETER;
        }
    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2013.06.14 K.Takagi ZX対応
**            2011.01.18 K.Takagi RASP24のヘッダサイズをマクロ化
**            2010.10.21 K.Takagi 新規作成
**
**  Description
**  -----------
**  RASP24のハードウェアによるヘッダ付加状態を取得
**
*/

int WsGetHeaderFlag(WS_HANDLE_t *h_ws, int *header_flag)
{
    int status;
    int get_val;

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

    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                  WS_CMD_GET_AD_HEADER_FLAG,
                                  &get_val);
        
        if(status == 0)
        {
            h_ws->header_flag = get_val;
            *header_flag      = get_val;
            
            /* ハードウェアによるヘッダ情報の付加状態 */
            if(h_ws->header_flag)
            {
                h_ws->header_size  = RASP24_HEADER_SIZE; 
            }
            else
            {
                h_ws->header_size  = 0; 
            }
            h_ws->frame_size       = h_ws->header_size + h_ws->byte_per_sample * h_ws->sample_per_frame; 
        }
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        /* RASP-ZXではヘッダは常にOFF */
        *header_flag = 0;
        status = STATUS_OK;
    }
    else
    {
        status = ERR_UNSUPPORTED_CMD;
    }
    
    return status;
}


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

int WsADStart(WS_HANDLE_t *h_ws)
{
    int status;

    h_ws->header_count = 0;

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

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  AD停止
**
*/

int WsADStop(WS_HANDLE_t *h_ws)
{
    int status;
    int last_status;
    
    int  io_stat;
#ifdef WIN32
    u_long rest_size;
#else
    int  rest_size;
#endif
    int  read_size;
    char dummy[1024];
    
    last_status = 0;
    status  = WsControlClient(h_ws->control_server_info.socket_fd, WS_CMD_AD_STOP, &last_status);
    
    /* データ破棄 */
    io_stat = ioctl(h_ws->data_server_info.socket_fd, FIONREAD, &rest_size);
    while((io_stat != -1) && (rest_size > 0))
    {
        read_size = read(h_ws->data_server_info.socket_fd, dummy, 1024);
        
        if(read_size < 0)
        {
            break;
        }
        
        io_stat = ioctl(h_ws->data_server_info.socket_fd, FIONREAD, &rest_size);
    }
    
    return last_status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  AD&DA同時開始
**  DA側の準備は完了していることを前提
**
*/

int WsAdDaStart(WS_HANDLE_t *h_ws)
{
    int status;

    h_ws->header_count = 0;

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

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2011.04.13 K.Takagi 新規作成／AS-RASPより移植
**
**  Description
**  -----------
**  A/Dの動作モード設定
**
*/

int WsSetAdMode(WS_HANDLE_t *h_ws, int ad_mode)
{
    int status;
    int set_val;

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

    set_val = ad_mode;
    status  = WsControlClient(h_ws->control_server_info.socket_fd,
                              WS_CMD_SET_AD_MODE,
                              &set_val);
    
    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2011.04.13 K.Takagi 新規作成／AS-RASPより移植
**
**  Description
**  -----------
**  A/Dの動作モード取得
**
*/

int WsGetAdMode(WS_HANDLE_t *h_ws, int *ad_mode)
{
    int status;
    int get_val;

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

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

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


/************************************************************
**
**  Public  : 
**
**  History : 2011.04.21 K.Takagi 新規作成
**
**  Description
**  -----------
**  A/D停止中のモード設定
**
*/

int WsSetAdSleepMode(WS_HANDLE_t *h_ws, int sleep_mode)
{
    int status;
    int set_val;

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

    set_val = sleep_mode;
    status  = WsControlClient(h_ws->control_server_info.socket_fd,
                              WS_CMD_SET_AD_SLEEP_MODE,
                              &set_val);
    
    return status;
}

/************************************************************
**
**  Public  : 
**
**  History : 2011.04.21 K.Takagi 新規作成
**
**  Description
**  -----------
**  A/D停止中のモード取得
**
*/

int WsGetAdSleepMode(WS_HANDLE_t *h_ws, int *sleep_mode)
{
    int status;
    int get_val;

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

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

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

/*----------------------------------------------------------*/
/*                     データ取得関係                       */
/*----------------------------------------------------------*/

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  データ取得を実行するread()のラッパ関数
**
*/

int WsDataRead(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size)
{
    int read_size;

    /* サーバーからデータを取得 */
    read_size = read(h_ws->data_server_info.socket_fd, buffer, read_req_size);
    
    return read_size;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.21 K.Takagi RASP24はヘッダ無効時のみ対応
**            2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  データ取得を実行するread()のラッパ関数
**    1サンプルデータの境界になるように調整する機能付き
**
**  ソケットオプションのSO_RCVLOWATはselect/pollでは機能しないが
**  readでは機能する
**
**
*/

int WsSampleDataRead(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size)
{
    unsigned int tmp;
    ssize_t read_size;
    unsigned int total_read_size;
#ifdef WIN32
    u_long readable_size;
#else
    unsigned int readable_size;
#endif
    unsigned int user_req_size;
    unsigned int byte_per_sample;

    int    io_stat;
    fd_set rfds;
    struct timeval timeout;


    if((h_ws->target_type == TARGET_TYPE_RASP24) && (h_ws->header_flag))
    {
        /* RASP24ではヘッダ無効の場合のみ実行可能 */
        return -1;
    }

    /* 1sampleのデータサイズ以下の要求はエラー */
    byte_per_sample = h_ws->byte_per_sample;
    if(read_req_size < byte_per_sample)
    {
        return -1;
    }
 

    /* 要求量を1sampleの倍数に調整 */
    user_req_size = read_req_size - (read_req_size % byte_per_sample);

#ifdef DEBUG_LOG
    printf("bps = %d, user_req = %d\n", byte_per_sample, user_req_size);
    fflush(stdout);
#endif

    total_read_size = 0;
    do
    {
        
        /* read可能か確認 */
        do
        {
            timeout.tv_sec  = 1;
            timeout.tv_usec = 0;
            
            FD_ZERO(&rfds);
            FD_SET(h_ws->data_server_info.socket_fd, &rfds);
            
            select(h_ws->data_server_info.socket_fd+1, &rfds, NULL, NULL, &timeout);
        }while(FD_ISSET(h_ws->data_server_info.socket_fd, &rfds) == 0);
        
        
        /* バッファリングされているデータ量を確認 */
        io_stat = ioctl(h_ws->data_server_info.socket_fd, FIONREAD, &readable_size);
        if(io_stat < 0)
        {
            return io_stat;
        }
        
        tmp = total_read_size + readable_size;

        /* バッファから読み出すサイズを1sampleの倍数に調整 */
        if(tmp < byte_per_sample)
        {
            /* 1sampleに満たない場合はあるだけ読み出す */
            read_req_size = readable_size;
        }
        else
        {
            if(tmp >= user_req_size)
            {
                /* ユーザ要求より多く読み出し可能なら、要求量まで読み出す */
                read_req_size = user_req_size - total_read_size;
            }
            else
            {
                /* 1sampleの倍数になるように読み出し量を調整 */
                tmp = tmp - (tmp % byte_per_sample);
                read_req_size = tmp - total_read_size;
            }
        }

#ifdef DEBUG_LOG
        printf("req = %d, readable = %d, total = %d\n", read_req_size, readable_size, total_read_size);
        fflush(stdout);
#endif

        do
        {
            /* サーバーからデータを取得 */
            read_size = read(h_ws->data_server_info.socket_fd, &buffer[total_read_size], read_req_size);
            
            /* エラー判定 */
            if(read_size < 0)
            {
                return read_size;
            }
            
            read_req_size   -= read_size;
            total_read_size += read_size;
            
        }while(read_req_size > 0);
        
    }while(total_read_size < byte_per_sample);


#ifdef DEBUG_LOG
    printf("total = [%d]\n\n", total_read_size);
    fflush(stdout);
#endif
    /*
    printf("%d\n", total_read_size % byte_per_sample);
    */
    return total_read_size;
}


/************************************************************
**
**  Public  : 
**
**  History : 2011.04.12 K.Takagi 不要コードを削除
**            2010.10.21 K.Takagi 新規作成
**                                ヘッダなしでの取り込みに対応
**
**  Description
**  -----------
**  フレーム単位でデータ取得を実行するread()のラッパ関数
**  ヘッダのチェック＆除去
**
**    1frame = N-ch * 4byte * 1023sampleのデータ取得
**                    又は
**    1frame = N-ch * 2byte * 1023sampleのデータ取得
**
*/

int RASP24_WsFrameRead(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size)
{
    int read_size;

    int *header;
    int header_status;
    int header_count;
    int header_size;
    int sample_size;
    int frame_size;
    int offset;

    header_size = h_ws->header_size;
    sample_size = h_ws->byte_per_sample;
    frame_size  = h_ws->frame_size;

    LOG_PRINT("Called %s.\n", __func__);
        
    /* バッファサイズが1frame未満はエラー */
    if(read_req_size < frame_size)
    {
        return -1;
    }

    /* 1frame分のデータ取得 */
    offset = 0;
    read_req_size = frame_size;
    while(read_req_size > 0)
    {
        /* サーバーからデータを取得 */
        read_size = read(h_ws->data_server_info.socket_fd,
                         &buffer[offset],
                         read_req_size);

        /* エラー判定 */
        if(read_size < 0)
        {
            break;
        }
        
        read_req_size -= read_size;
        offset += read_size;
    }
    
    /* エラー */
    if(read_req_size > 0)
    {
        return read_size;
    }

    /* ヘッダ有効時はヘッダチェック */
    if(h_ws->header_flag)
    {
        header        = (int *)buffer;
        
        header_count  = *header & 0x000fffff;
        header_status = *header & 0x00f00000;
        
        LOG_PRINT("Header count %d / %d\n", header_count, h_ws->header_count);
        
        /* RASP24側でエラー */
        if(header_status != 0)
        {
            return -1;
        }
        
        /* フレーム数の不一致 */
        if(header_count != h_ws->header_count)
        {
            return -1;
        }

        /* ヘッダを除去 */
        frame_size -= header_size;
        memmove(&buffer[0], &buffer[header_size], frame_size);
    }

    h_ws->header_count = (h_ws->header_count + 1) & 0x000fffff;
    
    return frame_size;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  無線RASP用 データ取得を実行するread()のラッパ関数
**    1frame = 16ch * 2Byte *  512sampleのデータ取得
**                  or
**    1frame =  8ch * 2byte * 1023sampleのデータ取得
**    ヘッダのチェック＆除去
**
*/

int RASP_WL_WsFrameRead(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size)
{
    int read_size;

    int *header;
    int header_status;
    int header_count;
    int sample_size;
    int frame_size;
    int offset;

    sample_size = h_ws->byte_per_sample;
    frame_size  = h_ws->frame_size;

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

    /* バッファサイズが1frame未満はエラー */
    if(read_req_size < frame_size)
    {
        return -1;
    }

    /* 1frame分のデータ取得 */
    offset = 0;
    read_req_size = frame_size;
    while(read_req_size > 0)
    {
        /* サーバーからデータを取得 */
        read_size = read(h_ws->data_server_info.socket_fd,
                         &buffer[offset],
                         read_req_size);

        /* エラー判定 */
        if(read_size < 0)
        {
            break;
        }
        
        read_req_size -= read_size;
        offset += read_size;
    }
    
    /* エラー */
    if(read_req_size > 0)
    {
        return read_size;
    }
    
    /* ヘッダチェック */
    header = (int *)buffer;
    
    /* 無線RASPは上位4bitがステータス、下位28bitがカウント */
    header_count  = *header & 0x0fffffff;
    header_status = *header & 0xf0000000;

    LOG_PRINT("Header count %d / %d\n", header_count, h_ws->header_count);

    /* 無線RASP側でエラー */
    if(header_status != 0)
    {
        return -1;
    }

    /* フレーム数の不一致 */
    if(header_count != h_ws->header_count)
    {
        return -1;
    }

    h_ws->header_count = (h_ws->header_count + 1) & 0x0fffffff;

    frame_size -= sample_size;
    memmove(&buffer[0], &buffer[sample_size], frame_size);
    
    
    return frame_size;
}


/************************************************************
**
**  Public  : 
**
**  History : 2011.04.12 K.Takagi 新規作成／AS-RASPより移植
**
**  Description
**  -----------
**  フレーム単位でデータ取得を実行するread()のラッパ関数
**  ヘッダのチェック＆除去
**
**    1frame = 10ch * 4byte * 1023sampleのデータ取得
**                    又は
**    1frame =  8ch * 4byte * 1023sampleのデータ取得
**
*/

int AS_RASP_WsFrameRead(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size)
{
    int read_size;

    int *header;
    int header_status;
    int header_count;
    int header_size;
    int sample_size;
    int frame_size;
    int offset;

    header_size = h_ws->header_size;
    sample_size = h_ws->byte_per_sample;
    frame_size  = h_ws->frame_size;

    LOG_PRINT("Called %s.\n", __func__);
        
    /* バッファサイズが1frame未満はエラー */
    if(read_req_size < frame_size)
    {
        return -1;
    }

    /* 1frame分のデータ取得 */
    offset = 0;
    read_req_size = frame_size;
    while(read_req_size > 0)
    {
        /* サーバーからデータを取得 */
        read_size = read(h_ws->data_server_info.socket_fd,
                         &buffer[offset],
                         read_req_size);

        /* エラー判定 */
        if(read_size < 0)
        {
            break;
        }
        
        read_req_size -= read_size;
        offset += read_size;
    }
    
    /* エラー */
    if(read_req_size > 0)
    {
        return read_size;
    }

    header        = (int *)buffer;
    header_count  = *header & 0x000fffff;
    header_status = *header & 0x00f00000;
    
    LOG_PRINT("Header count %d / %d\n", header_count, h_ws->header_count);
    
    /* AS-RASP側でエラー */
    if(header_status != 0)
    {
        return -1;
    }
    
    /* フレーム数の不一致 */
    if(header_count != h_ws->header_count)
    {
        return -1;
    }
    
    /* ヘッダを除去 */
    frame_size -= header_size;
    memmove(&buffer[0], &buffer[header_size], frame_size);
    
    h_ws->header_count = (h_ws->header_count + 1) & 0x000fffff;
    
    return frame_size;
}

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  フレーム単位でデータ取得を実行するread()のダミーラッパ関数
**
*/

int WsFrameReadDummy(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size)
{
    return -1;
}


/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  無線RASP用 データ取得を実行するread()のラッパ関数
**    1frame = 16ch * 2Byte *  512sampleのデータ取得
**                  or
**    1frame =  8ch * 2byte * 1023sampleのデータ取得
**    ヘッダのチェック＆除去
**    float変換
**
*/

int RASP_WL_WsFrameReadFloatFormat(WS_HANDLE_t *h_ws, char *buffer, size_t read_req_size)
{
    int read_size;

    int *header;
    int header_status;
    int header_count;
    int sample_size;
    int frame_size;
    int offset;
    int header_size;

    int  count;
    char *work_buffer;

    short  *in_data;
    float  *out_data;
    float   gain;

    sample_size = h_ws->byte_per_sample;
    frame_size  = h_ws->frame_size;
    header_size = sample_size / sizeof(float) * sizeof(short);

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

    /* バッファサイズが1frame未満はエラー */
    if(read_req_size < frame_size)
    {
        return -1;
    }

    /* 1frame分のデータ取得 */
    offset = 0;
    read_req_size = frame_size / sizeof(float) * sizeof(short);
    work_buffer   = (char *)h_ws->work_buffer;
    while(read_req_size > 0)
    {
        /* サーバーからデータを取得 */
        read_size = read(h_ws->data_server_info.socket_fd,
                         &work_buffer[offset],
                         read_req_size);

        /* エラー判定 */
        if(read_size < 0)
        {
            break;
        }
        
        read_req_size -= read_size;
        offset += read_size;
    }
    
    /* エラー */
    if(read_req_size > 0)
    {
        return read_size;
    }
    
    /* ヘッダチェック */
    header = (int *)work_buffer;
    
    /* 無線RASPは上位4bitがステータス、下位28bitがカウント */
    header_count  = *header & 0x0fffffff;
    header_status = *header & 0xf0000000;

    LOG_PRINT("Header count %d / %d\n", header_count, h_ws->header_count);

    /* 無線RASP側でエラー */
    if(header_status != 0)
    {
        return -1;
    }

    /* フレーム数の不一致 */
    if(header_count != h_ws->header_count)
    {
        return -1;
    }

    h_ws->header_count = (h_ws->header_count + 1) & 0x0fffffff;

    
    /* ヘッダ分は除去 */
    frame_size -= sample_size;

    in_data  = (short *)(work_buffer + header_size);
    out_data = (float *)buffer;

    gain = h_ws->gain / (float)0x7fff;
    for(count=0; count<(frame_size/sizeof(float)); count++)
    {
        out_data[count] = in_data[count] * gain;
    }
    
    return frame_size;
}


/************************************************************
**
**  Public  : 
**
**  History : 2013.06.17 K.Takagi ZX対応
**            2011.04.13 K.Takagi AS-RASP対応
**            2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  A/Dデータフォーマットを設定
**
*/

int WsSetAdDataFormat(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_AD_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;

            /* WsFrameRead関数のコールバックを設定 */
            WsFrameRead = &RASP24_WsFrameRead;
            
            UpdateChannelModeInfo(h_ws, h_ws->ch_mode);
        }
    }
    else if(h_ws->target_type == TARGET_TYPE_AS_RASP)
    {
        /* AS-RASPでは32bitモードのみ */
        h_ws->data_format = DATA_FORMAT_32BIT_PCM;
        
        WsFrameRead = &AS_RASP_WsFrameRead;

        UpdateChannelModeInfo(h_ws, h_ws->ch_mode);
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        if(h_ws->target_sub_type == 0)
        {
            format_type = DATA_FORMAT_32BIT_PCM;
            
            h_ws->resolution_bit = 32;
            
            h_ws->data_format = format_type;
            
            /* WsFrameRead関数のコールバックを設定 */
            WsFrameRead = &RASP24_WsFrameRead;
            
            UpdateChannelModeInfo(h_ws, h_ws->ch_mode);
        }
        else
        {
            /* 32bitデータフォーマット選択 */
            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_AD_FORMAT,
                                      &set_val);
            
            if(status == 0)
            {
                /* 2013.06では32bitのみ対応 */
                if(format_type == DATA_FORMAT_32BIT_PCM)
                {
                    h_ws->resolution_bit = 32;
                }
                else if(format_type == DATA_FORMAT_24BIT_PCM)
                {
                    h_ws->resolution_bit = 24;
                }
                else if(format_type == DATA_FORMAT_16BIT_PCM)
                {
                    h_ws->resolution_bit = 16;
                }
                else
                {
                    /* このケースはないはず */
                    return -1;
                }
                h_ws->data_format = format_type;
                
                /* WsFrameRead関数のコールバックを設定 */
                WsFrameRead = &RASP24_WsFrameRead;
                
                UpdateChannelModeInfo(h_ws, h_ws->ch_mode);
            }
        }
    }
    else
    {
        /* 無線RASPでは16bitモードのみ */
        h_ws->data_format = DATA_FORMAT_16BIT_PCM;
        
        WsFrameRead = &RASP_WL_WsFrameRead;

        UpdateChannelModeInfo(h_ws, h_ws->ch_mode);
    }

    return status;
}

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

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

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

    status  = 0;
    get_val = 0;
    if(h_ws->target_type == TARGET_TYPE_RASP24)
    {
        status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                  WS_CMD_GET_AD_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;

            /* WsFrameRead関数のコールバックを設定 */
            WsFrameRead = &RASP24_WsFrameRead;
            
            UpdateChannelModeInfo(h_ws, h_ws->ch_mode);
        }
    }
    else if(h_ws->target_type == TARGET_TYPE_RASPZX)
    {
        if(h_ws->target_sub_type == 0)
        {
            *format_type = h_ws->data_format;
        }
        else
        {
            /* 拡張できるように問い合わせを実行（2013.06では32bitのみ対応） */
            status  = WsControlClient(h_ws->control_server_info.socket_fd,
                                      WS_CMD_GET_AD_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_24BIT_PCM)
                {
                    h_ws->resolution_bit = 24;
                }
                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;
                
                /* WsFrameRead関数のコールバックを設定 */
                WsFrameRead = &RASP24_WsFrameRead;
                
                UpdateChannelModeInfo(h_ws, h_ws->ch_mode);
            }
        }
    }
    else
    {
        /* 
         * 従来の方式ではホストPC側でのみ処理しているので
         * コールバックの再設定等は不要
         */
        
        *format_type = h_ws->data_format;
    }

    return status;
}

/*----------------------------------------------------------*/
/*                      Word Clock関係                      */
/*----------------------------------------------------------*/

/************************************************************
**
**  Public  : 
**
**  History : 2010.10.18 K.Takagi 新規作成
**
**  Description
**  -----------
**  外部ユニット同期用クロック（Word Clock）の出力ON/OFF
**
*/

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

    set_val = mode;
    status  = WsControlClient(h_ws->control_server_info.socket_fd,
                              WS_CMD_SET_WORD_CLOCK_MODE,
                              &set_val);

    return status;
}


/************************************************************
**
**  Public  : 
**
**  History : 2011.04.13 K.Takagi RASP-24以外は非サポート
**            2011.01.30 K.Takagi 新規作成
**
**  Description
**  -----------
**  RASP-24システム電源OFF
**
*/

int WsSystemPowerDown(WS_HANDLE_t *h_ws)
{
    int status;
    int set_val;

    if(h_ws->target_type != TARGET_TYPE_RASP24)
    {
        return ERR_UNSUPPORTED_CMD;
    }
    
    set_val = 0;
    status  = WsControlClient(h_ws->control_server_info.socket_fd,
                              WS_CMD_SYSTEM_POWER_DOWN,
                              &set_val);

    return status;
}

/*----------------------------------------------------------*/
/*                         D/A関係                          */
/*----------------------------------------------------------*/

/* 別ファイルをインクルード */
#include "rasp-netapi-da.c"


/*----------------------------------------------------------*/
/*                    RASP-LC無線版関係                     */
/*----------------------------------------------------------*/

/* 別ファイルをインクルード */
#include "rasp-lcw-api.c"


/* EOF */
