/************************************************************
**
**     Object name : 
**
**     Description
**     -- -- -- -- -- -- -- --
**     バッファ制御
**
**
**     History
**     -- -- -- -- -- -- -- --
**     2013.03.22 K.Takagi PS/EYE対応のマージ
**     2013.03.05 K.Takagi 音源情報の取得でエラー時の戻り値を変更
**     2012.12.06 K.Takagi 取得時はバッファへのポインタを返すように変更
**                         パラメータ未設定の場合は ch=8,length=257 で初期化
**     2012.11.30 K.Takagi 取得時もデータコピー
**     2012.11.29 K.Takagi 新規作成
**
**     Copyright (c) 2012
**     System In Frontier,Inc.
**     All rights reserved. 
**
**     当社の許可なしに複製および転載を禁ず
**
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "HA_log.h"
#include "android_hark.h"

#include "HABuffer.h"
#include "MatrixMemoryAllocate.h"

//////////#include "header.h"

#ifdef STANDALON_TEST
#define HA_BUFFER_NUM       8 // テスト用
#else
//#define HA_BUFFER_NUM       128
#define HA_BUFFER_NUM       256
#endif
#define HA_BUFFER_NUM_MASK  (HA_BUFFER_NUM-1)


/* FFTデータを管理するためのバッファ用構造体 */
typedef struct 
{
    int full;
    int channel;
    int length;
    FFT_DATA_ARY_t ary[HA_BUFFER_NUM]; /* 操作で使用するための変数 */
    COMPLEX_FLOAT ***work_buffer;         /* データを格納する実際のバッファ */
} FFT_DATA_ARY_BUF_t;


typedef struct 
{
    int full;
    SOURCE_DATA_ARY_t ary[HA_BUFFER_NUM]; /* 操作で使用するための変数 */
} SOURCE_DATA_ARY_BUF_t;



static int fft_data_set_pos;
static int fft_data_get_pos;
static FFT_DATA_ARY_BUF_t fft_data_ary_buf;
static SOURCE_DATA_ARY_BUF_t source_data_ary_buf;
static SOURCE_DATA_ARY_t no_source_ary;
static SOURCE_DATA_ARY_BUF_t zc_source_data_ary_buf;


/******************************************************************************
**
**  History
**  -----------
**  2012.11.29 K.Takagi 新規作成
**
**  Description
**  -----------
**  パラメータ設定
**  Initの前に実行すること
*/

int HABufferSetParam(int fft_channel, int fft_length)
{
    fft_data_ary_buf.channel = fft_channel;
    fft_data_ary_buf.length  = fft_length;
    
    return 0;
}

/******************************************************************************
**
**  History
**  -----------
**  2013.07.19 M.Takigahira 未指定時のCH数, FFT長にheader.hのデフォルトを使用
**  2013.03.22 K.Takagi     未指定時のCH数をマクロ化
**  2012.12.06 K.Takagi     チャネル数、FFT長が未指定の場合はデフォルトを設定
**  2012.11.29 K.Takagi     新規作成
**
**  Description
**  -----------
**  バッファ確保などの初期化
**
*/

int HABufferInit(void)
{
    int index;
    
    fft_data_set_pos = 0;
    fft_data_get_pos = 0;
    
    /* チャネル数、FFT長が未指定の場合はデフォルト設定 */
    if(fft_data_ary_buf.channel <= 0)
    {
    	fft_data_ary_buf.channel = ARY_NUM_MIC; //change from _CH_VAL_
    }
    if(fft_data_ary_buf.length <= 0)
    {
        fft_data_ary_buf.length = ARY_NUM_FFT; //change from (512 / 2 + 1)
    }
    
    if(fft_data_ary_buf.work_buffer != NULL)
    {
        /* 確保済みなら一旦解放する */
        free(fft_data_ary_buf.work_buffer[0][0]);
        free(fft_data_ary_buf.work_buffer[0]);
        free(fft_data_ary_buf.work_buffer);
    }
    
    /* バッファ確保 */
    fft_data_ary_buf.work_buffer = (COMPLEX_FLOAT ***)MemoryAllocate3D(HA_BUFFER_NUM,
                                                                       fft_data_ary_buf.channel,
                                                                       fft_data_ary_buf.length,
                                                                       sizeof(COMPLEX_FLOAT));
    
    if(fft_data_ary_buf.work_buffer == NULL)
    {
        return -1;
    }
    
    for(index=0; index<HA_BUFFER_NUM; index++)
    {
        fft_data_ary_buf.ary[index].count = -1;
        fft_data_ary_buf.ary[index].data = fft_data_ary_buf.work_buffer[index];
    }
    
    for(index=0; index<HA_BUFFER_NUM; index++)
    {
        source_data_ary_buf.ary[index].count      = -1;
        source_data_ary_buf.ary[index].source_num = 0;
    }
    
    for(index=0; index<HA_BUFFER_NUM; index++)
    {
        zc_source_data_ary_buf.ary[index].count      = -1;
        zc_source_data_ary_buf.ary[index].source_num = 0;
    }
    
    return 0;
}


