#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); }