1048 lines
27 KiB
C
1048 lines
27 KiB
C
/***************************************************************************
|
|
*
|
|
* Copyright 2015-2019 BES.
|
|
* All rights reserved. All unpublished rights reserved.
|
|
*
|
|
* No part of this work may be used or reproduced in any form or by any
|
|
* means, or stored in a database or retrieval system, without prior written
|
|
* permission of BES.
|
|
*
|
|
* Use of this work is governed by a license granted by BES.
|
|
* This work contains confidential and proprietary information of
|
|
* BES. which is protected by copyright, trade secret,
|
|
* trademark and other intellectual property rights.
|
|
*
|
|
****************************************************************************/
|
|
#include "anc_usb_app.h"
|
|
#include "anc_process.h"
|
|
#include "audioflinger.h"
|
|
#include "cmsis.h"
|
|
#include "hal_codec.h"
|
|
#include "hal_key.h"
|
|
#include "hal_sleep.h"
|
|
#include "hal_timer.h"
|
|
#include "hal_trace.h"
|
|
#include "hwtimer_list.h"
|
|
#include "pmu.h"
|
|
#include "tgt_hardware.h"
|
|
#include "usb_audio_app.h"
|
|
|
|
#ifdef ANC_SWITCH_GPADC_CHAN
|
|
#include "hal_gpadc.h"
|
|
#endif
|
|
|
|
#define ANC_KEY_CPU_WAKE_USER HAL_CPU_WAKE_LOCK_USER_4
|
|
#define ANC_STATE_CPU_WAKE_USER HAL_CPU_WAKE_LOCK_USER_5
|
|
|
|
#define ANC_FADE_IN_OUT
|
|
#define ANC_FADE_GAIN_STEP 1
|
|
#define ANC_MODE_SWITCH_WITHOUT_FADE
|
|
|
|
#ifndef ANC_INIT_ON_TIMEOUT_MS
|
|
#ifdef CHIP_BEST1000
|
|
#define ANC_INIT_ON_TIMEOUT_MS 1200
|
|
#else
|
|
#define ANC_INIT_ON_TIMEOUT_MS 200
|
|
#endif
|
|
#endif
|
|
#ifndef ANC_SHUTDOWN_TIMEOUT_MS
|
|
#define ANC_SHUTDOWN_TIMEOUT_MS 5000
|
|
#endif
|
|
|
|
#ifndef ANC_SWITCH_CHECK_INTERVAL
|
|
#define ANC_SWITCH_CHECK_INTERVAL MS_TO_TICKS(500)
|
|
#endif
|
|
|
|
#ifdef ANC_COEF_NUM
|
|
#if (ANC_COEF_NUM < 1)
|
|
#error "Invalid ANC_COEF_NUM configuration"
|
|
#endif
|
|
#else
|
|
#define ANC_COEF_NUM (1)
|
|
#endif
|
|
|
|
#define KEY_PROCESS_TIMER_INTERVAL (MS_TO_TICKS(1) / 2)
|
|
#define FADE_TIMER_INTERVAL (MS_TO_TICKS(1) / 2)
|
|
|
|
enum ANC_STATUS_T {
|
|
ANC_STATUS_NULL = 0,
|
|
ANC_STATUS_INIT,
|
|
ANC_STATUS_FADEIN,
|
|
ANC_STATUS_ENABLE,
|
|
ANC_STATUS_FADEOUT,
|
|
ANC_STATUS_DISABLE,
|
|
ANC_STATUS_INIT_CLOSE,
|
|
};
|
|
|
|
enum ANC_KEY_STATE_T {
|
|
ANC_KEY_STATE_NULL = 0,
|
|
ANC_KEY_STATE_CLOSE,
|
|
ANC_KEY_STATE_OPEN,
|
|
ANC_KEY_STATE_DEBOUNCE,
|
|
};
|
|
|
|
enum ANC_CTRL_SM_T {
|
|
ANC_CTRL_SM_OFF = 0,
|
|
ANC_CTRL_SM_COEF_0,
|
|
ANC_CTRL_SM_COEF_N = ANC_CTRL_SM_COEF_0 + ANC_COEF_NUM - 1,
|
|
|
|
ANC_CTRL_SM_QTY
|
|
};
|
|
|
|
static enum ANC_STATUS_T anc_status = ANC_STATUS_NULL;
|
|
static enum ANC_KEY_STATE_T prev_key_state = ANC_KEY_STATE_NULL;
|
|
static enum HAL_KEY_EVENT_T anc_key_event = HAL_KEY_EVENT_NONE;
|
|
static enum ANC_CTRL_SM_T anc_ctrl_sm = ANC_CTRL_SM_OFF;
|
|
#ifdef ANC_TALK_THROUGH
|
|
static bool talk_through = false;
|
|
#endif
|
|
|
|
static uint32_t anc_init_time;
|
|
static uint32_t anc_close_time;
|
|
|
|
static enum ANC_INDEX cur_coef_index = ANC_INDEX_0;
|
|
|
|
static enum AUD_SAMPRATE_T anc_sample_rate[AUD_STREAM_NUM];
|
|
|
|
static bool anc_running = false;
|
|
|
|
#ifdef ANC_SWITCH_GPIO_PIN
|
|
static const struct HAL_IOMUX_PIN_FUNCTION_MAP pinmux_anc = {
|
|
ANC_SWITCH_GPIO_PIN, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO,
|
|
HAL_IOMUX_PIN_PULLUP_ENABLE};
|
|
static bool gpio_pending;
|
|
static bool gpio_irq_en;
|
|
static enum HAL_GPIO_IRQ_POLARITY_T gpio_irq_polarity;
|
|
#endif
|
|
|
|
// ANC_SWITCH_GPADC_CHAN
|
|
static HWTIMER_ID gpadc_timer;
|
|
|
|
// ANC_FADE_IN_OUT
|
|
static uint8_t fadein_cnt = 0;
|
|
static uint8_t fadeout_cnt = 0;
|
|
static uint32_t prev_fade_time = 0;
|
|
|
|
#ifdef CFG_HW_ANC_LED_PIN
|
|
const struct HAL_IOMUX_PIN_FUNCTION_MAP pinmux_anc_led[] = {
|
|
{CFG_HW_ANC_LED_PIN, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO,
|
|
HAL_IOMUX_PIN_NOPULL},
|
|
};
|
|
#endif
|
|
#ifdef CFG_HW_ANC_LED_PIN2
|
|
const struct HAL_IOMUX_PIN_FUNCTION_MAP pinmux_anc_led2[] = {
|
|
{CFG_HW_ANC_LED_PIN2, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO,
|
|
HAL_IOMUX_PIN_NOPULL},
|
|
};
|
|
#endif
|
|
|
|
static void anc_full_open(void);
|
|
static void anc_full_close(void);
|
|
|
|
// ANC_FADE_IN_OUT
|
|
int anc_usb_app_fadein(enum ANC_TYPE_T anc_type) {
|
|
|
|
int32_t gain0_curr, gain1_curr;
|
|
int32_t gain0_tg, gain1_tg;
|
|
|
|
anc_get_gain(&gain0_curr, &gain1_curr, anc_type);
|
|
anc_get_cfg_gain(&gain0_tg, &gain1_tg, anc_type);
|
|
|
|
/*
|
|
anc_set_gain(gain0_tg, gain1_tg,anc_type);
|
|
|
|
return 0;
|
|
*/
|
|
if (gain0_tg > 0) {
|
|
if (gain0_curr < gain0_tg) {
|
|
if (gain0_curr + ANC_FADE_GAIN_STEP < gain0_tg) {
|
|
gain0_curr += ANC_FADE_GAIN_STEP;
|
|
} else {
|
|
gain0_curr = gain0_tg;
|
|
}
|
|
}
|
|
} else {
|
|
if (gain0_curr > gain0_tg) {
|
|
if (gain0_curr - ANC_FADE_GAIN_STEP > gain0_tg) {
|
|
gain0_curr -= ANC_FADE_GAIN_STEP;
|
|
} else {
|
|
gain0_curr = gain0_tg;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (gain1_tg > 0) {
|
|
if (gain1_curr < gain1_tg) {
|
|
if (gain1_curr + ANC_FADE_GAIN_STEP < gain1_tg) {
|
|
gain1_curr += ANC_FADE_GAIN_STEP;
|
|
} else {
|
|
gain1_curr = gain1_tg;
|
|
}
|
|
}
|
|
} else {
|
|
if (gain1_curr > gain1_tg) {
|
|
if (gain1_curr - ANC_FADE_GAIN_STEP > gain1_tg) {
|
|
gain1_curr -= ANC_FADE_GAIN_STEP;
|
|
} else {
|
|
gain1_curr = gain1_tg;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TRACE(3,"[%s] cur gain: %d %d", __func__, gain0_curr, gain1_curr);
|
|
anc_set_gain(gain0_curr, gain1_curr, anc_type);
|
|
|
|
if ((gain0_curr == gain0_tg) && (gain1_curr == gain1_tg)) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int anc_usb_app_fadeout(enum ANC_TYPE_T anc_type) {
|
|
|
|
/*
|
|
anc_set_gain(0, 0,anc_type);
|
|
|
|
return 0;
|
|
*/
|
|
|
|
int32_t gain0_curr, gain1_curr;
|
|
|
|
anc_get_gain(&gain0_curr, &gain1_curr, anc_type);
|
|
|
|
if (gain0_curr > 0) {
|
|
if (gain0_curr > ANC_FADE_GAIN_STEP) {
|
|
gain0_curr -= ANC_FADE_GAIN_STEP;
|
|
} else {
|
|
gain0_curr = 0;
|
|
}
|
|
} else if (gain0_curr < 0) {
|
|
if (gain0_curr < -ANC_FADE_GAIN_STEP) {
|
|
gain0_curr += ANC_FADE_GAIN_STEP;
|
|
} else {
|
|
gain0_curr = 0;
|
|
}
|
|
}
|
|
|
|
if (gain1_curr > 0) {
|
|
if (gain1_curr > ANC_FADE_GAIN_STEP) {
|
|
gain1_curr -= ANC_FADE_GAIN_STEP;
|
|
} else {
|
|
gain1_curr = 0;
|
|
}
|
|
} else if (gain1_curr < 0) {
|
|
if (gain1_curr < -ANC_FADE_GAIN_STEP) {
|
|
gain1_curr += ANC_FADE_GAIN_STEP;
|
|
} else {
|
|
gain1_curr = 0;
|
|
}
|
|
}
|
|
|
|
// TRACE(3,"[%s] gain: %d, %d", __func__, gain0_curr, gain1_curr);
|
|
anc_set_gain(gain0_curr, gain1_curr, anc_type);
|
|
|
|
if ((gain0_curr == 0) && (gain1_curr == 0)) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void anc_usb_app(bool on) {
|
|
TRACE(2, "%s: on=%d", __func__, on);
|
|
|
|
if (anc_running == on)
|
|
return;
|
|
else
|
|
anc_running = on;
|
|
|
|
if (on) {
|
|
anc_enable();
|
|
} else {
|
|
anc_disable();
|
|
}
|
|
|
|
#ifdef CFG_HW_ANC_LED_PIN
|
|
if (on) {
|
|
hal_gpio_pin_set(CFG_HW_ANC_LED_PIN);
|
|
} else {
|
|
hal_gpio_pin_clr(CFG_HW_ANC_LED_PIN);
|
|
}
|
|
#endif
|
|
#ifdef CFG_HW_ANC_LED_PIN2
|
|
if (on) {
|
|
hal_gpio_pin_set(CFG_HW_ANC_LED_PIN2);
|
|
} else {
|
|
hal_gpio_pin_clr(CFG_HW_ANC_LED_PIN2);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool anc_usb_app_get_status() { return anc_running; }
|
|
|
|
#ifdef ANC_SWITCH_GPIO_PIN
|
|
static void anc_key_gpio_handler(enum HAL_GPIO_PIN_T pin) {
|
|
struct HAL_GPIO_IRQ_CFG_T gpiocfg;
|
|
|
|
gpiocfg.irq_enable = false;
|
|
hal_gpio_setup_irq((enum HAL_GPIO_PIN_T)pinmux_anc.pin, &gpiocfg);
|
|
|
|
gpio_irq_en = false;
|
|
gpio_pending = true;
|
|
|
|
hal_cpu_wake_lock(ANC_KEY_CPU_WAKE_USER);
|
|
}
|
|
|
|
static void anc_key_gpio_irq_setup(enum HAL_GPIO_IRQ_POLARITY_T polarity) {
|
|
struct HAL_GPIO_IRQ_CFG_T gpiocfg;
|
|
|
|
if (gpio_irq_en && gpio_irq_polarity == polarity) {
|
|
return;
|
|
}
|
|
|
|
gpio_irq_polarity = polarity;
|
|
gpio_irq_en = true;
|
|
|
|
gpiocfg.irq_enable = true;
|
|
gpiocfg.irq_debounce = true;
|
|
gpiocfg.irq_polarity = polarity;
|
|
gpiocfg.irq_handler = anc_key_gpio_handler;
|
|
gpiocfg.irq_type = HAL_GPIO_IRQ_TYPE_LEVEL_SENSITIVE;
|
|
|
|
hal_gpio_setup_irq((enum HAL_GPIO_PIN_T)pinmux_anc.pin, &gpiocfg);
|
|
}
|
|
#endif
|
|
|
|
static enum ANC_KEY_STATE_T anc_key_level_to_state(bool level) {
|
|
enum ANC_KEY_STATE_T key_state;
|
|
|
|
#ifdef ANC_SWITCH_GPIO_PIN
|
|
anc_key_gpio_irq_setup(level ? HAL_GPIO_IRQ_POLARITY_LOW_FALLING
|
|
: HAL_GPIO_IRQ_POLARITY_HIGH_RISING);
|
|
#endif
|
|
|
|
key_state = level ? ANC_KEY_STATE_OPEN : ANC_KEY_STATE_CLOSE;
|
|
|
|
return key_state;
|
|
}
|
|
|
|
enum ANC_KEY_STATE_T anc_key_get_state(bool init_state) {
|
|
enum ANC_KEY_STATE_T key_state = ANC_KEY_STATE_NULL;
|
|
uint8_t level;
|
|
|
|
#if defined(ANC_SWITCH_GPIO_PIN)
|
|
level = hal_gpio_pin_get_val((enum HAL_GPIO_PIN_T)pinmux_anc.pin);
|
|
|
|
level = level ? true : false;
|
|
|
|
#elif defined(ANC_SWITCH_GPADC_CHAN)
|
|
HAL_GPADC_MV_T volt = 0;
|
|
|
|
if (hal_gpadc_get_volt(ANC_SWITCH_GPADC_CHAN, &volt)) {
|
|
level = volt > ANC_SWITCH_VOLTAGE_THRESHOLD ? ANC_SWITCH_LEVEL_HIGH
|
|
: ANC_SWITCH_LEVEL_LOW;
|
|
// TRACE(3,"[%s] level = %d, volt = %d", __func__, level, volt);
|
|
} else {
|
|
// TRACE(1,"[%s] else...", __func__);
|
|
return ANC_KEY_STATE_NULL;
|
|
}
|
|
#else
|
|
return key_state;
|
|
#endif
|
|
|
|
static uint32_t s_time;
|
|
static bool key_trigger = false;
|
|
static bool key_level = false;
|
|
|
|
if (init_state) {
|
|
key_level = level;
|
|
return anc_key_level_to_state(level);
|
|
}
|
|
|
|
if (key_trigger) {
|
|
if (key_level == level) {
|
|
key_trigger = false;
|
|
} else {
|
|
uint32_t diff_time_ms;
|
|
|
|
diff_time_ms = TICKS_TO_MS(hal_sys_timer_get() - s_time);
|
|
|
|
if (diff_time_ms >= 200) {
|
|
key_level = level;
|
|
key_trigger = false;
|
|
}
|
|
}
|
|
} else {
|
|
if (key_level != level) {
|
|
s_time = hal_sys_timer_get();
|
|
key_trigger = true;
|
|
}
|
|
}
|
|
|
|
if (key_trigger) {
|
|
key_state = ANC_KEY_STATE_DEBOUNCE;
|
|
} else {
|
|
key_state = anc_key_level_to_state(level);
|
|
}
|
|
|
|
return key_state;
|
|
}
|
|
|
|
static void anc_key_proc_open(bool from_key) {
|
|
int POSSIBLY_UNUSED ret;
|
|
uint32_t POSSIBLY_UNUSED time;
|
|
|
|
time = hal_sys_timer_get();
|
|
|
|
if (anc_status == ANC_STATUS_INIT_CLOSE) {
|
|
TRACE(1, "[ANC KEY PROC] ANC INIT_CLOSE => INIT T:%u", time);
|
|
|
|
anc_status = ANC_STATUS_INIT;
|
|
} else if (anc_status == ANC_STATUS_NULL) {
|
|
TRACE(1, "[ANC KEY PROC] ANC NULL => INIT T:%u", time);
|
|
|
|
anc_full_open();
|
|
#ifdef ANC_MODE_SWITCH_WITHOUT_FADE
|
|
} else if (anc_status == ANC_STATUS_ENABLE) {
|
|
#ifdef ANC_FF_ENABLED
|
|
ret = anc_select_coef(anc_sample_rate[AUD_STREAM_PLAYBACK], cur_coef_index,
|
|
ANC_FEEDFORWARD, ANC_GAIN_NO_DELAY);
|
|
TRACE(2, "[ANC KEY PROC] updata coefs ff %d: ret=%d", cur_coef_index, ret);
|
|
#endif
|
|
#ifdef ANC_FB_ENABLED
|
|
ret = anc_select_coef(anc_sample_rate[AUD_STREAM_PLAYBACK], cur_coef_index,
|
|
ANC_FEEDBACK, ANC_GAIN_NO_DELAY);
|
|
TRACE(2, "[ANC KEY PROC] updata coefs fb %d: ret=%d", cur_coef_index, ret);
|
|
#endif
|
|
#if defined(AUDIO_ANC_FB_MC_HW)
|
|
ret = anc_select_coef(anc_sample_rate[AUD_STREAM_PLAYBACK], cur_coef_index,
|
|
ANC_MUSICCANCLE, ANC_GAIN_NO_DELAY);
|
|
TRACE(2, "[ANC KEY PROC] anc_select_coef mc %d: ret=%d", cur_coef_index,
|
|
ret);
|
|
#endif
|
|
#if defined(AUDIO_ANC_TT_HW)
|
|
ret = anc_select_coef(anc_sample_rate[AUD_STREAM_PLAYBACK], cur_coef_index,
|
|
ANC_TALKTHRU, ANC_GAIN_NO_DELAY);
|
|
TRACE(2, "[ANC KEY PROC] anc_select_coef tt %d: ret=%d", cur_coef_index,
|
|
ret);
|
|
#endif
|
|
|
|
#endif
|
|
} else {
|
|
if (from_key && anc_status == ANC_STATUS_INIT) {
|
|
TRACE(1, "[ANC KEY PROC] ANC ON2 T:%u", time);
|
|
// Let state machine enable ANC
|
|
return;
|
|
}
|
|
|
|
TRACE(1, "[ANC KEY PROC] ANC ON T:%u", time);
|
|
|
|
#ifdef ANC_FF_ENABLED
|
|
ret = anc_select_coef(anc_sample_rate[AUD_STREAM_PLAYBACK], cur_coef_index,
|
|
ANC_FEEDFORWARD, ANC_GAIN_DELAY);
|
|
TRACE(2, "[ANC KEY PROC] anc_select_coef ff %d: ret=%d", cur_coef_index,
|
|
ret);
|
|
#endif
|
|
#ifdef ANC_FB_ENABLED
|
|
ret = anc_select_coef(anc_sample_rate[AUD_STREAM_PLAYBACK], cur_coef_index,
|
|
ANC_FEEDBACK, ANC_GAIN_DELAY);
|
|
TRACE(2, "[ANC KEY PROC] anc_select_coef fb %d: ret=%d", cur_coef_index,
|
|
ret);
|
|
#endif
|
|
#if defined(AUDIO_ANC_FB_MC_HW)
|
|
ret = anc_select_coef(anc_sample_rate[AUD_STREAM_PLAYBACK], cur_coef_index,
|
|
ANC_MUSICCANCLE, ANC_GAIN_DELAY);
|
|
TRACE(2, "[ANC KEY PROC] anc_select_coef mc %d: ret=%d", cur_coef_index,
|
|
ret);
|
|
#endif
|
|
#if defined(AUDIO_ANC_TT_HW)
|
|
ret = anc_select_coef(anc_sample_rate[AUD_STREAM_PLAYBACK], cur_coef_index,
|
|
ANC_TALKTHRU, ANC_GAIN_DELAY);
|
|
TRACE(2, "[ANC KEY PROC] anc_select_coef tt %d: ret=%d", cur_coef_index,
|
|
ret);
|
|
#endif
|
|
|
|
anc_usb_app(true);
|
|
#ifdef ANC_FADE_IN_OUT
|
|
fadein_cnt = 0;
|
|
anc_status = ANC_STATUS_FADEIN;
|
|
#else
|
|
{
|
|
int32_t gain_ch_l, gain_ch_r;
|
|
#if defined(AUDIO_ANC_TT_HW)
|
|
anc_get_cfg_gain(&gain_ch_l, &gain_ch_r, ANC_TALKTHRU);
|
|
anc_set_gain(gain_ch_l, gain_ch_r, ANC_TALKTHRU);
|
|
#endif
|
|
#ifdef ANC_FF_ENABLED
|
|
anc_get_cfg_gain(&gain_ch_l, &gain_ch_r, ANC_FEEDFORWARD);
|
|
anc_set_gain(gain_ch_l, gain_ch_r, ANC_FEEDFORWARD);
|
|
#endif
|
|
#ifdef ANC_FB_ENABLED
|
|
anc_get_cfg_gain(&gain_ch_l, &gain_ch_r, ANC_FEEDBACK);
|
|
anc_set_gain(gain_ch_l, gain_ch_r, ANC_FEEDBACK);
|
|
#endif
|
|
#ifdef AUDIO_ANC_FB_MC_HW
|
|
anc_get_cfg_gain(&gain_ch_l, &gain_ch_r, ANC_MUSICCANCLE);
|
|
anc_set_gain(gain_ch_l, gain_ch_r, ANC_MUSICCANCLE);
|
|
#endif
|
|
}
|
|
anc_status = ANC_STATUS_ENABLE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void anc_key_proc_close(bool from_key) {
|
|
uint32_t time;
|
|
|
|
time = hal_sys_timer_get();
|
|
anc_close_time = time;
|
|
|
|
if (anc_status == ANC_STATUS_INIT) {
|
|
TRACE(1, "[ANC KEY PROC] ANC INIT => INIT_CLOSE T:%u", time);
|
|
|
|
anc_status = ANC_STATUS_INIT_CLOSE;
|
|
} else if (anc_status == ANC_STATUS_INIT_CLOSE ||
|
|
anc_status == ANC_STATUS_DISABLE) {
|
|
if (from_key) {
|
|
TRACE(1, "[ANC KEY PROC] ANC OFF2 T:%u", time);
|
|
// Let state machine to shutdown ANC
|
|
return;
|
|
}
|
|
|
|
TRACE(1, "[ANC KEY PROC] ANC CLOSE => NULL T:%u", time);
|
|
|
|
anc_full_close();
|
|
} else {
|
|
TRACE(1, "[ANC KEY PROC] ANC OFF T:%u", time);
|
|
|
|
#ifdef ANC_FADE_IN_OUT
|
|
fadeout_cnt = 0;
|
|
anc_status = ANC_STATUS_FADEOUT;
|
|
#else
|
|
anc_usb_app(false);
|
|
anc_status = ANC_STATUS_DISABLE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void anc_switch_on_off_ctrl(void) {
|
|
uint32_t lock;
|
|
enum ANC_KEY_STATE_T key_state = ANC_KEY_STATE_NULL;
|
|
|
|
lock = int_lock();
|
|
// Check if there is a state change
|
|
if (anc_key_event != HAL_KEY_EVENT_NONE) {
|
|
key_state = prev_key_state;
|
|
anc_key_event = HAL_KEY_EVENT_NONE;
|
|
}
|
|
int_unlock(lock);
|
|
|
|
if (key_state == ANC_KEY_STATE_OPEN) {
|
|
anc_key_proc_open(true);
|
|
} else if (key_state == ANC_KEY_STATE_CLOSE) {
|
|
anc_key_proc_close(true);
|
|
}
|
|
}
|
|
|
|
void anc_double_click_on_off(void) {
|
|
uint32_t lock;
|
|
enum HAL_KEY_EVENT_T event;
|
|
|
|
lock = int_lock();
|
|
event = anc_key_event;
|
|
anc_key_event = HAL_KEY_EVENT_NONE;
|
|
hal_cpu_wake_unlock(ANC_KEY_CPU_WAKE_USER);
|
|
int_unlock(lock);
|
|
|
|
if (event == HAL_KEY_EVENT_NONE) {
|
|
return;
|
|
} else if (event == HAL_KEY_EVENT_DOUBLECLICK) {
|
|
prev_key_state = (prev_key_state == ANC_KEY_STATE_OPEN)
|
|
? ANC_KEY_STATE_CLOSE
|
|
: ANC_KEY_STATE_OPEN;
|
|
if (prev_key_state == ANC_KEY_STATE_OPEN) {
|
|
anc_key_proc_open(true);
|
|
} else {
|
|
anc_key_proc_close(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void anc_click_on_off(void) {
|
|
enum ANC_STATE_UPDATE_T {
|
|
ANC_STATE_UPDATE_NULL = 0,
|
|
ANC_STATE_UPDATE_TALK_THROUGH,
|
|
ANC_STATE_UPDATE_COEF,
|
|
};
|
|
|
|
enum HAL_KEY_EVENT_T event;
|
|
enum ANC_STATE_UPDATE_T state_update = ANC_STATE_UPDATE_NULL;
|
|
uint8_t click_cnt = 0;
|
|
uint32_t lock;
|
|
|
|
lock = int_lock();
|
|
event = anc_key_event;
|
|
anc_key_event = HAL_KEY_EVENT_NONE;
|
|
hal_cpu_wake_unlock(ANC_KEY_CPU_WAKE_USER);
|
|
int_unlock(lock);
|
|
|
|
if (event == HAL_KEY_EVENT_NONE) {
|
|
return;
|
|
#ifdef ANC_TALK_THROUGH
|
|
} else if (event == HAL_KEY_EVENT_LONGPRESS) {
|
|
talk_through = !talk_through;
|
|
if (talk_through) {
|
|
state_update = ANC_STATE_UPDATE_TALK_THROUGH;
|
|
cur_coef_index = ANC_COEF_NUM;
|
|
TRACE(0, "[ANC KEY PROC] anc_talk_through on");
|
|
} else {
|
|
state_update = ANC_STATE_UPDATE_COEF;
|
|
TRACE(0, "[ANC KEY PROC] anc_talk_through off");
|
|
}
|
|
#endif
|
|
} else if (event == HAL_KEY_EVENT_CLICK) {
|
|
click_cnt = 1;
|
|
}
|
|
if (event == HAL_KEY_EVENT_DOUBLECLICK) {
|
|
click_cnt = 2;
|
|
}
|
|
if (event == HAL_KEY_EVENT_TRIPLECLICK) {
|
|
click_cnt = 3;
|
|
}
|
|
|
|
if (click_cnt > 0) {
|
|
anc_ctrl_sm = (anc_ctrl_sm + click_cnt) % ANC_CTRL_SM_QTY;
|
|
state_update = ANC_STATE_UPDATE_COEF;
|
|
#ifdef ANC_TALK_THROUGH
|
|
talk_through = false;
|
|
#endif
|
|
}
|
|
|
|
if (state_update == ANC_STATE_UPDATE_COEF) {
|
|
if (anc_ctrl_sm >= ANC_CTRL_SM_COEF_0 &&
|
|
anc_ctrl_sm <= ANC_CTRL_SM_COEF_N) {
|
|
cur_coef_index = anc_ctrl_sm - ANC_CTRL_SM_COEF_0;
|
|
}
|
|
}
|
|
|
|
if (state_update != ANC_STATE_UPDATE_NULL) {
|
|
if (anc_ctrl_sm == ANC_CTRL_SM_OFF &&
|
|
state_update != ANC_STATE_UPDATE_TALK_THROUGH) {
|
|
anc_key_proc_close(true);
|
|
} else {
|
|
anc_key_proc_open(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void anc_key_process(void) {
|
|
#if defined(ANC_SWITCH_GPIO_PIN) || defined(ANC_SWITCH_GPADC_CHAN)
|
|
|
|
anc_switch_on_off_ctrl();
|
|
|
|
#elif defined(ANC_KEY_DOUBLE_CLICK_ON_OFF)
|
|
|
|
anc_double_click_on_off();
|
|
|
|
#else
|
|
|
|
anc_click_on_off();
|
|
|
|
#endif
|
|
}
|
|
|
|
void anc_state_transition(void) {
|
|
uint32_t t_time;
|
|
#ifdef ANC_FADE_IN_OUT
|
|
int res_ff = 0, res_fb = 0;
|
|
#ifdef AUDIO_ANC_TT_HW
|
|
int res_tt = 0;
|
|
#endif
|
|
#ifdef AUDIO_ANC_FB_MC_HW
|
|
int res_mc = 0;
|
|
#endif
|
|
#endif
|
|
|
|
t_time = hal_sys_timer_get();
|
|
|
|
if (anc_status == ANC_STATUS_INIT) {
|
|
if (t_time - anc_init_time >= MS_TO_TICKS(ANC_INIT_ON_TIMEOUT_MS)) {
|
|
// TRACE(2,"[%s] anc init on T:%u", __func__, t_time);
|
|
anc_key_proc_open(false);
|
|
// fadein or open
|
|
}
|
|
}
|
|
|
|
#ifdef ANC_FADE_IN_OUT
|
|
if (anc_status == ANC_STATUS_FADEIN) {
|
|
// process
|
|
if (fadein_cnt == 0) {
|
|
TRACE(2, "[%s] anc fadein started T:%u", __func__, t_time);
|
|
prev_fade_time = t_time;
|
|
fadein_cnt++;
|
|
} else if (fadein_cnt == 1) {
|
|
// delay 60 ticks
|
|
if (t_time - prev_fade_time >= 60) {
|
|
fadein_cnt++;
|
|
prev_fade_time = t_time;
|
|
}
|
|
} else {
|
|
// delay 1 ticks
|
|
if (t_time > prev_fade_time) {
|
|
// TRACE(2,"[%s] anc_usb_app_fadein T:%u", __func__, t_time);
|
|
#ifdef AUDIO_ANC_TT_HW
|
|
res_tt = anc_usb_app_fadein(ANC_TALKTHRU);
|
|
#endif
|
|
#ifdef ANC_FF_ENABLED
|
|
res_ff = anc_usb_app_fadein(ANC_FEEDFORWARD);
|
|
#endif
|
|
#ifdef ANC_FB_ENABLED
|
|
res_fb = anc_usb_app_fadein(ANC_FEEDBACK);
|
|
#endif
|
|
#ifdef AUDIO_ANC_FB_MC_HW
|
|
res_mc = anc_usb_app_fadein(ANC_MUSICCANCLE);
|
|
#endif
|
|
if (res_ff == 0 && res_fb == 0
|
|
#ifdef AUDIO_ANC_TT_HW
|
|
&& res_tt == 0
|
|
#endif
|
|
#ifdef AUDIO_ANC_FB_MC_HW
|
|
&& res_mc == 0
|
|
#endif
|
|
) {
|
|
anc_status = ANC_STATUS_ENABLE;
|
|
TRACE(2, "[%s] anc fadein done T:%u", __func__, t_time);
|
|
} else {
|
|
prev_fade_time = t_time;
|
|
}
|
|
}
|
|
}
|
|
} else if (anc_status == ANC_STATUS_FADEOUT) {
|
|
// process
|
|
if (fadeout_cnt == 0) {
|
|
TRACE(2, "[%s] anc fadeout started T:%u", __func__, t_time);
|
|
prev_fade_time = t_time;
|
|
fadeout_cnt++;
|
|
} else if (fadeout_cnt == 1) {
|
|
// delay 1 ticks
|
|
if (t_time > prev_fade_time) {
|
|
// TRACE(2,"[%s] anc_usb_app_fadeout T:%u", __func__, t_time);
|
|
#ifdef AUDIO_ANC_TT_HW
|
|
res_tt = anc_usb_app_fadeout(ANC_TALKTHRU);
|
|
#endif
|
|
#ifdef ANC_FF_ENABLED
|
|
res_ff = anc_usb_app_fadeout(ANC_FEEDFORWARD);
|
|
#endif
|
|
#ifdef ANC_FB_ENABLED
|
|
res_fb = anc_usb_app_fadeout(ANC_FEEDBACK);
|
|
#endif
|
|
#ifdef AUDIO_ANC_FB_MC_HW
|
|
res_mc = anc_usb_app_fadein(ANC_MUSICCANCLE);
|
|
#endif
|
|
if (res_ff == 0 && res_fb == 0
|
|
#ifdef AUDIO_ANC_TT_HW
|
|
&& res_tt == 0
|
|
#endif
|
|
#ifdef AUDIO_ANC_FB_MC_HW
|
|
&& res_mc == 0
|
|
#endif
|
|
) {
|
|
fadeout_cnt++;
|
|
}
|
|
|
|
prev_fade_time = t_time;
|
|
}
|
|
} else {
|
|
anc_usb_app(false);
|
|
anc_status = ANC_STATUS_DISABLE;
|
|
TRACE(2, "[%s] anc fadeout done T:%u", __func__, t_time);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (anc_status == ANC_STATUS_INIT_CLOSE || anc_status == ANC_STATUS_DISABLE) {
|
|
if (t_time - anc_close_time >= MS_TO_TICKS(ANC_SHUTDOWN_TIMEOUT_MS)) {
|
|
// TRACE(2,"[%s] anc shutdown T:%u", __func__, t_time);
|
|
anc_key_proc_close(false);
|
|
}
|
|
}
|
|
|
|
if (anc_status == ANC_STATUS_NULL || anc_status == ANC_STATUS_ENABLE) {
|
|
hal_cpu_wake_unlock(ANC_STATE_CPU_WAKE_USER);
|
|
} else {
|
|
hal_cpu_wake_lock(ANC_STATE_CPU_WAKE_USER);
|
|
}
|
|
}
|
|
|
|
int anc_usb_app_key(enum HAL_KEY_CODE_T code, enum HAL_KEY_EVENT_T event) {
|
|
#if !defined(ANC_SWITCH_GPIO_PIN) && !defined(ANC_SWITCH_GPADC_CHAN)
|
|
|
|
#ifdef ANC_KEY_DOUBLE_CLICK_ON_OFF
|
|
|
|
if (code == ANC_FUNCTION_KEY) {
|
|
if (event == HAL_KEY_EVENT_DOUBLECLICK) {
|
|
anc_key_event = event;
|
|
hal_cpu_wake_lock(ANC_KEY_CPU_WAKE_USER);
|
|
// The key event has been processed
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
if (code == ANC_FUNCTION_KEY) {
|
|
if (event == HAL_KEY_EVENT_CLICK || event == HAL_KEY_EVENT_DOUBLECLICK ||
|
|
event == HAL_KEY_EVENT_TRIPLECLICK ||
|
|
event == HAL_KEY_EVENT_LONGPRESS) {
|
|
anc_key_event = event;
|
|
hal_cpu_wake_lock(ANC_KEY_CPU_WAKE_USER);
|
|
}
|
|
// The key event has been processed
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
// Let other applications check the key event
|
|
return 1;
|
|
}
|
|
|
|
void anc_key_check(void) {
|
|
enum ANC_KEY_STATE_T key_state;
|
|
|
|
#ifdef ANC_SWITCH_GPIO_PIN
|
|
uint32_t lock;
|
|
|
|
gpio_pending = false;
|
|
#endif
|
|
|
|
key_state = anc_key_get_state(false);
|
|
|
|
if (key_state == ANC_KEY_STATE_NULL) {
|
|
return;
|
|
} else if (key_state == ANC_KEY_STATE_DEBOUNCE) {
|
|
hal_cpu_wake_lock(ANC_KEY_CPU_WAKE_USER);
|
|
} else if (key_state != prev_key_state) {
|
|
prev_key_state = key_state;
|
|
// Reuse click event to tag a state change
|
|
anc_key_event = HAL_KEY_EVENT_CLICK;
|
|
hal_cpu_wake_lock(ANC_KEY_CPU_WAKE_USER);
|
|
} else if (anc_key_event == HAL_KEY_EVENT_NONE) {
|
|
#ifdef ANC_SWITCH_GPIO_PIN
|
|
lock = int_lock();
|
|
if (!gpio_pending) {
|
|
hal_cpu_wake_unlock(ANC_KEY_CPU_WAKE_USER);
|
|
}
|
|
int_unlock(lock);
|
|
#else
|
|
hal_cpu_wake_unlock(ANC_KEY_CPU_WAKE_USER);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void anc_key_gpadc_timer_handler(void *param) {
|
|
hwtimer_start(gpadc_timer, ANC_SWITCH_CHECK_INTERVAL);
|
|
}
|
|
|
|
static void anc_key_init(void) {
|
|
#if defined(ANC_SWITCH_GPIO_PIN)
|
|
hal_iomux_init((struct HAL_IOMUX_PIN_FUNCTION_MAP *)&pinmux_anc, 1);
|
|
hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)pinmux_anc.pin, HAL_GPIO_DIR_IN, 0);
|
|
// Make sure gpio value is ready
|
|
hal_sys_timer_delay(3);
|
|
#elif defined(ANC_SWITCH_GPADC_CHAN)
|
|
hal_gpadc_open(ANC_SWITCH_GPADC_CHAN, HAL_GPADC_ATP_20MS, NULL);
|
|
// Make sure gpadc channel data is ready
|
|
hal_sys_timer_delay(6);
|
|
gpadc_timer = hwtimer_alloc(anc_key_gpadc_timer_handler, NULL);
|
|
ASSERT(gpadc_timer, "Failed to alloc gpadc timer");
|
|
hwtimer_start(gpadc_timer, ANC_SWITCH_CHECK_INTERVAL);
|
|
#endif
|
|
|
|
// Add other key initialize
|
|
}
|
|
|
|
#if defined(USB_AUDIO_DYN_CFG) && !defined(__AUDIO_RESAMPLE__)
|
|
static void anc_sample_rate_change(enum AUD_STREAM_T stream,
|
|
enum AUD_SAMPRATE_T rate,
|
|
enum AUD_SAMPRATE_T *new_play,
|
|
enum AUD_SAMPRATE_T *new_cap) {
|
|
enum AUD_SAMPRATE_T play_rate, cap_rate;
|
|
|
|
if (anc_sample_rate[stream] != rate) {
|
|
#ifdef CHIP_BEST1000
|
|
if (stream == AUD_STREAM_PLAYBACK) {
|
|
play_rate = rate;
|
|
cap_rate = rate * (anc_sample_rate[AUD_STREAM_CAPTURE] /
|
|
anc_sample_rate[AUD_STREAM_PLAYBACK]);
|
|
} else {
|
|
play_rate = rate / (anc_sample_rate[AUD_STREAM_CAPTURE] /
|
|
anc_sample_rate[AUD_STREAM_PLAYBACK]);
|
|
cap_rate = rate;
|
|
}
|
|
#else
|
|
play_rate = rate;
|
|
cap_rate = rate;
|
|
#ifdef ANC_FF_ENABLED
|
|
anc_select_coef(play_rate, cur_coef_index, ANC_FEEDFORWARD,
|
|
ANC_GAIN_NO_DELAY);
|
|
#endif
|
|
|
|
#ifdef ANC_FB_ENABLED
|
|
anc_select_coef(play_rate, cur_coef_index, ANC_FEEDBACK, ANC_GAIN_NO_DELAY);
|
|
#endif
|
|
|
|
#if defined(AUDIO_ANC_FB_MC_HW)
|
|
anc_select_coef(play_rate, cur_coef_index, ANC_MUSICCANCLE,
|
|
ANC_GAIN_NO_DELAY);
|
|
#endif
|
|
|
|
#if defined(AUDIO_ANC_TT_HW)
|
|
anc_select_coef(play_rate, cur_coef_index, ANC_TALKTHRU, ANC_GAIN_NO_DELAY);
|
|
#endif
|
|
|
|
#endif
|
|
|
|
TRACE(5, "%s: Update anc sample rate from %u/%u to %u/%u", __func__,
|
|
anc_sample_rate[AUD_STREAM_PLAYBACK],
|
|
anc_sample_rate[AUD_STREAM_CAPTURE], play_rate, cap_rate);
|
|
|
|
if (new_play) {
|
|
*new_play = play_rate;
|
|
}
|
|
if (new_cap) {
|
|
*new_cap = cap_rate;
|
|
}
|
|
|
|
anc_sample_rate[AUD_STREAM_PLAYBACK] = play_rate;
|
|
anc_sample_rate[AUD_STREAM_CAPTURE] = cap_rate;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void anc_full_open(void) {
|
|
AF_ANC_HANDLER POSSIBLY_UNUSED handler;
|
|
|
|
#if defined(USB_AUDIO_DYN_CFG) && !defined(__AUDIO_RESAMPLE__)
|
|
handler = anc_sample_rate_change;
|
|
#else
|
|
handler = NULL;
|
|
#endif
|
|
|
|
#ifdef USB_AUDIO_APP
|
|
usb_audio_keep_streams_running(true);
|
|
#endif
|
|
|
|
pmu_anc_config(1);
|
|
|
|
#ifdef ANC_FF_ENABLED
|
|
af_anc_open(ANC_FEEDFORWARD, anc_sample_rate[AUD_STREAM_PLAYBACK],
|
|
anc_sample_rate[AUD_STREAM_CAPTURE], handler);
|
|
anc_open(ANC_FEEDFORWARD);
|
|
#endif
|
|
|
|
#ifdef ANC_FB_ENABLED
|
|
af_anc_open(ANC_FEEDBACK, anc_sample_rate[AUD_STREAM_PLAYBACK],
|
|
anc_sample_rate[AUD_STREAM_CAPTURE], handler);
|
|
anc_open(ANC_FEEDBACK);
|
|
#if defined(AUDIO_ANC_FB_MC_HW)
|
|
anc_open(ANC_MUSICCANCLE);
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(AUDIO_ANC_TT_HW)
|
|
anc_open(ANC_TALKTHRU);
|
|
#endif
|
|
|
|
anc_init_time = hal_sys_timer_get();
|
|
anc_status = ANC_STATUS_INIT;
|
|
}
|
|
|
|
static void anc_full_close(void) {
|
|
|
|
#if defined(AUDIO_ANC_TT_HW)
|
|
anc_close(ANC_TALKTHRU);
|
|
#endif
|
|
|
|
#ifdef ANC_FF_ENABLED
|
|
anc_close(ANC_FEEDFORWARD);
|
|
af_anc_close(ANC_FEEDFORWARD);
|
|
#endif
|
|
|
|
#ifdef ANC_FB_ENABLED
|
|
#if defined(AUDIO_ANC_FB_MC_HW)
|
|
anc_close(ANC_MUSICCANCLE);
|
|
#endif
|
|
anc_close(ANC_FEEDBACK);
|
|
af_anc_close(ANC_FEEDBACK);
|
|
#endif
|
|
|
|
pmu_anc_config(0);
|
|
|
|
anc_status = ANC_STATUS_NULL;
|
|
|
|
#ifdef USB_AUDIO_APP
|
|
usb_audio_keep_streams_running(false);
|
|
#endif
|
|
}
|
|
|
|
void anc_usb_app_loop(void) {
|
|
#if defined(ANC_SWITCH_GPIO_PIN) || defined(ANC_SWITCH_GPADC_CHAN)
|
|
anc_key_check();
|
|
#endif
|
|
anc_key_process();
|
|
anc_state_transition();
|
|
}
|
|
|
|
void anc_usb_app_init(enum AUD_IO_PATH_T input_path,
|
|
enum AUD_SAMPRATE_T playback_rate,
|
|
enum AUD_SAMPRATE_T capture_rate) {
|
|
enum ANC_KEY_STATE_T key_state;
|
|
|
|
#ifdef CFG_HW_ANC_LED_PIN
|
|
hal_iomux_init(pinmux_anc_led, ARRAY_SIZE(pinmux_anc_led));
|
|
hal_gpio_pin_set_dir(CFG_HW_ANC_LED_PIN, HAL_GPIO_DIR_OUT, 0);
|
|
#endif
|
|
#ifdef CFG_HW_ANC_LED_PIN2
|
|
hal_iomux_init(pinmux_anc_led2, ARRAY_SIZE(pinmux_anc_led2));
|
|
hal_gpio_pin_set_dir(CFG_HW_ANC_LED_PIN2, HAL_GPIO_DIR_OUT, 0);
|
|
#endif
|
|
|
|
anc_key_init();
|
|
|
|
#ifdef __AUDIO_SECTION_SUPPT__
|
|
anc_load_cfg();
|
|
#endif
|
|
|
|
anc_sample_rate[AUD_STREAM_PLAYBACK] =
|
|
hal_codec_anc_convert_rate(playback_rate);
|
|
anc_sample_rate[AUD_STREAM_CAPTURE] =
|
|
hal_codec_anc_convert_rate(capture_rate);
|
|
|
|
#if defined(ANC_SWITCH_GPIO_PIN) || defined(ANC_SWITCH_GPADC_CHAN)
|
|
key_state = anc_key_get_state(true);
|
|
prev_key_state = key_state;
|
|
#elif defined(ANC_KEY_DOUBLE_CLICK_ON_OFF)
|
|
key_state = ANC_KEY_STATE_OPEN;
|
|
prev_key_state = key_state;
|
|
#else
|
|
key_state = ANC_KEY_STATE_OPEN;
|
|
anc_ctrl_sm = ANC_CTRL_SM_COEF_0 + cur_coef_index;
|
|
#endif
|
|
|
|
#ifdef ANC_INIT_OFF
|
|
key_state = ANC_KEY_STATE_CLOSE;
|
|
prev_key_state = key_state;
|
|
anc_ctrl_sm = ANC_CTRL_SM_OFF;
|
|
#endif
|
|
|
|
if (key_state == ANC_KEY_STATE_OPEN) {
|
|
anc_full_open();
|
|
}
|
|
}
|
|
|
|
void anc_usb_app_term(void) { anc_full_close(); }
|