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

763 lines
19 KiB
C
Raw Normal View History

#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
2026-08-22 09:21:15 +00:00
/* 当前播的是非编号文件(如 aa.mp3下一曲直接 play_next */
#define KT_FILE_IDX_NONUM 0xFF
typedef struct _kt_var_
{
int kt_timer;
int t_cnt;
u8 led_mode;
u8 active_ch; /* 1~4 按键播放会话中, 0=无 */
u8 fail_ch; /* 处于失败快闪的通道, 0=无 */
2026-08-22 09:21:15 +00:00
u8 file_idx; /* 00/01/... 或 KT_FILE_IDX_NONUM */
} _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);
2026-08-22 09:21:15 +00:00
gpio_set_hd0(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();
if (on)
{
SYS_LED_ON();
if (__this->led_mode == KT_LED_IDLE)
{
2026-08-22 09:21:15 +00:00
/* 待机K1~K4 与音量灯同步慢闪 */
kt_key_led_all_on();
2026-08-22 09:21:15 +00:00
KUP_LED_ON();
KDOWN_LED_ON();
}
else if (__this->led_mode == KT_LED_FAIL)
{
2026-08-22 09:21:15 +00:00
/* 失败:仅对应通道 KEY_LED + SYS 快闪,音量灯保持灭 */
kt_key_led_on(__this->fail_ch);
2026-08-22 09:21:15 +00:00
KUP_LED_OFF();
KDOWN_LED_OFF();
}
else
{
/* 升级等SYS 快闪,按键灯全亮忽明忽暗时由 UPDATE 模式另控 */
KUP_LED_OFF();
KDOWN_LED_OFF();
}
}
else
{
SYS_LED_OFF();
kt_key_led_all_off();
2026-08-22 09:21:15 +00:00
KUP_LED_OFF();
KDOWN_LED_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);
2026-08-22 09:21:15 +00:00
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();
}
2026-08-22 09:21:15 +00:00
/* 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);
2026-08-22 09:21:15 +00:00
} */
2026-08-22 09:21:15 +00:00
/* void kt_update_led_finish(void)
{
printf("kt_update_led_finish\n");
2026-08-22 09:21:15 +00:00
//升级结束:恢复 SYS_LED 正常空闲慢闪
__this->fail_ch = 0;
kt_led_set_mode(KT_LED_IDLE);
2026-08-22 09:21:15 +00:00
} */
2026-08-22 09:21:15 +00:00
/* void kt_update_start_remind(void)
{
printf("kt_update_start_remind\n");
kt_update_led_start();
kt_update_play_tone(TONE_SUP);
2026-08-22 09:21:15 +00:00
} */
2026-08-22 09:21:15 +00:00
/* 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();
2026-08-22 09:21:15 +00:00
} */
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);
}
2026-08-22 09:21:15 +00:00
/*
*
* play_by_path stop(1) fsn play_next
*/
static int kt_numbered_exists(u8 idx)
{
static const char *const roots[] = {
"storage/sd1/C/",
"storage/udisk0/C/",
};
static const char *const exts[] = {
"mp3", "MP3", "wav", "WAV", "wma", "WMA",
"flac", "FLA", "ape", "APE", "m4a", "M4A",
};
char path[64];
FILE *fp;
u8 r, e;
for (r = 0; r < ARRAY_SIZE(roots); r++)
{
for (e = 0; e < ARRAY_SIZE(exts); e++)
{
sprintf(path, "%s%02d.%s", roots[r], idx, exts[e]);
fp = fopen(path, "r");
if (fp)
{
fclose(fp);
return 1;
}
}
}
return 0;
}
/* 根据当前播放文件名同步 file_idxNN.xxx → 序号,否则 NONUM */
static u8 kt_file_idx_from_cur(void)
{
u8 name[64];
u8 *p;
int len;
FILE *fp = music_player_get_file_hdl();
if (!fp)
{
return KT_FILE_IDX_NONUM;
}
len = fget_name(fp, name, sizeof(name));
if (len < 3)
{
return KT_FILE_IDX_NONUM;
}
p = name;
if ((p[0] == '\\') && (p[1] == 'U'))
{
p += 2;
if (len < 5)
{
return KT_FILE_IDX_NONUM;
}
}
if ((p[0] >= '0') && (p[0] <= '9') &&
(p[1] >= '0') && (p[1] <= '9') &&
(p[2] == '.'))
{
return (u8)((p[0] - '0') * 10 + (p[1] - '0'));
}
return KT_FILE_IDX_NONUM;
}
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)
{
2026-08-22 09:21:15 +00:00
/*
*
* 1) idx+1 exists fsn
* 2) play_next aa.mp3
* 3) play_next 00
*/
u8 from_nonum = (__this->file_idx == KT_FILE_IDX_NONUM);
if (!from_nonum)
{
2026-08-22 09:21:15 +00:00
u8 next_idx = __this->file_idx + 1;
printf("kt_channel_key_handler same ch next_idx=%d\n", next_idx);
if (kt_numbered_exists(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;
}
}
else
{
printf("kt_channel_key_handler no more numbered, play_next\n");
}
}
2026-08-22 09:21:15 +00:00
err = music_player_play_next();
if (err == MUSIC_PLAYER_SUCC)
{
2026-08-22 09:21:15 +00:00
u8 idx = kt_file_idx_from_cur();
/* 刚从非编号区绕回编号文件:统一回到 00 */
if (from_nonum && (idx != KT_FILE_IDX_NONUM))
{
printf("kt_channel_key_handler nonum done, wrap to 00\n");
if (idx == 0)
{
__this->file_idx = 0;
kt_play_success(ch);
return MUSIC_PLAYER_SUCC;
}
err = kt_play_file_idx(0);
if (err == MUSIC_PLAYER_SUCC)
{
__this->file_idx = 0;
kt_play_success(ch);
return MUSIC_PLAYER_SUCC;
}
}
else
{
__this->file_idx = idx;
printf("kt_channel_key_handler play_next ok file_idx=%d\n", __this->file_idx);
kt_play_success(ch);
return MUSIC_PLAYER_SUCC;
}
}
/* play_next 失败:回绕 00需求保证存在 */
printf("kt_channel_key_handler wrap to 00\n");
err = kt_play_file_idx(0);
if (err == MUSIC_PLAYER_SUCC)
{
__this->file_idx = 0;
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)
{
2026-08-22 09:21:15 +00:00
__this->file_idx = kt_file_idx_from_cur();
printf("kt_channel_key_handler idle play first ch=%d file_idx=%d\n",
ch, __this->file_idx);
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)
{
2026-08-22 09:21:15 +00:00
/* 音量+KUP/KDOWN 灯不单独闪 3s跟随 PLAY/IDLE 状态机 */
app_task_put_key_msg(KEY_VOL_UP, 0);
printf("kt vol+ %d\n", app_audio_get_volume(APP_AUDIO_CURRENT_STATE));
}
else
{
2026-08-22 09:21:15 +00:00
/* 音量-;下限 2 */
if (app_audio_get_volume(APP_AUDIO_STATE_MUSIC) > 2)
{
2026-08-22 09:21:15 +00:00
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
2026-08-22 09:21:15 +00:00
* KEY_LED + KUP/KDOWN
* 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);
}