#include <stdio.h>
#include "audio_bsp.h"
#include "freertos/FreeRTOS.h"
#include "driver/i2s_std.h"
#include "user_config.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "driver/i2s_pdm.h"

static const char *TAG = "user_audio";


#define volumeMax  50                             //int16_t (100/2) uint16_t 100
static uint8_t volume = 10;


static i2s_chan_handle_t                tx_chan;        // I2S tx channel handler
static i2s_chan_handle_t                rx_chan;        // I2S rx channel handler

#define I2S_SAMPLE_RATE      44100                     // 采样率 (Hz)
#define I2S_BIT_WIDTH        I2S_DATA_BIT_WIDTH_16BIT  // 位深，使用 ESP-IDF 提供的枚举
#define I2S_CHANNEL_FORMAT   I2S_SLOT_MODE_MONO        // 声道格式（立体声）STEREO      MONO


#define EXAMPLE_STD_BCLK_PIN       EXAMPLE_I2S_STD_BCLK_PIN     // I2S bit clock io number
#define EXAMPLE_STD_WS_PIN         EXAMPLE_I2S_STD_WS_PIN       // I2S word select io number
#define EXAMPLE_STD_DOUT_PIN       EXAMPLE_I2S_STD_DOUT_PIN     // I2S data out io number


#define EXAMPLE_PDM_DATA_PIN       EXAMPLE_I2S_PDM_DATA_PIN
#define EXAMPLE_PDM_CLK_PIN        EXAMPLE_I2S_PDM_CLK_PIN 




/*MIC set pdm*/

#define EXAMPLE_PDM_RX_FREQ_HZ          44100           // I2S PDM RX frequency
         


static void i2s_example_init_std_simplex(void)
{
  /* Setp 1: Determine the I2S channel configuration and allocate two channels one by one
   * The default configuration can be generated by the helper macro,
   * it only requires the I2S controller id and I2S role
   * The tx and rx channels here are registered on different I2S controller,
   * Except ESP32 and ESP32-S2, others allow to register two separate tx & rx channels on a same controller */
  i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_MASTER);
  ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_chan, NULL));

  /* Step 2: Setting the configurations of standard mode and initialize each channels one by one
   * The slot configuration and clock configuration can be generated by the macros
   * These two helper macros is defined in 'i2s_std.h' which can only be used in STD mode.
   * They can help to specify the slot and clock configurations for initialization or re-configuring */
  i2s_std_config_t tx_std_cfg = {
      .clk_cfg  = I2S_STD_CLK_DEFAULT_CONFIG(I2S_SAMPLE_RATE),
      .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_BIT_WIDTH, I2S_CHANNEL_FORMAT),
      .gpio_cfg = {
          .mclk = I2S_GPIO_UNUSED,    // some codecs may require mclk signal, this example doesn't need it
          .bclk = EXAMPLE_STD_BCLK_PIN,
          .ws   = EXAMPLE_STD_WS_PIN,
          .dout = EXAMPLE_STD_DOUT_PIN,
          .din  = I2S_GPIO_UNUSED,
          .invert_flags = {
              .mclk_inv = false,
              .bclk_inv = false,
              .ws_inv   = false,
          },
      },
  };
  ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &tx_std_cfg));
  ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
}

static void i2s_example_init_pdm_rx(void)
{
  i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
  ESP_ERROR_CHECK(i2s_new_channel(&rx_chan_cfg, NULL, &rx_chan));
  i2s_pdm_rx_config_t pdm_rx_cfg = 
  {
    .clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(EXAMPLE_PDM_RX_FREQ_HZ),                         //采样率
    /* The data bit-width of PDM mode is fixed to 16 */
    .slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), //16位深 单声道
    .gpio_cfg = 
    {
      .clk = EXAMPLE_PDM_CLK_PIN,
      .din = EXAMPLE_PDM_DATA_PIN, //只配置一个MIC
      .invert_flags = 
      {
        .clk_inv = false,
      },
    },
  };
  ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(rx_chan, &pdm_rx_cfg));
  /* Step 3: Enable the rx channels before reading data */
  ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
}
int volume_adjustment(uint8_t vol)
{
  if(vol <= volumeMax)
  {
    volume = vol;
    return ESP_OK;
  }
  return ESP_FAIL;
}

static esp_err_t bsp_i2s_write(void *audio_buffer, size_t len, size_t *bytes_written)
{
  esp_err_t err = ESP_OK;
  int16_t *audio_per = (int16_t *)audio_buffer;
  size_t sample_count = len / sizeof(int16_t);
  int16_t *samples = (int16_t *)heap_caps_malloc(len, MALLOC_CAP_SPIRAM); 
  float volume_factor = volume / 100.0f;// Calculate the volume scaling factor to convert the volume level from 0-100 to the 0.0-1.0 range
  for(uint32_t i = 0; i<sample_count; i++)
  {
    samples[i] = (int16_t)(audio_per[i] * volume_factor); //加入声音调节(int16_t)(audio_per[i] * volume_factor); 源声是audio_per[i]
  }
  err = i2s_channel_write(tx_chan, (int8_t *)samples, len, bytes_written, 1000);
  heap_caps_free(samples);
  samples = NULL;
  return err;
}
static void i2s_adc_dac_loop_task(void *arg)
{
  int16_t *r_buf = (int16_t *)calloc(1, 2048);
  assert(r_buf);
  size_t r_bytes = 0;
  for(;;)
  {
    if(i2s_channel_read(rx_chan, r_buf, 2048, &r_bytes, 1000) == ESP_OK)
    {
      bsp_i2s_write(r_buf,2048,&r_bytes);
    }
  }
  free(r_buf);
  vTaskDelete(NULL);
}

static void audio_gpio_init(void)
{
  gpio_config_t gpio_conf = {};
  gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
  gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
  gpio_conf.intr_type = GPIO_INTR_DISABLE;
  gpio_conf.pin_bit_mask = ((uint64_t)0x01<<GPIO_NUM_0);
  gpio_conf.mode = GPIO_MODE_OUTPUT; 
  ESP_ERROR_CHECK_WITHOUT_ABORT(gpio_config(&gpio_conf));
  gpio_set_level(GPIO_NUM_0,1);
}
void audio_bsp_init(void)
{
  audio_gpio_init(); //把PCM5100A的控制权给到ESP32S3
  i2s_example_init_std_simplex();
  i2s_example_init_pdm_rx();
  xTaskCreate(i2s_adc_dac_loop_task, "i2s_adc_dac_loop_task", 4000, NULL, 6, NULL);
}
