#include "audio_hal.h"
#include <string.h>
#include "main.h"
#include "elog.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "heap.h"

static const char *TAG = "audio_hal";

typedef struct {
  void *buffer_ptr;
  uint32_t buffer_size;
} audio_sample_t;

static QueueHandle_t audio_queue = NULL;
static uint8_t *audio_buffer = NULL;
static uint32_t audio_buffer_length = 0;
static uint8_t audio_buffer_underrun_warn_flag = 0;

void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
  BaseType_t need_yield = pdFALSE;
  audio_sample_t sample;

  if (xQueueReceiveFromISR(audio_queue, &sample, &need_yield) == pdTRUE) {
    memcpy(&audio_buffer[0], sample.buffer_ptr, sample.buffer_size); //复制到第一个缓冲区
    free(sample.buffer_ptr); //释放使用完的缓冲区
  }

  HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_SET);
  portYIELD_FROM_ISR(need_yield);
}

void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
{
  BaseType_t need_yield = pdFALSE;
  audio_sample_t sample;

  if (xQueueReceiveFromISR(audio_queue, &sample, &need_yield) == pdTRUE) {
    memcpy(&audio_buffer[audio_buffer_length / 2], sample.buffer_ptr, sample.buffer_size); //复制到第二个缓冲区
    free(sample.buffer_ptr); //释放使用完的缓冲区
  }

  HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET);
  portYIELD_FROM_ISR(need_yield);
}

void audio_hal_start(uint32_t sample_count, uint8_t sample_size)
{
  audio_buffer_length = sample_count * sample_size * 2; //双缓冲
  elog_info(TAG, "audio_hal_start: sample_count=%d, sample_size=%d, allocating %d bytes for audio buffer",
                 sample_count, sample_size, audio_buffer_length);

  if (audio_buffer != NULL) {
    elog_warn(TAG, "audio_hal_start: audio_buffer is not freed");
    free_ahb(audio_buffer);
  }
  audio_buffer = malloc_ahb(audio_buffer_length);
  memset(audio_buffer, 0, audio_buffer_length);

  if (audio_queue != NULL) {
    elog_warn(TAG, "audio_hal_start: audio_queue is not deleted");
    vQueueDelete(audio_queue);
  }
  audio_queue = xQueueCreate(AUDIO_HAL_SAMPLE_QUEUE_SIZE, sizeof(audio_sample_t));
  audio_buffer_underrun_warn_flag = 0;

  HAL_SAI_Transmit_DMA(&hsai_BlockB1, audio_buffer, sample_count * 2); //开始DMA循环发送
}

void audio_hal_stop(void)
{
  HAL_SAI_DMAStop(&hsai_BlockB1);

  audio_sample_t sample;
  while (xQueueReceive(audio_queue, &sample, 0) == pdTRUE) {
    free(sample.buffer_ptr);
    elog_debug(TAG, "audio_hal_stop: freeing unused buffer");
  }

  vQueueDelete(audio_queue);
  audio_queue = NULL;

  free_ahb(audio_buffer);
  audio_buffer = NULL;
}

void audio_hal_write(void *buffer_ptr, uint32_t buffer_size)
{
  if (buffer_size == 0) {
    return;
  }

  audio_sample_t sample = {
    .buffer_ptr = buffer_ptr,
    .buffer_size = buffer_size
  };

  if (uxQueueSpacesAvailable(audio_queue) == AUDIO_HAL_SAMPLE_QUEUE_SIZE && audio_buffer_underrun_warn_flag != 0) {
    elog_warn(TAG, "audio_hal_write: audio sample queue is empty before xQueueSend");
  }

  xQueueSend(audio_queue, &sample, portMAX_DELAY); //发送缓冲区到队列中
  audio_buffer_underrun_warn_flag = 1; //屏蔽首次报错
}