/******************************************************************************
**
**  History
**  -----------
**  2012.11.29 K.Takagi 新規作成
**
**  Description
**  -----------
**  バッファの解放など
**
*/

int HABufferRelease(void)
{
    
    if(fft_data_ary_buf.work_buffer != NULL)
    {
        free(fft_data_ary_buf.work_buffer[0][0]);
        free(fft_data_ary_buf.work_buffer[0]);
        free(fft_data_ary_buf.work_buffer);
        fft_data_ary_buf.work_buffer = NULL;
    }
    
    
    return 0;
}


/******************************************************************************
**
**  History
**  -----------
**  2012.11.29 K.Takagi 新規作成
**
**  Description
**  -----------
**  内部情報のクリア
**
*/

void HABufferClear(void)
{
    int index;
    
    fft_data_set_pos = 0;
    fft_data_get_pos = HA_BUFFER_NUM_MASK;

    for(index=0; index<HA_BUFFER_NUM; index++)
    {
        fft_data_ary_buf.ary[index].count = -1;
    }
    
    for(index=0; index<HA_BUFFER_NUM; index++)
    {
        source_data_ary_buf.ary[index].count      = -1;
        source_data_ary_buf.ary[index].source_num = 0;
    }
}


/******************************************************************************
**
**  History
**  -----------
**  2012.11.29 K.Takagi 新規作成
**
**  Description
**  -----------
**  FFTデータの設定
**    まずは常に書き込み成功とする
**
*/
int HABufferSetFFTData(int count, FFT_DATA_ARY_t *data_ary)
{
    int set_req_pos;
    int channel;
    int length;
    COMPLEX_FLOAT **data;
    
    set_req_pos = count & HA_BUFFER_NUM_MASK;
    
    /* データコピー */
    fft_data_ary_buf.ary[set_req_pos].count = count;
    length = fft_data_ary_buf.length;
    data   = fft_data_ary_buf.ary[set_req_pos].data;
    

    for(channel=0; channel<fft_data_ary_buf.channel; channel++)
    {
    	memcpy(data[channel], data_ary->data[channel], sizeof(COMPLEX_FLOAT) * length);
    }
    
    return 0;
}


/******************************************************************************
**
**  History
**  -----------
**  2012.12.06 K.Takagi 取得時はバッファへのポインタを返すように変更
**  2012.11.30 K.Takagi データをコピーするように修正
**  2012.11.29 K.Takagi 新規作成
**
**  Description
**  -----------
**  FFTデータの取得
**    要求位置に保存されているデータのカウンタ値が異なるとエラー
**
*/

FFT_DATA_ARY_t *HABufferGetFFTData(int count)
{
    int get_req_pos;
    
    get_req_pos = count & HA_BUFFER_NUM_MASK;
    
    /* 要求したデータのカウント値が一致しなければエラー */
    if(fft_data_ary_buf.ary[get_req_pos].count != count)
    {
        return NULL;
    }
    
    /* 読み出した位置を記録 */
    fft_data_get_pos = get_req_pos;
    fft_data_ary_buf.full = 0;
    
    return &fft_data_ary_buf.ary[get_req_pos];
}



/******************************************************************************
**
**  History
**  -----------
**  2013.07.03 M.Takigahira mask追加
**  2012.11.29 K.Takagi     新規作成
**
**  Description
**  -----------
**  音源位置データの設定
**    まずは常に書き込み成功とする
**
*/
//  2013.10.16 M.Takigahira TFINDEX対応追加

