2025-02-27 17:59:18 +08:00

446 lines
11 KiB
C
Executable File

// Copyright 2020-2021 Beken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <os/os.h>
#include <os/mem.h>
#include <os/str.h>
#include "stdio.h"
#include <driver/audio_ring_buff.h>
#include "aud_tras.h"
#include <driver/uart.h>
#include "gpio_driver.h"
#include <driver/timer.h>
#if (CONFIG_CACHE_ENABLE)
#include "cache.h"
#endif
#define AUD_TRAS "aud_tras"
#define LOGI(...) BK_LOGI(AUD_TRAS, ##__VA_ARGS__)
#define LOGW(...) BK_LOGW(AUD_TRAS, ##__VA_ARGS__)
#define LOGE(...) BK_LOGE(AUD_TRAS, ##__VA_ARGS__)
#define LOGD(...) BK_LOGD(AUD_TRAS, ##__VA_ARGS__)
#define TU_QITEM_COUNT (40)
#define AUD_TRAS_BUFF_SIZE (320 * 5)
//#define AUD_TX_DEBUG
#define CONFIG_AUD_TX_COUNT_DEBUG
#ifdef CONFIG_AUD_TX_COUNT_DEBUG
#define AUD_TX_DEBUG_INTERVAL (1000 * 2)
#endif
typedef struct
{
beken_thread_t aud_tras_task_hdl;
beken_queue_t aud_tras_int_msg_que;
uint8_t *aud_tras_buff_addr;
RingBufferContext aud_tras_rb; //save mic data needed to send by aud_tras task
bool is_running;
} aud_tras_info_t;
#ifdef CONFIG_AUD_TX_COUNT_DEBUG
typedef struct {
beken_timer_t timer;
uint32_t complete_size;
} aud_tx_count_debug_t;
static aud_tx_count_debug_t aud_tx_count = {0};
#endif
static aud_tras_setup_t aud_trs_setup_bk = {0};
static aud_tras_info_t *aud_tras_info = NULL;
static beken_semaphore_t aud_tras_task_sem = NULL;
static void *audio_tras_malloc(uint32_t size)
{
#if CONFIG_PSRAM_AS_SYS_MEMORY
return psram_malloc(size);
#else
return os_malloc(size);
#endif
}
static void audio_tras_free(void *mem)
{
os_free(mem);
}
#ifdef AUD_TX_DEBUG
static void uart_dump_mic_data(uart_id_t id, uint32_t baud_rate)
{
uart_config_t config = {0};
os_memset(&config, 0, sizeof(uart_config_t));
if (id == 0) {
gpio_dev_unmap(GPIO_10);
gpio_dev_map(GPIO_10, GPIO_DEV_UART1_RXD);
gpio_dev_unmap(GPIO_11);
gpio_dev_map(GPIO_11, GPIO_DEV_UART1_TXD);
} else if (id == 2) {
gpio_dev_unmap(GPIO_40);
gpio_dev_map(GPIO_40, GPIO_DEV_UART3_RXD);
gpio_dev_unmap(GPIO_41);
gpio_dev_map(GPIO_41, GPIO_DEV_UART3_TXD);
} else {
gpio_dev_unmap(GPIO_0);
gpio_dev_map(GPIO_0, GPIO_DEV_UART2_TXD);
gpio_dev_unmap(GPIO_1);
gpio_dev_map(GPIO_1, GPIO_DEV_UART2_RXD);
}
config.baud_rate = baud_rate;
config.data_bits = UART_DATA_8_BITS;
config.parity = UART_PARITY_NONE;
config.stop_bits = UART_STOP_BITS_1;
config.flow_ctrl = UART_FLOWCTRL_DISABLE;
config.src_clk = UART_SCLK_XTAL_26M;
if (bk_uart_init(id, &config) != BK_OK) {
LOGE("init uart fail \r\n");
} else {
LOGI("init uart ok \r\n");
}
}
#endif
#ifdef CONFIG_AUD_TX_COUNT_DEBUG
static void aud_tx_lost_count_dump(void *param)
{
aud_tx_count.complete_size = aud_tx_count.complete_size / 1024 / (AUD_TX_DEBUG_INTERVAL / 1000);
LOGI("[AUD Tx] %uKB/s \r\n", aud_tx_count.complete_size);
aud_tx_count.complete_size = 0;
}
#endif
bk_err_t aud_tras_send_msg(aud_tras_op_t op, void *param)
{
bk_err_t ret;
aud_tras_msg_t msg;
msg.op = op;
msg.param = param;
if (aud_tras_info->is_running && aud_tras_info && aud_tras_info->aud_tras_int_msg_que) {
ret = rtos_push_to_queue(&aud_tras_info->aud_tras_int_msg_que, &msg, BEKEN_NO_WAIT);
if (kNoErr != ret) {
LOGE("aud_tras_send_int_msg fail \r\n");
return kOverrunErr;
}
return ret;
}
return kNoResourcesErr;
}
bk_err_t aud_tras_deinit(void)
{
bk_err_t ret = BK_OK;
aud_tras_msg_t msg;
msg.op = AUD_TRAS_EXIT;
msg.param = NULL;
if (aud_tras_info && aud_tras_info->aud_tras_int_msg_que) {
ret = rtos_push_to_queue_front(&aud_tras_info->aud_tras_int_msg_que, &msg, BEKEN_NO_WAIT);
if (kNoErr != ret) {
LOGE("audio send msg: AUD_TRAS_EXIT fail \r\n");
return kOverrunErr;
}
} else {
return BK_OK;
}
ret = rtos_get_semaphore(&aud_tras_task_sem, BEKEN_WAIT_FOREVER);
if (ret != BK_OK)
{
LOGE("%s, %d, rtos_get_semaphore\n", __func__, __LINE__);
return BK_FAIL;
}
if(aud_tras_task_sem)
{
rtos_deinit_semaphore(&aud_tras_task_sem);
aud_tras_task_sem = NULL;
}
return kNoResourcesErr;
}
static void aud_tras_main(beken_thread_arg_t param_data)
{
bk_err_t ret = BK_OK;
uint32_t fill_size = 0;
aud_tras_setup_t *aud_trs_setup = NULL;
aud_trs_setup = (aud_tras_setup_t *)param_data;
uint8_t *aud_temp_data = NULL;
int tx_size = 0;
#ifdef AUD_TX_DEBUG
uart_dump_mic_data(1, 2000000);
#endif
#ifdef CONFIG_AUD_TX_COUNT_DEBUG
if (aud_tx_count.timer.handle != NULL)
{
ret = rtos_deinit_timer(&aud_tx_count.timer);
if (BK_OK != ret)
{
LOGE("deinit aud_tx_count time fail\r\n");
goto aud_tras_exit;
}
aud_tx_count.timer.handle = NULL;
}
aud_tx_count.complete_size = 0;
ret = rtos_init_timer(&aud_tx_count.timer, AUD_TX_DEBUG_INTERVAL, aud_tx_lost_count_dump, NULL);
if (ret != BK_OK) {
LOGE("rtos_init_timer fail \n");
}
ret = rtos_start_timer(&aud_tx_count.timer);
if (ret != BK_OK) {
LOGE("rtos_start_timer fail \n");
}
LOGI("start audio tx count timer complete \r\n");
#endif
GLOBAL_INT_DECLARATION();
aud_temp_data = audio_tras_malloc(320);
if (!aud_temp_data)
{
LOGE("malloc aud_temp_data\n");
goto aud_tras_exit;
}
os_memset(aud_temp_data, 0, 320);
rtos_set_semaphore(&aud_tras_task_sem);
aud_tras_info->is_running = true;
aud_tras_send_msg(AUD_TRAS_TX, NULL);
aud_tras_msg_t msg;
while (1) {
ret = rtos_pop_from_queue(&aud_tras_info->aud_tras_int_msg_que, &msg, BEKEN_WAIT_FOREVER);
if (kNoErr == ret) {
switch (msg.op) {
case AUD_TRAS_IDLE:
break;
case AUD_TRAS_EXIT:
LOGD("goto: AUD_TRAS_EXIT \r\n");
goto aud_tras_exit;
break;
case AUD_TRAS_TX:
fill_size = ring_buffer_get_fill_size(&aud_tras_info->aud_tras_rb);
for (int n = 0; n < fill_size/320; n++) {
// GPIO_UP(6);
#if (CONFIG_CACHE_ENABLE)
flush_all_dcache();
#endif
GLOBAL_INT_DISABLE();
ring_buffer_read(&aud_tras_info->aud_tras_rb, aud_temp_data, 320);
GLOBAL_INT_RESTORE();
#ifdef AUD_TX_DEBUG
bk_uart_write_bytes(UART_ID_1, aud_temp_data, 320);
#endif
tx_size = aud_trs_setup->aud_tras_send_data_cb(aud_temp_data, 320);
if (tx_size > 0) {
#ifdef CONFIG_AUD_TX_COUNT_DEBUG
aud_tx_count.complete_size+=tx_size;
#endif
}
// GPIO_DOWN(6);
}
rtos_delay_milliseconds(5);
aud_tras_send_msg(AUD_TRAS_TX, NULL);
break;
default:
break;
}
}
}
aud_tras_exit:
aud_tras_info->is_running = false;
if (aud_temp_data) {
audio_tras_free(aud_temp_data);
aud_temp_data == NULL;
}
#ifdef CONFIG_AUD_TX_COUNT_DEBUG
if (aud_tx_count.timer.handle) {
ret = rtos_stop_timer(&aud_tx_count.timer);
if (ret != BK_OK) {
LOGE("stop aud_tx_count timer fail \n");
}
ret = rtos_deinit_timer(&aud_tx_count.timer);
if (ret != BK_OK) {
LOGE("deinit aud_tx_count timer fail \n");
}
aud_tx_count.timer.handle = NULL;
}
aud_tx_count.complete_size = 0;
#endif
if (aud_tras_info->aud_tras_buff_addr) {
ring_buffer_clear(&aud_tras_info->aud_tras_rb);
audio_tras_free(aud_tras_info->aud_tras_buff_addr);
aud_tras_info->aud_tras_buff_addr == NULL;
}
/* delete msg queue */
ret = rtos_deinit_queue(&aud_tras_info->aud_tras_int_msg_que);
if (ret != kNoErr) {
LOGE("delete message queue fail \r\n");
}
aud_tras_info->aud_tras_int_msg_que = NULL;
LOGI("delete aud_tras_int_msg_que \r\n");
os_memset(&aud_trs_setup_bk, 0, sizeof(aud_tras_setup_t));
/* delete task */
aud_tras_info->aud_tras_task_hdl = NULL;
if (aud_tras_info)
{
audio_tras_free(aud_tras_info);
aud_tras_info = NULL;
}
rtos_set_semaphore(&aud_tras_task_sem);
rtos_delete_thread(NULL);
}
bk_err_t aud_tras_init(aud_tras_setup_t *setup_cfg)
{
bk_err_t ret = BK_OK;
aud_tras_info = audio_tras_malloc(sizeof(aud_tras_info_t));
if (aud_tras_info == NULL)
{
LOGE("malloc aud_tras_info\n");
return BK_FAIL;
}
os_memset(aud_tras_info, 0, sizeof(aud_tras_info_t));
aud_tras_info->aud_tras_buff_addr = audio_tras_malloc(AUD_TRAS_BUFF_SIZE + CONFIG_AUD_RING_BUFF_SAFE_INTERVAL);
if (!aud_tras_info->aud_tras_buff_addr) {
LOGE("malloc aud_tras_buff_addr\n");
goto out;
}
ring_buffer_init(&aud_tras_info->aud_tras_rb, aud_tras_info->aud_tras_buff_addr, AUD_TRAS_BUFF_SIZE + CONFIG_AUD_RING_BUFF_SAFE_INTERVAL, DMA_ID_MAX, RB_DMA_TYPE_NULL);
LOGD("aud_tras_info->aud_tras_rb: %p \n", &aud_tras_info->aud_tras_rb);
os_memcpy(&aud_trs_setup_bk, setup_cfg, sizeof(aud_tras_setup_t));
if (aud_tras_task_sem == NULL) {
ret = rtos_init_semaphore(&aud_tras_task_sem, 1);
if (ret != BK_OK)
{
LOGE("%s, %d, create audio tras task semaphore failed \n", __func__, __LINE__);
goto out;
}
}
if ((!aud_tras_info->aud_tras_task_hdl) && (!aud_tras_info->aud_tras_int_msg_que))
{
ret = rtos_init_queue(&aud_tras_info->aud_tras_int_msg_que,
"aud_tras_int_que",
sizeof(aud_tras_msg_t),
TU_QITEM_COUNT);
if (ret != kNoErr)
{
LOGE("create audio transfer internal message queue fail\n");
goto out;
}
LOGD("create audio transfer internal message queue complete\n");
ret = rtos_create_thread(&aud_tras_info->aud_tras_task_hdl,
4,
"aud_tras",
(beken_thread_function_t)aud_tras_main,
1024 * 2,
(beken_thread_arg_t)&aud_trs_setup_bk);
if (ret != kNoErr)
{
LOGE("Error: Failed to create aud_tras task \n");
return kGeneralErr;
}
ret = rtos_get_semaphore(&aud_tras_task_sem, BEKEN_WAIT_FOREVER);
if (ret != BK_OK)
{
LOGE("%s, %d, rtos_get_semaphore\n", __func__, __LINE__);
goto out;
}
LOGD("init aud_tras task complete \n");
}
else
{
goto out;
}
return BK_OK;
out:
if(aud_tras_task_sem)
{
rtos_deinit_semaphore(&aud_tras_task_sem);
aud_tras_task_sem = NULL;
}
if (aud_tras_info->aud_tras_int_msg_que)
{
ret = rtos_deinit_queue(&aud_tras_info->aud_tras_int_msg_que);
if (ret != kNoErr) {
LOGE("delete message queue fail \r\n");
}
aud_tras_info->aud_tras_int_msg_que = NULL;
}
if (aud_tras_info->aud_tras_buff_addr) {
ring_buffer_clear(&aud_tras_info->aud_tras_rb);
audio_tras_free(aud_tras_info->aud_tras_buff_addr);
aud_tras_info->aud_tras_buff_addr == NULL;
}
if (aud_tras_info)
{
audio_tras_free(aud_tras_info);
aud_tras_info = NULL;
}
return BK_FAIL;
}
RingBufferContext *aud_tras_get_tx_rb(void)
{
return &aud_tras_info->aud_tras_rb;
}