KT25-1015_AC695x_SDK310/apps/kaotings/kt.c

627 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "kt.h"
#include "key_event_deal.h"
#include "music_player.h"
#include "audio_config.h"
#include "tone_player.h"
#include "update.h"
enum
{
KT_LED_IDLE = 0, /* 空闲慢闪 */
KT_LED_PLAY, /* 播放常亮 */
KT_LED_FAIL, /* 播放失败快闪 */
KT_LED_UPDATE, /* 升级快闪 */
};
/* 定时器 50ms慢闪 1s灭/1s亮快闪 100ms灭/100ms亮 */
#define KT_LED_SLOW_HALF 20
#define KT_LED_FAST_HALF 2
typedef struct _kt_var_
{
int kt_timer;
int t_cnt;
u8 led_mode;
u8 active_ch; /* 1~4 按键播放会话中, 0=无 */
u8 fail_ch; /* 处于失败快闪的通道, 0=无 */
u8 file_idx; /* 当前播放文件序号, 00/01/02... */
} _kt_var;
static _kt_var kt_var;
#define __this (&kt_var)
static void kt_key_led_on(u8 ch)
{
switch (ch)
{
case 1: KEY_LED_OUT_CH1_ON(); break;
case 2: KEY_LED_OUT_CH2_ON(); break;
case 3: KEY_LED_OUT_CH3_ON(); break;
case 4: KEY_LED_OUT_CH4_ON(); break;
default: break;
}
}
static void kt_key_led_all_on(void)
{
KEY_LED_OUT_CH1_ON();
KEY_LED_OUT_CH2_ON();
KEY_LED_OUT_CH3_ON();
KEY_LED_OUT_CH4_ON();
}
static void kt_key_led_all_off(void)
{
KEY_LED_OUT_CH1_OFF();
KEY_LED_OUT_CH2_OFF();
KEY_LED_OUT_CH3_OFF();
KEY_LED_OUT_CH4_OFF();
}
static void kt_led_bar_on(u8 ch)
{
switch (ch)
{
case 1:
LED_BAR_OUT_CH1_ON();
break;
case 2:
LED_BAR_OUT_CH2_ON();
break;
case 3:
LED_BAR_OUT_CH3_ON();
break;
case 4:
LED_BAR_OUT_CH4_ON();
break;
default:
break;
}
}
static void kt_led_bar_all_off(void)
{
LED_BAR_OUT_CH1_OFF();
LED_BAR_OUT_CH2_OFF();
LED_BAR_OUT_CH3_OFF();
LED_BAR_OUT_CH4_OFF();
}
static void kt_led_set_mode(u8 mode)
{
__this->led_mode = mode;
__this->t_cnt = 0;
kt_key_led_all_off();
kt_led_bar_all_off();
KUP_LED_OFF();
KDOWN_LED_OFF();
if (mode == KT_LED_PLAY)
{
SYS_LED_ON();
kt_key_led_on(__this->active_ch);
kt_led_bar_on(__this->active_ch);
KUP_LED_ON();
KDOWN_LED_ON();
}
else
{
SYS_LED_OFF();
}
}
static void kt_clear_fail_to_idle(void)
{
if (__this->fail_ch == 0)
{
return;
}
__this->fail_ch = 0;
kt_led_set_mode(KT_LED_IDLE);
}
static void kt_audio_all_off(void)
{
AUDIO_OUT_CH1_OFF();
AUDIO_OUT_CH2_OFF();
AUDIO_OUT_CH3_OFF();
AUDIO_OUT_CH4_OFF();
}
static void kt_audio_all_on(void)
{
AUDIO_OUT_CH1_ON();
AUDIO_OUT_CH2_ON();
AUDIO_OUT_CH3_ON();
AUDIO_OUT_CH4_ON();
}
/* 升级提示音需要四路音频输出同时打开LED 仍由状态机控制。 */
static void kt_all_channels_on(void)
{
kt_audio_all_on();
}
static void kt_all_channels_off(void)
{
kt_audio_all_off();
}
/* CS8406 复位释放,保证 IIS 通路稳定 */
static void kt_cs8406_reset_release(void)
{
gpio_set_direction(IO_PORTA_06, 0);
gpio_set_output_value(IO_PORTA_06, 0);
os_time_dly(5); /* ~50ms 保持复位 */
gpio_set_output_value(IO_PORTA_06, 1);
os_time_dly(30); /* ~300ms 等待芯片就绪 */
}
static void kt_channel_drive_off(u8 ch)
{
switch (ch)
{
case 1: AUDIO_OUT_CH1_OFF(); break;
case 2: AUDIO_OUT_CH2_OFF(); break;
case 3: AUDIO_OUT_CH3_OFF(); break;
case 4: AUDIO_OUT_CH4_OFF(); break;
default: break;
}
}
/* 音频通道互斥切换;灯光由 kt_led_set_mode() 统一处理。 */
static void kt_channel_outputs_on(u8 ch)
{
kt_audio_all_off();
switch (ch)
{
case 1: AUDIO_OUT_CH1_ON(); break;
case 2: AUDIO_OUT_CH2_ON(); break;
case 3: AUDIO_OUT_CH3_ON(); break;
case 4: AUDIO_OUT_CH4_ON(); break;
default: break;
}
}
static void kt_gpio_out_init(u32 pin)
{
gpio_set_pull_down(pin, 0);
gpio_set_pull_up(pin, 0);
gpio_set_direction(pin, 0);
gpio_set_output_value(pin, 0);
}
void kt_boot_init(void)
{
// CS8406 RST
gpio_set_pull_down(IO_PORTA_06, 0);
gpio_set_pull_up(IO_PORTA_06, 0);
gpio_set_direction(IO_PORTA_06, 0);
gpio_set_output_value(IO_PORTA_06, 0);
// iis 双绑引脚高阻化
gpio_set_pull_down(IO_PORTA_01, 0);
gpio_set_pull_up(IO_PORTA_01, 0);
gpio_set_direction(IO_PORTA_01, 1);
gpio_set_die(IO_PORTA_01, 1);
gpio_set_pull_down(IO_PORTA_05, 0);
gpio_set_pull_up(IO_PORTA_05, 0);
gpio_set_direction(IO_PORTA_05, 1);
gpio_set_die(IO_PORTA_05, 1);
// CS8406 TX EN
kt_gpio_out_init(AUDIO_OUT_CHANNEL1);
kt_gpio_out_init(AUDIO_OUT_CHANNEL2);
kt_gpio_out_init(AUDIO_OUT_CHANNEL3);
kt_gpio_out_init(AUDIO_OUT_CHANNEL4);
// key led output
kt_gpio_out_init(KEY_LED_OUT_CHANNEL1);
kt_gpio_out_init(KEY_LED_OUT_CHANNEL2);
kt_gpio_out_init(KEY_LED_OUT_CHANNEL3);
kt_gpio_out_init(KEY_LED_OUT_CHANNEL4);
// led bar output
kt_gpio_out_init(LED_BAR_OUT_CHANNEL1);
kt_gpio_out_init(LED_BAR_OUT_CHANNEL2);
kt_gpio_out_init(LED_BAR_OUT_CHANNEL3);
kt_gpio_out_init(LED_BAR_OUT_CHANNEL4);
// vol key led output
kt_gpio_out_init(KUP_LED_PIN);
kt_gpio_out_init(KDOWN_LED_PIN);
// sys led
kt_gpio_out_init(SYS_LED_PIN);
}
static void timer_cb(void *priv)
{
u8 half;
u8 on;
(void)priv;
if (__this->led_mode == KT_LED_PLAY)
{
SYS_LED_ON();
kt_key_led_all_off();
kt_key_led_on(__this->active_ch);
kt_led_bar_all_off();
kt_led_bar_on(__this->active_ch);
KUP_LED_ON();
KDOWN_LED_ON();
return;
}
half = (__this->led_mode == KT_LED_FAIL || __this->led_mode == KT_LED_UPDATE)
? KT_LED_FAST_HALF
: KT_LED_SLOW_HALF;
__this->t_cnt++;
if (__this->t_cnt <= half)
{
on = 0;
}
else if (__this->t_cnt <= (half * 2))
{
on = 1;
}
else
{
__this->t_cnt = 0;
on = 0;
}
kt_led_bar_all_off();
KUP_LED_OFF();
KDOWN_LED_OFF();
if (on)
{
SYS_LED_ON();
if (__this->led_mode == KT_LED_IDLE)
{
kt_key_led_all_on();
}
else if (__this->led_mode == KT_LED_FAIL)
{
kt_key_led_on(__this->fail_ch);
}
}
else
{
SYS_LED_OFF();
kt_key_led_all_off();
}
}
static void start_time_base(u32 time_base_ms)
{
if (__this->kt_timer)
{
sys_timer_del(__this->kt_timer);
}
__this->t_cnt = 0;
__this->kt_timer = sys_timer_add(NULL, timer_cb, time_base_ms);
}
/* 音量不记忆:空闲时固定恢复为 SYS_DEFAULT_VOL */
static void kt_vol_reset_default(void)
{
app_audio_set_volume(APP_AUDIO_STATE_MUSIC, SYS_DEFAULT_VOL, 1);
printf("kt vol reset to %d\n", SYS_DEFAULT_VOL);
}
static void kt_update_play_tone(const char *name)
{
int err;
u32 t;
extern u8 get_max_sys_vol(void);
tone_play_stop();
if (music_player_get_play_status() == FILE_DEC_STATUS_PLAY)
{
music_player_stop(0);
os_time_dly(5);
}
kt_cs8406_reset_release();
kt_all_channels_on();
app_audio_output_start();
app_audio_state_switch(APP_AUDIO_STATE_WTONE, get_max_sys_vol());
app_audio_set_volume(APP_AUDIO_STATE_WTONE, get_max_sys_vol(), 1);
printf("kt_update_play_tone: %s\n", name);
err = tone_play(name, 1);
printf("kt_update_play_tone err=%d\n", err);
/* 等 DAC 真正启动后再判 START避免 dec 已置位但无声 */
for (t = 0; t < 100; t++)
{
wdt_clear();
if (tone_get_dec_status() == TONE_START)
{
break;
}
os_time_dly(1);
}
printf("kt_tone wait_start=%d dec=%d get=%d\n",
t, tone_get_dec_status(), tone_get_status());
if (tone_get_dec_status() == TONE_START)
{
for (t = 0; t < 1500; t++)
{
wdt_clear();
if (tone_get_dec_status() != TONE_START)
{
break;
}
os_time_dly(1);
}
printf("kt_tone wait_end=%d\n", t);
os_time_dly(20); /* 播完后稍留,避免尾音被截断 */
}
else
{
printf("kt_tone start fail, keep ch on for a while\n");
os_time_dly(200);
}
kt_all_channels_off();
}
void kt_update_led_start(void)
{
printf("kt_update_led_start\n");
if (!__this->kt_timer)
{
start_time_base(50);
}
kt_led_set_mode(KT_LED_UPDATE);
}
void kt_update_led_finish(void)
{
printf("kt_update_led_finish\n");
/* 升级结束:恢复 SYS_LED 正常空闲慢闪 */
__this->fail_ch = 0;
kt_led_set_mode(KT_LED_IDLE);
}
void kt_update_start_remind(void)
{
printf("kt_update_start_remind\n");
kt_update_led_start();
kt_update_play_tone(TONE_SUP);
}
void kt_update_finish_remind(u16 result)
{
printf("kt_update_finish_remind result=0x%x\n", result);
if (result == UPDATA_SUCC)
{
kt_update_play_tone(TONE_EUP);
}
kt_update_led_finish();
}
void kt_init(void)
{
printf("kt_init\n");
__this->active_ch = 0;
__this->fail_ch = 0;
__this->file_idx = 0;
kt_led_set_mode(KT_LED_IDLE);
// CS8406 RST
gpio_set_output_value(IO_PORTA_06, 1);
/* 默认关闭各音频通道,按键播放时再打开对应通道 */
kt_audio_all_off();
kt_key_led_all_off();
kt_led_bar_all_off();
KUP_LED_OFF();
KDOWN_LED_OFF();
kt_vol_reset_default();
start_time_base(50);
printf("kt_init end\n");
}
/* 播放结束/出错/拔卡:关闭音频输出,恢复待机灯态和默认音量 */
int kt_music_play_end_handler(void)
{
if (__this->active_ch == 0)
{
return 0;
}
printf("kt_music_play_end_handler ch=%d\n", __this->active_ch);
kt_channel_drive_off(__this->active_ch);
__this->active_ch = 0;
__this->fail_ch = 0;
/* 必须停解码,否则 get_play_status 仍为 PLAY下次按键会误判 */
music_player_stop(0);
kt_led_set_mode(KT_LED_IDLE);
kt_vol_reset_default();
return 1;
}
static int kt_try_play_path(const char *path)
{
int err;
err = music_player_play_by_path((char *)"sd1", path);
if (err != MUSIC_PLAYER_SUCC)
{
err = music_player_play_by_path((char *)"udisk0", path);
}
return err;
}
static int kt_try_play_first_file(void)
{
int err;
err = music_player_play_first_file((char *)"sd1");
if (err != MUSIC_PLAYER_SUCC)
{
err = music_player_play_first_file((char *)"udisk0");
}
return err;
}
static int kt_play_file_idx(u8 idx)
{
char path[16];
sprintf(path, "/%02d.*", idx);
printf("kt_play_file_idx %s\n", path);
return kt_try_play_path(path);
}
static void kt_play_success(u8 ch)
{
printf("kt_play_success ch=%d\n", ch);
kt_channel_outputs_on(ch);
__this->active_ch = ch;
__this->fail_ch = 0;
kt_led_set_mode(KT_LED_PLAY);
}
static void kt_play_fail(u8 ch)
{
printf("kt_play_fail ch=%d\n", ch);
/* 失败SYS_LED 与对应 KEY_LED 快闪LED_BAR 和音量灯保持熄灭 */
kt_audio_all_off();
kt_key_led_all_off();
kt_led_bar_all_off();
__this->active_ch = 0;
__this->fail_ch = ch;
kt_led_set_mode(KT_LED_FAIL);
}
static void kt_switch_channel_only(u8 ch)
{
printf("kt_switch_channel_only ch=%d\n", ch);
/* 正在播放其它通道:只切音频输出,不改变当前歌曲 */
kt_channel_outputs_on(ch);
__this->active_ch = ch;
__this->fail_ch = 0;
printf("kt_switch_channel_only fail_ch=%d\n", __this->fail_ch);
kt_led_set_mode(KT_LED_PLAY);
}
static int kt_channel_key_handler(u8 ch)
{
int err;
u8 playing;
/* 若之前有通道错误,先恢复为慢闪 */
printf("kt_channel_key_handler ch=%d\n", ch);
kt_clear_fail_to_idle();
playing = (music_player_get_play_status() == FILE_DEC_STATUS_PLAY);
printf("kt_channel_key_handler playing=%d active_ch=%d\n", playing, __this->active_ch);
/* 仅 KT 会话在播active_ch!=0才走同通道 next / 异通道切换;
* 播完后 active_ch=0即便解码状态残留也按空闲处理 */
if (playing && (__this->active_ch != 0))
{
if (__this->active_ch == ch)
{
/* 同通道:先尝试播放 idx+1如 01→02失败再用播放器自动下一曲 */
u8 next_idx = __this->file_idx + 1;
printf("kt_channel_key_handler same ch next_idx=%d\n", next_idx);
err = kt_play_file_idx(next_idx);
if (err == MUSIC_PLAYER_SUCC)
{
__this->file_idx = next_idx;
kt_play_success(ch);
return MUSIC_PLAYER_SUCC;
}
err = music_player_play_next();
if (err == MUSIC_PLAYER_SUCC)
{
__this->file_idx = next_idx;
kt_play_success(ch);
return MUSIC_PLAYER_SUCC;
}
kt_play_fail(ch);
return MUSIC_PLAYER_ERR_NULL;
}
/* 正在播放但不是当前通道:只切换音频和对应灯态 */
printf("kt_channel_key_handler switch ch only %d->%d\n", __this->active_ch, ch);
kt_switch_channel_only(ch);
return MUSIC_PLAYER_SUCC;
}
/* 空闲(或播完残留状态):从 00.* 开始 */
if (playing) {
music_player_stop(0);
}
__this->file_idx = 0;
err = kt_play_file_idx(0);
if (err == MUSIC_PLAYER_SUCC)
{
printf("kt_channel_key_handler idle play 00 ch=%d\n", ch);
kt_play_success(ch);
return MUSIC_PLAYER_SUCC;
}
/* 00.* 不存在:回退播放 sd1/udisk0 第一首 */
err = kt_try_play_first_file();
if (err == MUSIC_PLAYER_SUCC)
{
printf("kt_channel_key_handler idle play first ch=%d\n", ch);
kt_play_success(ch);
return MUSIC_PLAYER_SUCC;
}
printf("kt_channel_key_handler kt_play_fail ch=%d\n", ch);
kt_play_fail(ch);
return MUSIC_PLAYER_ERR_NULL;
}
static int kt_vol_key_handler(u16 key)
{
if (key == KEY_USER_KEY_5)
{
/* 音量+,播放状态下两个音量键灯由统一状态机保持常亮 */
//app_audio_volume_up(1);
app_task_put_key_msg(KEY_VOL_UP,0);
printf("kt vol+ %d\n", app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
}
else
{
/* 音量-,播放状态下两个音量键灯由统一状态机保持常亮 */
//app_audio_volume_down(1);
if (app_audio_get_volume(APP_AUDIO_STATE_MUSIC) > 2)
{
app_task_put_key_msg(KEY_VOL_DOWN,0);
}
printf("kt vol- %d\n", app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
}
return MUSIC_PLAYER_ERR_NULL;
}
/*
* KEY1~4空闲播 00.*;同通道 next异通道只切输出
* 成功常亮,结束慢闪,失败快闪。
* KEY5/6音量 +/-;播放状态下两个音量键灯持续常亮。
*/
int kt_key_event_handler(u16 key)
{
u8 ch;
if (key == KEY_USER_KEY_5 || key == KEY_USER_KEY_6)
{
return kt_vol_key_handler(key);
}
if (key < KEY_USER_KEY_1 || key > KEY_USER_KEY_4)
{
return MUSIC_PLAYER_ERR_NULL;
}
ch = (u8)(key - KEY_USER_KEY_1 + 1);
printf("kt_key_event_handler key=%d ch=%d\n", key, ch);
return kt_channel_key_handler(ch);
}