int HABufferSetSourceData(int count, SOURCE_DATA_ARY_t *data_ary)
{
    int set_req_pos;
    int index;
    SOURCE_t *data;
    
    set_req_pos = count & HA_BUFFER_NUM_MASK;
    
    /* データコピー */
    source_data_ary_buf.ary[set_req_pos].count = count;
    source_data_ary_buf.ary[set_req_pos].source_num = data_ary->source_num;
    data = source_data_ary_buf.ary[set_req_pos].data;
    
    for(index=0; index<data_ary->source_num; index++)
    {
        data[index].x[0]             = data_ary->data[index].x[0];
        data[index].x[1]             = data_ary->data[index].x[1];
        data[index].x[2]             = data_ary->data[index].x[2];
        
        data[index].power            = data_ary->data[index].power;
        data[index].id               = data_ary->data[index].id;
        data[index].remaining        = data_ary->data[index].remaining;

        data[index].count            = data_ary->data[index].count;
        data[index].last_found_count = data_ary->data[index].last_found_count;

        data[index].tfindex[0]       = data_ary->data[index].tfindex[0];
        data[index].tfindex[1]       = data_ary->data[index].tfindex[1];
        data[index].tfindex[2]       = data_ary->data[index].tfindex[2];

        data[index].tfindex_max[0]   = data_ary->data[index].tfindex_max[0];
        data[index].tfindex_max[1]   = data_ary->data[index].tfindex_max[1];
        data[index].tfindex_max[2]   = data_ary->data[index].tfindex_max[2];

        data[index].tfindex_min[0]   = data_ary->data[index].tfindex_min[0];
        data[index].tfindex_min[1]   = data_ary->data[index].tfindex_min[1];
        data[index].tfindex_min[2]   = data_ary->data[index].tfindex_min[2];

        data[index].mask             = data_ary->data[index].mask;
        
        data[index].dir_id           = data_ary->data[index].dir_id; // 2017.08.18 K.Takagi UART
    }
    
    return 0;
}


/******************************************************************************
**
**  History
**  -----------
**  2013.03.05 K.Takagi     エラー時は音源なしの情報を返すように修正
**  2012.12.06 K.Takagi     取得時はバッファへのポインタを返すように変更
**  2012.11.30 K.Takagi     データをコピーするように修正
**  2012.11.29 K.Takagi     新規作成
**
**  Description
**  -----------
**  音源位置データの取得
**    要求位置に保存されているデータのカウンタ値が異なるとエラー
**
*/

SOURCE_DATA_ARY_t *HABufferGetSourceData(int count)
{
    int get_req_pos;
    
    get_req_pos = count & HA_BUFFER_NUM_MASK;
    
    /* 要求したデータのカウント値が一致しなければエラー */
    if(source_data_ary_buf.ary[get_req_pos].count != count)
    {
        no_source_ary.count = count;
        no_source_ary.source_num = 0;
        return &no_source_ary;
        //return NULL;
    }
    
    return &source_data_ary_buf.ary[get_req_pos];
}

// S.Miyazaki ZeroCrossノードで音源情報を扱う為に追加 2013.04.11
//  2013.07.03 M.Takigahira mask追加
//  2013.10.16 M.Takigahira TFINDEX対応追加
int HABufferSetZCSourceData(int count, SOURCE_DATA_ARY_t *data_ary)
{
    int set_req_pos;
    int index;
    SOURCE_t *data;

    set_req_pos = count & HA_BUFFER_NUM_MASK;

    /* データコピー */
    zc_source_data_ary_buf.ary[set_req_pos].count = count;
    zc_source_data_ary_buf.ary[set_req_pos].source_num = data_ary->source_num;
    data = zc_source_data_ary_buf.ary[set_req_pos].data;

    for(index=0; index<data_ary->source_num; index++)
    {
        data[index].x[0]             = data_ary->data[index].x[0];
        data[index].x[1]             = data_ary->data[index].x[1];
        data[index].x[2]             = data_ary->data[index].x[2];

        data[index].power            = data_ary->data[index].power;
        data[index].id               = data_ary->data[index].id;
        data[index].remaining        = data_ary->data[index].remaining;

        data[index].count            = data_ary->data[index].count;
        data[index].last_found_count = data_ary->data[index].last_found_count;

        data[index].tfindex[0]       = data_ary->data[index].tfindex[0];
        data[index].tfindex[1]       = data_ary->data[index].tfindex[1];
        data[index].tfindex[2]       = data_ary->data[index].tfindex[2];

        data[index].tfindex_max[0]   = data_ary->data[index].tfindex_max[0];
        data[index].tfindex_max[1]   = data_ary->data[index].tfindex_max[1];
        data[index].tfindex_max[2]   = data_ary->data[index].tfindex_max[2];

        data[index].tfindex_min[0]   = data_ary->data[index].tfindex_min[0];
        data[index].tfindex_min[1]   = data_ary->data[index].tfindex_min[1];
        data[index].tfindex_min[2]   = data_ary->data[index].tfindex_min[2];

        data[index].mask             = data_ary->data[index].mask;

        data[index].dir_id           = data_ary->data[index].dir_id; // 2017.08.18 K.Takagi UART
    }

    return 0;
}

