/*
 *****************************************************************
 *
 * Audio ADC 多通道使用demo
 *
 *****************************************************************
 */

#include "asm/includes.h"
#include "media/includes.h"
#include "system/includes.h"
#include "asm/audio_src.h"
#include "audio_enc.h"
#include "app_main.h"
//#include "app_task.h"
#include "audio_config.h"

extern struct audio_adc_hdl adc_hdl;

/*总共使能多少个通道*/
#define LADC_CH_NUM         1

#define LADC_BUF_NUM        2
#define LADC_IRQ_POINTS     256	/*中断点数*/
#define LADC_BUFS_SIZE      (LADC_CH_NUM * LADC_BUF_NUM * LADC_IRQ_POINTS)

/*调试使用，推mic数据/linein数据/mic&line混合数据到dac*/
#define  LADC_2_DAC_ENABLE	1
#define LADC_MIC_2_DAC		BIT(0)
#define LADC_LIN_2_DAC		BIT(1)
#define LADC_2_DAC			(LADC_MIC_2_DAC | LADC_LIN_2_DAC)

typedef struct {
    struct audio_adc_output_hdl output;
    struct audio_adc_ch linein_ch;
    struct adc_mic_ch mic_ch;
    s16 adc_buf[LADC_BUFS_SIZE];    //align 4Bytes
    s16 temp_buf[LADC_IRQ_POINTS * 3];
} audio_adc_t;
static audio_adc_t *ladc_var = NULL;

/*
 * 使能1个通道,1个linein或者1个mic：
 * 数据结构：DAT0 DAT1 DAT2
 */
static void audio_adc1_output_demo(void *priv, s16 *data, int len)
{
    struct audio_adc_hdl *hdl = priv;
    int wlen = 0;

    putchar('1');
    if (ladc_var == NULL) {
        return;
    }
    /* printf("linein:%x,len:%d,ch:%d",data,len,hdl->channel); */

#if LADC_2_DAC_ENABLE
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)//双声道数据结构
    for (int i = 0; i < (len / 2); i++) {
        ladc_var->temp_buf[i * 2] = data[i];
        ladc_var->temp_buf[i * 2 + 1] = data[i];
    }
    wlen = app_audio_output_write(ladc_var->temp_buf, len * 2);
#else //单声道数据结构
    //TODO
    wlen = app_audio_output_write(data, len * hdl->channel);
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
#endif/*LADC_2_DAC_ENABLE*/
}

/*
 * 使能2个通道,1个linein和1个mic：
 * 数据结构：LIN0 MIC0 LIN1 MIC1 LIN2 MIC2
 */
static void audio_adc2_output_demo(void *priv, s16 *data, int len)
{
    struct audio_adc_hdl *hdl = priv;
    int wlen = 0;

    putchar('2');
    if (ladc_var == NULL) {
        return;
    }
    /* printf("linein:%x,len:%d,ch:%d",data,len,hdl->channel); */

#if LADC_2_DAC_ENABLE
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)//双声道数据结构
    wlen = app_audio_output_write(data, len * 2);
#else //单声道数据结构
    //TODO
#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
#endif/*LADC_2_DAC_ENABLE*/
}
/*
 * 使能3个通道,2个linein 和 1个mic：
 * 数据结构：LINL0 LINR0 MIC0 LINL1 LINR1 MIC1 LINL2 LINR2 MIC2...
 */
static void audio_adc3_output_demo(void *priv, s16 *data, int len)
{
    struct audio_adc_hdl *hdl = priv;
    int wlen = 0;

    putchar('3');
    if (ladc_var == NULL) {
        return;
    }
    /* printf("linein:%x,len:%d,ch:%d",data,len,hdl->channel); */

#if LADC_2_DAC_ENABLE
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)//双声道数据结构
#if (LADC_2_DAC == LADC_LIN_2_DAC)
    for (u16 i = 0; i < len / 2; i++) {
        data[2 * i] = data[3 * i];
        data[2 * i + 1] = data[3 * i + 1];
    }
#elif (LADC_2_DAC == LADC_MIC_2_DAC)
    for (u16 i = 0; i < len / 2; i++) {
        data[2 * i] = data[3 * i + 2];
        data[2 * i + 1] = data[3 * i + 2];
    }
#else //linein data and mic data mix
    int tmp_data;
    for (u16 i = 0; i < len / 2; i++) {
        tmp_data = data[3 * i];
        tmp_data += data[3 * i + 2];
        if (tmp_data > 32767) {
            tmp_data = 32767;
        } else if (tmp_data < -32768) {
            tmp_data = -32768;
        }
        data[2 * i] = tmp_data;

        tmp_data = data[3 * i + 1];
        tmp_data += data[3 * i + 2];
        if (tmp_data > 32767) {
            tmp_data = 32767;
        } else if (tmp_data < -32768) {
            tmp_data = -32768;
        }
        data[2 * i + 1] = tmp_data;
    }
