627 lines
15 KiB
C
627 lines
15 KiB
C
#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);
|
||
}
|