SOURCE_DATA_ARY_t *HABufferGetZCSourceData(int count)
{
    int get_req_pos;

    get_req_pos = count & HA_BUFFER_NUM_MASK;

    /* 要求したデータのカウント値が一致しなければエラー */
    if(zc_source_data_ary_buf.ary[get_req_pos].count != count)
    {
        no_source_ary.count = count;
        no_source_ary.source_num = 0;
        return &no_source_ary;
        //return NULL;
    }

    return &zc_source_data_ary_buf.ary[get_req_pos];
}

#ifdef STANDALON_TEST

/************************************************************
**
**  Public  : 
**
**  History : 2012.11.26 K.Takagi 新規作成
**
**  Description
**  -----------
**  単体テストのメイン
**
**
*/

int main(void)
{
    int stat;
    int count;
    int channel;
    int length;
    
    FFT_DATA_ARY_t fft_data;
    FFT_DATA_ARY_t fft_data_r;
    FFT_DATA_ARY_t *fft_data_p;
    
    COMPLEX_FLOAT **data;

    SOURCE_DATA_ARY_t source_data;
    SOURCE_DATA_ARY_t source_data_r;
    SOURCE_DATA_ARY_t *source_data_p;
    

    channel = 8;
    length  = (512/2 + 1);
    
    data = (COMPLEX_FLOAT **)MemoryAllocate2D(channel, length, sizeof(COMPLEX_FLOAT));
    if(data == NULL)
    {
        return -1;
    }
    
    /* パラメータ設定 */
    HABufferSetParam(channel, length);
    
    stat = HABufferInit();
    if(stat != 0)
    {
        printf("Buffer Allocate Error.\n");
        goto ErrEnd;
    }
    
    /** FFTデータ **/
    printf("-- FFT Data Buffer --\n");
    printf("[Set]\n");
    
    /* 書き込みテスト */
    for(count=0; count<HA_BUFFER_NUM+1; count++)
    {
        data[0][0].real = 10 + count;
        data[0][0].imag = 100 + count;
        
        fft_data.data = data;
        stat = HABufferSetFFTData(count, &fft_data);
        printf("count = %d, stat = %d\n", count, stat);
    }
    
    printf("\n[Get]\n");
    /* 読み出しテスト */
    for(count=0; count<HA_BUFFER_NUM+1; count++)
    {
        fft_data_p = HABufferGetFFTData(count);
        if(fft_data_p != NULL)
        {
            printf("count = %d (%d), stat = OK\n", count, fft_data_p->count);
            printf("  real = %f, imag = %f\n", fft_data_p->data[0][0].real, fft_data_p->data[0][0].imag);
        }
        else
        {
            printf("count = %d, stat = ERROR\n", count);
        }
    }
    
    
    
    /** 音源位置データ **/
    printf("\n-- Source Data Buffer --\n");
    printf("[Set]\n");
    
    /* 書き込みテスト */
    for(count=0; count<HA_BUFFER_NUM+1; count++)
    {
        source_data.source_num = (count & 3) + 1;
        source_data.data[0].power = count * 20;
        
        stat = HABufferSetSourceData(count, &source_data);
        printf("count = %d, stat = %d\n", count, stat);
    }
    
    printf("\n[Get]\n");
    /* 読み出しテスト */
    for(count=0; count<HA_BUFFER_NUM+2; count++)
    {
        source_data_p = HABufferGetSourceData(count);
        if(source_data_p != NULL)
        {
            printf("count = %d (%d), stat = OK\n", count, source_data_p->count);
            printf("  source_num = %d, power = %f\n", source_data_p->source_num, source_data_p->data[0].power);
        }
        else
        {
            printf("count = %d, stat = ERROR\n", count);
        }
    }


    HABufferRelease();
    
ErrEnd:
    free(data[0]);
    free(data);
    
    return 0;
}

#endif

/* EOF */