#endif/*LADC_2_DAC*/
    wlen = app_audio_output_write(data, len * 2);
#else //单声道数据结构

#endif/*TCFG_AUDIO_DAC_CONNECT_MODE*/
#endif/*LADC_2_DAC_ENABLE*/
}


int audio_adc_open_demo(void)
{
    u16 ladc_sr = 16000;
    u8 mic_gain = 5;
    u8 linein_gain = 3;
    r_printf("audio_adc_open_demo,sr:%d,mic_gain:%d,linein_gain:%d\n", ladc_sr, mic_gain, linein_gain);
    if (ladc_var) {
        r_printf("ladc already open \n");
        return 0;
    }
    ladc_var = zalloc(sizeof(audio_adc_t));
    if (ladc_var) {
#if (LADC_CH_NUM == 1)
        audio_adc_mic_open(&ladc_var->mic_ch, AUDIO_ADC_MIC_CH, &adc_hdl);
        audio_adc_mic_set_sample_rate(&ladc_var->mic_ch, ladc_sr);
        audio_adc_mic_set_gain(&ladc_var->mic_ch, mic_gain);
        audio_adc_mic_set_buffs(&ladc_var->mic_ch, ladc_var->adc_buf, LADC_CH_NUM * LADC_IRQ_POINTS * 2, LADC_BUF_NUM);
        ladc_var->output.handler = audio_adc1_output_demo;
        ladc_var->output.priv = &adc_hdl;
        audio_adc_add_output_handler(&adc_hdl, &ladc_var->output);
        audio_adc_mic_start(&ladc_var->mic_ch);
#else
        audio_adc_mic_open(&ladc_var->mic_ch, AUDIO_ADC_MIC_CH, &adc_hdl);
        audio_adc_mic_set_sample_rate(&ladc_var->mic_ch, ladc_sr);
        audio_adc_mic_set_gain(&ladc_var->mic_ch, mic_gain);

#if (LADC_CH_NUM ==2 )
        audio_adc_linein_open(&ladc_var->linein_ch, AUDIO_ADC_LINE0_L, &adc_hdl);
        //audio_adc_linein_open(&ladc_var->linein_ch, AUDIO_ADC_LINE0_R, &adc_hdl);
#else
        audio_adc_linein_open(&ladc_var->linein_ch, AUDIO_ADC_LINE0_LR, &adc_hdl);
#endif
        audio_adc_linein_set_sample_rate(&ladc_var->linein_ch, ladc_sr);
        audio_adc_linein_set_gain(&ladc_var->linein_ch, linein_gain);

        printf("adc_buf_size:%d", sizeof(ladc_var->adc_buf));
        audio_adc_set_buffs(&ladc_var->linein_ch, ladc_var->adc_buf, LADC_CH_NUM * LADC_IRQ_POINTS * 2, LADC_BUF_NUM);
#if (LADC_CH_NUM == 2)
        ladc_var->output.handler = audio_adc2_output_demo;
#else
        ladc_var->output.handler = audio_adc3_output_demo;
#endif/*LADC_CH_NUM*/
        ladc_var->output.priv = &adc_hdl;
        audio_adc_add_output_handler(&adc_hdl, &ladc_var->output);
        audio_adc_start(&ladc_var->linein_ch, &ladc_var->mic_ch);
#endif

#if LADC_2_DAC_ENABLE
        app_audio_output_samplerate_set(ladc_sr);
        app_audio_output_start();
#endif/*LADC_2_DAC_ENABLE*/
        return 0;
    } else {
        return -1;
    }
}

void audio_adc_close_demo()
{
    if (ladc_var) {
        audio_adc_mic_close(&ladc_var->mic_ch);
        audio_adc_del_output_handler(&adc_hdl, &ladc_var->output);
        local_irq_disable();
        free(ladc_var);
        ladc_var = NULL;
        local_irq_enable();
        extern void audio_output_stop(void);
        audio_output_stop();
    }
}

#if 1
static u8 audio_adc_demo_idle_query(void)
{
    if (ladc_var) {
        return 0;
    }
    return 1;
}

REGISTER_LP_TARGET(audio_adc_demo) = {
    .name       = "audio_adc_demo",
    .is_idle    = audio_adc_demo_idle_query,
};
#endif
