#include "platform.h"
#include "hal_headfile.h"
#include "debug.h"
#include "audio.h"
#include "config.h"

DMA_HandleTypeDef         audio_dma;
audio_adc_handle_typedef  audio_adc;
volatile __ALIGNED(4) uint16_t   adc_dma_buff[AUDIO_CALLBACK_LEN * 2 * 2]; //双通道、pingpong总buf，每次dma中断搬运AUDIO_CALLBACK_LEN*2个点，单个声道即AUDIO_CALLBACK_LEN个点

void audio_adc_data_full_cplt(DMA_HandleTypeDef *_hdma, void *_param);
void audio_adc_data_half_cplt(DMA_HandleTypeDef *_hdma, void *_param);

/**
 * this function will init adc
 *
 * @param: none:
 *
 * @return: none.
 */
void audio_adc_init(void)
{
    static uint8_t  init_flag = 0;
    audio_adc_ch_cfg_typedef   cfg;
    cfg.sample_rate  = SAMPLE_RATE_16K;            /*配置采样率*/
    cfg.digit_volume = VOLUME_01X;                 /*数字音量*/
    cfg.hw_pin = AMIC_CH0;                         /*模拟通道*/
    cfg.amic.mode = different;                     /*差分模式*/
    if (aec_param.mian_mic_option == MIC_0)
	{
		cfg.amic.mic_gain = aec_param.mian_mic_gain;
	}
	else
	{
		cfg.amic.mic_gain = aec_param.sub_mic_gain;
	}
    cfg.amic.mix_gain = MADC_MIX_GAIN_N0D0B;       /*设置MIX增益*/
    cfg.amic.vmic = VOLT_2o59;                     /*设置VMIC电压*/
    hal_audio_adc_ch_cfg(&audio_adc, cfg);

    cfg.hw_pin = AMIC_CH1;
    if (aec_param.mian_mic_option == MIC_1)
	{
		cfg.amic.mic_gain = aec_param.mian_mic_gain;
	}
	else
	{
		cfg.amic.mic_gain = aec_param.sub_mic_gain;
	}
    hal_audio_adc_ch_cfg(&audio_adc, cfg);
    audio_adc.init.data_width = WIDTH_16BIT;       /*数据宽度*/
#ifndef    ADC_USE_SRC1
    audio_adc.init.src_sel = AHB;
#else
    audio_adc.init.src_sel = SRC;
#endif
    audio_adc.init.channel_id = CHN0 | CHN1;
    audio_adc.dma_handle = &audio_dma;/*注册DMA句柄*/
    hal_audio_init(&audio_adc);
#ifndef    ADC_USE_SRC1

    if (init_flag == 0)
    {
        init_flag = 1;
        adc_dma_init();
    }

#endif
    adc_mic0_AGC_init();
    audio_adc_cmd(&audio_adc, ENABLE);
}

/**
 * this function will init mic0 agc
 *
 * @param: none:
 *
 * @return: none.
 */
void adc_mic0_AGC_init(void)
{
    adc_AGC_config_typedef_def mic0_gac;
    agc_param_def *addr;
    uint32_t  temp = ((uint32_t)(FW_HEADER->BIN[3].ADDR));//ext.a空间
    temp += sizeof(denoise_param_def);
    addr = (agc_param_def *)temp;

    if ((addr->agc_config.AGC_enable) && (addr->agc_param_enable))
    {
        mic0_gac.AGC_enable = addr->agc_config.AGC_enable;
        mic0_gac.noise_gain_enable = addr->agc_config.noise_gain_enable;
        mic0_gac.Hysteresis = addr->agc_config.Hysteresis;
        mic0_gac.Min_gain = addr->agc_config.Min_gain;
        mic0_gac.Max_gain = addr->agc_config.Max_gain;
        mic0_gac.noise_level = addr->agc_config.noise_level;
        mic0_gac.Target_level = addr->agc_config.Target_level;
        mic0_gac.Peak_Attack_time = addr->agc_config.Peak_Attack_time;
        mic0_gac.Peak_Release_time = addr->agc_config.Peak_Release_time;
        mic0_gac.Gain_Attack_time = addr->agc_config.Gain_Attack_time;
        mic0_gac.Gain_Release_time = addr->agc_config.Gain_Release_time;
        hal_audio_adc_set_agc(&audio_adc, &mic0_gac);
    }
    else
    {
        // mic0_gac.AGC_enable = addr->agc_config.AGC_enable;
        // mic0_gac.noise_gain_enable = addr->agc_config.noise_gain_enable;
        // mic0_gac.Hysteresis = addr->agc_config.Hysteresis;
        // mic0_gac.Min_gain = addr->agc_config.Min_gain;
        // mic0_gac.Max_gain = addr->agc_config.Max_gain;
        // mic0_gac.noise_level = addr->agc_config.noise_level;
        // mic0_gac.Target_level = addr->agc_config.Target_level;
        // mic0_gac.Peak_Attack_time = addr->agc_config.Peak_Attack_time;
        // mic0_gac.Peak_Release_time = addr->agc_config.Peak_Release_time;
        // mic0_gac.Gain_Attack_time = addr->agc_config.Gain_Attack_time;
        // mic0_gac.Gain_Release_time = addr->agc_config.Gain_Release_time;
        // hal_audio_adc_set_agc(&audio_adc,&mic0_gac);
    }
}


