* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2020-2021. All rights reserved.
* Description: source file for module operation
*/
#include <stdlib.h>
#ifdef __LITEOS__
#include <los_task.h>
#endif
#include "cmsis_os.h"
#include "thread_os.h"
#include "securec.h"
#include "sample_audio_api.h"
#include "chip_type.h"
#include "audio_struct.h"
#include "soc_uapi_audio_sys.h"
#include "sample_audio.h"
#if (SAP_CHIP_TYPE == brandy)
#include "es8311_codec.h"
#include "pm_clocks.h"
#endif
#define TEST_SUITE_TASK_STACK_SIZE 0xc00
#define TEST_SUITE_NAME "audio"
#define TEST_SUITE_MAX_ARGV_LEN 128
#ifdef BOARD_CS
#define AUDIO_MEM_PROT_CFG 0x500006a0
#define AUDIO_MEM_PROT_LOCK 0x3
#endif
#define ADDRESS_OFFSET 4
#define HIFI_FREQ_176M 176947200
#define HIFI_FREQ_147M 147456000
#define HIFI_FREQ_64M 64000000
#define HIFI_INVALID_PROFILE 0xF
static td_u8 g_dsp_profile = HIFI_INVALID_PROFILE;
typedef struct {
td_s32 argc;
td_char argv[TEST_SUITE_MAX_ARGC][TEST_SUITE_MAX_ARGV_LEN];
} cmd_msg_queue;
typedef struct {
td_char *name;
td_s32 (*func)(td_s32 argc, td_char *argv[]);
td_bool running;
} functions;
typedef struct {
td_char *std_data_name;
td_u8 std_data_size;
td_char *td_data_name;
td_u8 td_data_size;
} data_type_func;
typedef struct {
athread_handle task;
td_bool task_active;
} sample_audio_inst;
static td_bool g_sample_cfg_singleton = TD_TRUE;
typedef struct {
td_char *sample;
td_char *config;
td_char *value;
} sample_set_config_arg;
typedef struct {
td_char *sample;
td_char *addr;
td_char *value;
} sample_audio_wr_arg;
typedef struct {
td_char *sample;
td_char *handle;
td_char *port;
td_char *ch_id;
td_char *type;
td_char *integer;
td_char *decimal;
} sample_set_vol_arg;
static td_void sample_set_dump_mask(td_u8 dump_mask)
{
td_s32 ret;
uapi_audio_debug_cfg cfg = {0};
ret = uapi_audio_get_debug_cfg(&cfg);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_audio_get_debug_cfg, ret);
return;
}
cfg.dump_mask = dump_mask;
ret = uapi_audio_set_debug_cfg(&cfg);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_audio_set_debug_cfg, ret);
return;
}
sap_alert_log_info("dump mask status");
sap_alert_log_bool((dump_mask & UAPI_AUDIO_DUMP_MASK_AI) != 0);
sap_alert_log_bool((dump_mask & UAPI_AUDIO_DUMP_MASK_SEA) != 0);
sap_alert_log_bool((dump_mask & UAPI_AUDIO_DUMP_MASK_AENC) != 0);
sap_alert_log_bool((dump_mask & UAPI_AUDIO_DUMP_MASK_ADEC) != 0);
sap_alert_log_bool((dump_mask & UAPI_AUDIO_DUMP_MASK_TRACK) != 0);
sap_alert_log_bool((dump_mask & UAPI_AUDIO_DUMP_MASK_AO) != 0);
}
static td_void sample_set_proc_mask(td_u8 proc_mask)
{
td_s32 ret;
uapi_audio_debug_cfg cfg = {0};
ret = uapi_audio_get_debug_cfg(&cfg);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_audio_get_debug_cfg, ret);
return;
}
cfg.proc_mask = proc_mask;
ret = uapi_audio_set_debug_cfg(&cfg);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_audio_set_debug_cfg, ret);
return;
}
sap_alert_log_info("proc mask status");
sap_alert_log_bool((proc_mask & UAPI_AUDIO_PROC_MASK_UART) != 0);
sap_alert_log_bool((proc_mask & UAPI_AUDIO_PROC_MASK_DIAG_SHELL) != 0);
}
#if defined(SAP_TWS_PRODUCT) || defined(SAP_SOUND_BOX_PRODUCT)
enum {
TWS_ROLE,
TWS_FORM,
TWS_MONO,
TWS_MAX,
};
typedef struct {
char *name;
td_u32 type;
td_u32 value;
} tws_config;
static tws_config g_tws_config[] = {
{"master", TWS_ROLE, AUDIO_TWS_ROLE_MASTER},
{"slave", TWS_ROLE, AUDIO_TWS_ROLE_SLAVE},
{"freeman", TWS_ROLE, AUDIO_TWS_ROLE_FREEMAN},
{"left", TWS_FORM, UAPI_AUDIO_PRODUCT_FORM_TWS_LEFT},
{"right", TWS_FORM, UAPI_AUDIO_PRODUCT_FORM_TWS_RIGHT},
{"mono", TWS_MONO, 1},
{"stereo", TWS_MONO, 0},
};
static td_void sample_set_tws_config(td_char *config)
{
td_u32 i;
td_u32 type = TWS_MAX;
td_u32 val;
for (i = 0; i < sizeof(g_tws_config) / sizeof(g_tws_config[0]); i++) {
if ((strcmp(g_tws_config[i].name, config) == 0)) {
type = g_tws_config[i].type;
val = g_tws_config[i].value;
break;
}
}
switch (type) {
case TWS_ROLE :
uapi_audio_set_tws_role((uapi_audio_tws_role)val);
break;
case TWS_FORM :
uapi_audio_set_product_form((uapi_audio_product_form)val);
break;
case TWS_MONO :
uapi_audio_set_tws_mono_mode((td_bool)val);
break;
default :
sap_alert_log_info("invalid tws config\n");
return;
}
}
#else
static td_void sample_set_tws_config(td_char *config)
{
audio_unused(config);
}
#endif
static td_void sample_set_dsp_profile(td_u8 profile)
{
g_dsp_profile = profile;
sap_alert_log_u32(g_dsp_profile);
}
static td_void sample_audio_init(td_u8 arg)
{
td_s32 ret;
if (arg == TD_TRUE) {
ret = uapi_audio_init();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_audio_init, ret);
}
sap_alert_log_info("call uapi_audio_init\n");
} else if (arg == TD_FALSE) {
ret = uapi_audio_deinit();
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_audio_deinit, ret);
}
sap_alert_log_info("call uapi_audio_deinit\n");
} else {
sap_alert_log_info("nothing changed!");
}
}
#ifndef MONO_PROFILE_CUT
static td_void sample_audio_set_global_mute(td_u8 arg)
{
td_s32 ret;
td_bool mute = !!arg;
ret = uapi_audio_set_global_mute(mute);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_audio_set_global_mute, ret);
}
}
#endif
static td_s32 sample_set_config(td_s32 argc, td_char *argv[])
{
td_u8 tmp_mask;
sample_set_config_arg *arg = (sample_set_config_arg *)argv;
if (argc == 0x2 && (strcmp("q", argv[1]) == 0)) {
return EXT_SUCCESS;
}
if (argc != (td_s32)sizeof(sample_set_config_arg) / (td_s32)sizeof(td_char *)) {
sap_err_log_info("nothing changed!");
return EXT_SUCCESS;
}
tmp_mask = (td_u8)strtoul(arg->value, TD_NULL, 0);
if (strcmp(arg->config, "singleton") == 0) {
g_sample_cfg_singleton = ((strtoul(arg->value, TD_NULL, 0)) == 0) ? TD_FALSE : TD_TRUE;
sap_alert_log_u32(g_sample_cfg_singleton);
} else if (strcmp(arg->config, "dump_mask") == 0) {
sample_set_dump_mask(tmp_mask);
} else if (strcmp(arg->config, "proc_mask") == 0) {
sample_set_proc_mask(tmp_mask);
} else if (strcmp(arg->config, "tws") == 0) {
sample_set_tws_config(arg->value);
} else if (strcmp(arg->config, "profile") == 0) {
sample_set_dsp_profile(tmp_mask);
} else if (strcmp(arg->config, "audio_init") == 0) {
sample_audio_init(tmp_mask);
#ifndef MONO_PROFILE_CUT
} else if (strcmp(arg->config, "global_mute") == 0) {
sample_audio_set_global_mute(tmp_mask);
#endif
} else {
sap_err_log_info("nothing changed!");
}
return EXT_SUCCESS;
}
#ifdef SAP_REG_DFX_SAMPLE_SUPPORT
td_s32 sample_audio_w4(td_s32 argc, td_char *argv[])
{
td_u32 val;
td_u32 addr;
td_u32 read_val;
sample_audio_wr_arg *arg = (sample_audio_wr_arg *)argv;
if (argc != (td_s32)sizeof(sample_audio_wr_arg) / (td_s32)sizeof(td_char *)) {
sap_printf("cmd input is invalid!\n");
return AUDIO_FAILURE;
}
addr = (td_u32)strtoul(arg->addr, TD_NULL, 16);
val = (td_u32)strtoul(arg->value, TD_NULL, 16);
if (is_4byte_aligned(addr) != TD_TRUE) {
sap_printf("Invalid address\n");
return AUDIO_FAILURE;
}
audio_reg_read(addr, read_val);
audio_reg_write(addr, val);
sap_printf("Writing addr 0x%08x: 0x%08x -> 0x%08x.\n", addr, read_val, val);
return AUDIO_SUCCESS;
}
#define MEM32_MAX_NUM 1000
td_s32 sample_audio_mem32(td_s32 argc, td_char *argv[])
{
td_u32 addr;
td_u32 len;
td_u32 val;
td_u32 i;
sample_audio_wr_arg *arg = (sample_audio_wr_arg *)argv;
if (argc != (td_s32)sizeof(sample_audio_wr_arg) / (td_s32)sizeof(td_char *)) {
sap_printf("cmd input is invalid!\n");
return AUDIO_FAILURE;
}
addr = (td_u32)strtoul(arg->addr, TD_NULL, 16);
len = (td_u32)strtoul(arg->value, TD_NULL, 16);
if (len == 0 || len > MEM32_MAX_NUM) {
sap_err_log_u32(len);
return EXT_FAILURE;
}
if (is_4byte_aligned(addr) != TD_TRUE) {
sap_printf("Invalid address\n");
return AUDIO_FAILURE;
}
for (i = 0; i < len; i++) {
if (i % 4 == 0) {
sap_printf("\n%08x =", addr);
}
audio_reg_read(addr, val);
sap_printf(" %08x", val);
addr = addr + ADDRESS_OFFSET;
}
sap_printf("\n");
return AUDIO_SUCCESS;
}
#endif
static td_s32 sample_set_vol(td_s32 argc, td_char *argv[])
{
td_s32 ret;
td_u32 handle;
uapi_audio_volume_cfg vol_cfg = {0, 0, 0, 0, 0};
sample_set_vol_arg *arg = (sample_set_vol_arg *)argv;
if (argc != (td_s32)sizeof(sample_set_vol_arg) / (td_s32)sizeof(td_char *)) {
sap_printf("cmd input is invalid!\n");
return AUDIO_FAILURE;
}
handle = (td_u32)strtoul(arg->handle, TD_NULL, 16);
vol_cfg.port = (td_u32)strtoul(arg->port, TD_NULL, 16);
vol_cfg.ch_id = (td_u32)strtoul(arg->ch_id, TD_NULL, 16);
vol_cfg.vol_type = (td_u32)strtoul(arg->type, TD_NULL, 16);
vol_cfg.integer = (td_s32)strtol(arg->integer, TD_NULL, 0);
vol_cfg.decimal = (td_s32)strtol(arg->decimal, TD_NULL, 0);
sap_printf("handle: 0x%08x |port: 0x%x |ch_id: 0x%d |type: 0x%d |integer: %d |decimal: %d\n",
handle, vol_cfg.port, vol_cfg.ch_id, vol_cfg.vol_type, vol_cfg.integer, vol_cfg.decimal);
ret = uapi_audio_set_volume(handle, &vol_cfg);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_audio_set_volume, ret);
return ret;
}
return AUDIO_SUCCESS;
}
#define SAMPLE_ITEM(name) {#name, name, TD_FALSE}
#define SAMPLE_ITEM2(name, function) {#name, function, TD_FALSE}
static functions g_audio_func[] = {
#ifdef SAP_REG_DFX_SAMPLE_SUPPORT
SAMPLE_ITEM2(w4, sample_audio_w4),
SAMPLE_ITEM2(mem32, sample_audio_mem32),
#endif
SAMPLE_ITEM(sample_set_vol),
SAMPLE_ITEM(sample_set_config),
SAMPLE_ITEM(sample_ai),
SAMPLE_ITEM(sample_ao),
SAMPLE_ITEM(sample_proc),
SAMPLE_ITEM2(sample_bmic, sample_bmic),
#ifndef SAP_MINIMIZE_SAMPLE_RELEASE
SAMPLE_ITEM(sample_asr),
SAMPLE_ITEM(sample_vad_feed),
SAMPLE_ITEM(sample_encode),
SAMPLE_ITEM(sample_cast_aenc_play),
SAMPLE_ITEM(sample_encode_play),
SAMPLE_ITEM(sample_adec),
SAMPLE_ITEM(sample_decode),
SAMPLE_ITEM(sample_ai_aenc),
SAMPLE_ITEM(sample_ai_sea_aenc),
SAMPLE_ITEM(sample_ai_ao),
SAMPLE_ITEM(sample_ai_sea_ao),
SAMPLE_ITEM(sample_sea),
SAMPLE_ITEM(sample_sea_only),
SAMPLE_ITEM(sample_gui_aef),
SAMPLE_ITEM(sample_lpwk),
SAMPLE_ITEM(sample_dump),
SAMPLE_ITEM(sample_rms),
SAMPLE_ITEM2(sample_phone, sample_phone_application),
SAMPLE_ITEM(sample_aef),
SAMPLE_ITEM(sample_effect),
SAMPLE_ITEM(sample_test_int),
SAMPLE_ITEM(sample_haid),
SAMPLE_ITEM2(sample_bmic_rx, sample_bmic),
SAMPLE_ITEM2(sample_bmic_tx, sample_bmic),
SAMPLE_ITEM2(sample_bmic_rec, sample_bmic),
SAMPLE_ITEM(sample_dpm),
SAMPLE_ITEM(sample_aha),
SAMPLE_ITEM(sample_sle_music),
SAMPLE_ITEM(sample_tts),
SAMPLE_ITEM(sample_wakeup),
#endif
};
static td_void audio_auto_exit_function(td_s32 argc, td_char *argv[], td_u32 fun_id)
{
td_u32 i;
td_char *q = "q";
td_char *cmd[] = {argv[0], q};
if (!g_sample_cfg_singleton) {
return;
}
if ((strcmp(argv[0], "mem32") == 0) || (strcmp(argv[0], "w4") == 0)) {
return;
}
if (argc == 0x2 && (strcmp("q", argv[1]) == 0)) {
g_audio_func[fun_id].running = TD_FALSE;
return;
}
for (i = 0; i < (sizeof(g_audio_func) / sizeof(g_audio_func[0])); i++) {
if (g_audio_func[i].running == TD_TRUE) {
(td_void)g_audio_func[i].func(0x2, cmd);
g_audio_func[i].running = TD_FALSE;
}
}
g_audio_func[fun_id].running = TD_TRUE;
}
static td_void update_dsp_profile(td_void)
{
#if (SAP_CHIP_TYPE == brandy)
#ifndef CONFIG_PROT_CORE
pm_hifi_mode_t hifi_mode;
if (SAP_DSP_CLK_HZ > HIFI_FREQ_176M) {
hifi_mode = HIFI_LPM_CLK_HIGH_LEVEL;
} else if (SAP_DSP_CLK_HZ > HIFI_FREQ_147M) {
hifi_mode = HIFI_LPM_CLK_LEVEL2;
} else if (SAP_DSP_CLK_HZ > HIFI_FREQ_64M) {
hifi_mode = HIFI_LPM_CLK_LEVEL1;
} else {
hifi_mode = HIFI_LPM_CLK_LOW_LEVEL;
}
if ((td_u32)g_dsp_profile < HIFI_LPM_CLK_MAX) {
hifi_mode = g_dsp_profile;
}
sap_printf("SAP_DSP_CLK_HZ = %d, hifi_mode = %d.\n", SAP_DSP_CLK_HZ, hifi_mode);
uapi_set_hifi_mode(hifi_mode);
#endif
#endif
}
static td_u32 g_data_type_cnt = 0;
static data_type_func g_data_type_func[] = {
{"uint8_t", sizeof(uint8_t), "td_u8", sizeof(td_u8)},
{"uint16_t", sizeof(uint16_t), "td_u16", sizeof(td_u16)},
{"uint32_t", sizeof(uint32_t), "td_u32", sizeof(td_u32)},
{"uint64_t", sizeof(uint64_t), "td_u64", sizeof(td_u64)},
{"int8_t", sizeof(int8_t), "td_s8", sizeof(td_s8)},
{"int16_t", sizeof(int16_t), "td_s16", sizeof(td_s16)},
{"int32_t", sizeof(int32_t), "td_s32", sizeof(td_s32)},
{"int64_t", sizeof(int64_t), "td_s64", sizeof(td_s64)},
{"uint8_t", sizeof(uint8_t), "td_bool", sizeof(td_bool)},
{"uint32_t", sizeof(uint32_t), "td_handle", sizeof(td_handle)},
{"char", sizeof(char), "td_char", sizeof(td_char)},
};
static td_void check_data_type(td_void)
{
td_u32 i;
td_s32 ret = EXT_SUCCESS;
g_data_type_cnt++;
for (i = 0; i < (sizeof(g_data_type_func) / sizeof(g_data_type_func[0])); i++) {
if (g_data_type_func[i].std_data_size != g_data_type_func[i].td_data_size) {
ret = EXT_FAILURE;
sap_err_log_str(g_data_type_func[i].std_data_name);
sap_err_log_str(g_data_type_func[i].td_data_name);
}
}
if (ret != EXT_SUCCESS) {
sap_err_log_info("check data type failed.");
} else {
sap_alert_log_info("check data type succeeded.");
}
}
td_void audio_execute_function(td_s32 argc, td_char *argv[])
{
td_u32 i;
td_s32 ret;
if (argc == 0) {
return;
}
if (strcmp("help", *argv) == 0) {
return;
}
if (g_data_type_cnt == 0) {
check_data_type();
}
ret = uapi_audio_set_dsp_log_level(AUDIO_LOG_LEVEL_WARN);
if (ret != EXT_SUCCESS) {
sap_err_log_fun(uapi_audio_set_dsp_log_level, ret);
}
for (i = 0; i < (sizeof(g_audio_func) / sizeof(g_audio_func[0])); i++) {
if (strcmp(*argv, g_audio_func[i].name) != 0) {
continue;
}
if (strcmp(*argv, "sample_proc") != 0) {
update_dsp_profile();
sample_audio_set_hifi_mode(UAPI_AUDIO_SCENE_UNKNOWN);
audio_auto_exit_function(argc, argv, i);
}
ret = g_audio_func[i].func(argc, argv);
sap_alert_log_str(g_audio_func[i].name);
if (ret != EXT_SUCCESS) {
sap_err_log_info("sample execute failed.");
} else {
sap_alert_log_info("sample execute succeeded.");
}
return;
}
sap_err_log_info("sample execute failed.");
}