void audio_adc_suspend(void)
{
    cmu_set_clk_en(ADC_CLOCK_ENABLE, DISABLE);
    rmu_set_rst_en(ADC_RST_ENABLE, DISABLE);
}

/**
 * this function will init adc dma
 *
 * @param none:
 *
 * @return: none.
 */
void adc_dma_init(void)
{
    /*目标地址*/
    audio_adc.dma_handle->init.dst_data_loc = DMA_Data_Location_Select_Low;
    audio_adc.dma_handle->init.dst_data_width = DMA_Data_Width_16Bit;
    audio_adc.dma_handle->init.dst_inc = DMA_Address_Type_Inc;
    /*源地址*/
    audio_adc.dma_handle->init.src_data_loc = DMA_Data_Location_Select_Low;
    audio_adc.dma_handle->init.src_data_width = DMA_Data_Width_16Bit;
    audio_adc.dma_handle->init.src_inc = DMA_Address_Type_Fix;
    /*DMA*/
    audio_adc.dma_handle->init.memory_burst = DMA_Burst_Length_Burst2;
    audio_adc.dma_handle->init.channel = CH5;/*adc使用dma通道7*/
    audio_adc.dma_handle->init.priority = 5;
    audio_adc.dma_handle->init.mode = DMA_Mode_Circular;
    hal_dma_init(audio_adc.dma_handle);
    hal_dma_register_callback(audio_adc.dma_handle, HAL_DMA_XFER_CPLT_CB_ID, audio_adc_data_full_cplt);    /*注册完成中断服务函数*/
    hal_dma_register_callback(audio_adc.dma_handle, HAL_DMA_XFER_HALFCPLT_CB_ID, audio_adc_data_half_cplt); /*注册半完成中断服务函数*/
    hal_dma_start_it(audio_adc.dma_handle, (((uint32_t)(&(DEV_ADC->RBUF)) + 2)), (uint32_t)adc_dma_buff, AUDIO_CALLBACK_LEN * 2 * 2 * 2, NULL); /*dma开始传输*/
}
/**
 * Callback function halfway through DMA transfer
 *
 * @param _hdma:  adc dma handle
 *
 * @return: none.
 */
void audio_adc_data_half_cplt(DMA_HandleTypeDef *_hdma, void *_param)
{
#ifdef DEBUG_ADC_WAV
    debug_puts_hex((uint8_t *)adc_dma_buff, AUDIO_CALLBACK_LEN * 2 * 2);
#else
    adc_read_data((uint8_t *)adc_dma_buff, AUDIO_CALLBACK_LEN);//point num
#endif
}

/**
 * Callback function after DMA transfer
 *
 * @param _hdma:  adc dma handle
 *
 * @return: none.
 */
void audio_adc_data_full_cplt(DMA_HandleTypeDef *_hdma, void *_param)
{
#ifdef DEBUG_ADC_WAV
    debug_puts_hex((uint8_t *)adc_dma_buff + AUDIO_CALLBACK_LEN * 2 * 2, AUDIO_CALLBACK_LEN * 2 * 2);
#else
    adc_read_data((uint8_t *)adc_dma_buff + AUDIO_CALLBACK_LEN * 2 * 2, AUDIO_CALLBACK_LEN);//point num
#endif
}

/**
 * get adc data
 *
 * @param _hdma:  adc dma handle
 *
 * @return: none.
 */
void adc_read_data(uint8_t *_data, uint32_t _len)
{
    push_primitive_audio_from_adc((int16_t *)_data, _len); //point num
}
