SDK结构
1.1 SDK目录结构
└─app
├─platform
│ ├─bsp //底层外设相关
│ ├─functions //功能相关
│ ├─gui //显示功能
│ ├─header
│ └─libs
└─projects //调用API
└─earphone
├─display //显示
├─message //消息处理
├─Output //文件输出
│ └─bin //音乐文件,配置
│ ├─res
│ │ ├─en
│ │ ├─eq
│ │ └─zh
│ └─Settings
│ └─Resources
│ ├─S6
│ │ ├─en
│ │ └─zh
│ └─TWS
│ ├─en
│ └─zh
├─plugin //插件
└─port //移植
1.1.1 bsp目录
该目录下,包含一些和底层硬件相关的数据,函数初始化
1.1.2 functions目录
主要包括蓝牙功能的实现,大部分的函数以库函数的形式提供
1.1.3 Message目录
主要包括按键消息处理,是蓝牙方案经常需要改动的目录
1.1.4 Plugin目录
音乐文件的调用,基本不会去修改这里
1.1.5 Port目录
主要包括硬件外设的调用,mani函数
2 代码运行流程
2.1 初始化
//正常启动Main函数
int main(void)
{
printf("Hello AB533X!\n");
bsp_sys_init();
func_run();
return 0;
}
bsp_sys_init();函数主要包括各种功能的初始化,获取download工具的配置。
func_run();主要是处理蓝牙消息和硬件的消息。
2.2 各模式循环
初始化之后,进入一个FUN函数,蓝牙耳机的FUN函数基本上都在跑func_bt
void func_run(void)
{
printf("%s\n", __func__);
//func_cb.sta = FUNC_AUX;
while (1) {
func_clear();
switch (func_cb.sta) {
#if FUNC_BT_EN
case FUNC_BT:
func_bt();
break;
#endif
#if FUNC_BTHID_EN
case FUNC_BTHID:
func_bthid();
break;
#endif // FUNC_BTHID_EN
#if FUNC_AUX_EN
case FUNC_AUX:
func_aux();
break;
#endif // FUNC_AUX_EN
case FUNC_PWROFF:
func_pwroff(sys_cb.pwrdwn_tone_en);
break;
case FUNC_BT_CBT:
func_bt_cbt();
break;
default:
func_exit();
break;
}
}
}
2.3 蓝牙模式
AT(.text.func.bt)
void func_bt(void)
{
printf("func_bt\n");
func_bt_enter();
while (func_cb.sta == FUNC_BT) {
func_bt_process();
func_bt_message(msg_dequeue());
}
func_bt_exit();
}
在程序跑到func_bt();的时候,SDK留给开发者处理的只有消息处理和电量检测,来电检测等,蓝牙耳机接收音频信号,解码那些都是屏蔽起来的。
printf("%s\n", func);
2.3.1 进入蓝牙模式
func_bt_enter();
主要执行蓝牙初始化,播报提示音
2.3.2 蓝牙模式大循环
func_bt_process();
包括响铃,通话,蓝牙音乐
sfunc_bt_ring();
sfunc_bt_call();
func_bt_message(msg_dequeue());
消息处理
2.3.3 补充
C语言的特殊宏
LINE 表示正在编译的文件的行号
FILE 表示正在编译的文件的名字
DATE_ 表示编译时刻的日期字符串,例如: “25 Dec 2007”
TIME 表示编译时刻的时间字符串,例如: “12:30:55”
#include <stdio.h>
int main(void)
{
printf("%s\r\n",__FILE__);
printf("%d\r\n",__LINE__);
printf("%s\r\n",__DATE__);
printf("%s\r\n",__TIME__);
return 0;
}
打印结果
speci_define.c
6
Jul 6 2019
00:46:39
2.4 消息
经常需要改动的部分
2.4.1 消息处理:
二次开发中修改最多的部分就是消息处理这一块,按键消息处理的修改最多。按键消息有长按,短按,双击,三击,四击,五击等等
Func函数的为例
AT(.text.func.msg)
void func_message(u16 msg)
{
switch (msg) {
case KL_NEXT_VOL_UP://如果长按NEXT_VOL_UP这个按键
if (sfunc_bt_call_flag) {
……
break;
}
……
}
2.4.2 消息来源:
以按键为例
void msg_enqueue(u16 msg);//消息队列
在程序中执行按键扫描函数:
u8 bsp_key_scan(void)
{
u8 key_val = NO_KEY;
u16 key = NO_KEY;
pwrkey_2_hw_pwroff_detect();
if (!get_adc_val()) {
return NO_KEY;
}
#if USER_ADKEY
key_val = get_adkey(adc_cb.key_val, xcfg_cb.user_adkey_en);
#endif // USER_ADKEY
#if USER_ADKEY2
if (key_val == NO_KEY) {
key_val = get_adkey2();
}
#endif // USER_ADKEY2
#if USER_IOKEY
if (key_val == NO_KEY) {
key_val = get_iokey();
}
#endif // USER_IOKEY
#if USER_PWRKEY
if (key_val == NO_KEY) {
key_val = get_pwrkey();
}
#endif // USER_PWRKEY
#if VBAT_DETECT_EN
sys_cb.vbat = get_vbat_val();
#endif // VBAT_DETECT_EN
#if (IRRX_SW_EN || IRRX_HW_EN)
if (key_val == NO_KEY) {
key_val = get_irkey();
}
#endif // (IRRX_SW_EN || IRRX_HW_EN)
#if USER_ADKEY_MUX_SDCLK
//需要放到最后处理,当没进行adc convert需要返回
if (key_val == NO_KEY) {
if (!adc_cb.sdclk_valid) {
return NO_KEY;
}
key_val = get_adkey(adc_cb.sdclk_val, xcfg_cb.user_adkey_mux_sdclk_en);
}
#endif // USER_ADKEY_MUX_SDCLK
key = bsp_key_process(key_val);//得到具体按下哪个按键
if (key != NO_KEY) {
//printf("enqueue: %04x\n", key);
if ((key & KEY_TYPE_MASK) == KEY_LONG_UP) {
msg_queue_detach(key | KEY_HOLD); //长按抬键,先清掉HOLD按键消息
}
#if KEY_MSG_REMAP_EN
key_msg_remap(&key); //按键重映射.
#endif
msg_enqueue(key);//把消息放到消息队列
}
return key_val;
}
2.4.3 按键消息的注意事项:
下面的宏都是按键消息:
以PLAY按键为例
#define K_PLAY (KEY_PLAY | KEY_SHORT) //下降沿
#define KU_PLAY (KEY_PLAY | KEY_SHORT_UP) //上升沿
#define KL_PLAY (KEY_PLAY | KEY_LONG) //长按
#define KLU_PLAY (KEY_PLAY | KEY_LONG_UP) //长按上升沿
#define KH_PLAY (KEY_PLAY | KEY_HOLD) //长按2秒左右
#define KD_PLAY (KEY_PLAY | KEY_DOUBLE) //双击
#define KTH_PLAY (KEY_PLAY | KEY_THREE) //三击
#define KFO_PLAY (KEY_PLAY | KEY_FOUR) //四击
#define KFI_PLAY (KEY_PLAY | KEY_FIVE) //五击
注意!每次按键都会触发下降沿。
以蓝牙模式为例:
程序先在func_bt_message函数做判断,如果在该函数没有找到一致的case,则会跑到公共的消息处理函数中 void func_message(u16 msg) 再做判断。
AT(.text.func.bt.msg)
void func_bt_message(u16 msg)
{
switch (msg) {
case KU_PLAY:
case KU_PLAY_POWER:
case KU_PLAY_MODE:
bt_music_play_pause();
f_bt.pp_2_unmute = sys_cb.mute;
break;
case KU_PREV_VOL_DOWN:
case KL_VOL_DOWN_PREV:
case KU_PREV:
bt_music_prev();
sys_cb.key2unmute_cnt = 15 * sys_cb.mute;
break;
……
default:
func_message(msg);
break;
2.4.4 应用:1S消息
再定时器中,每隔一秒发送一个消息MSG_SYS_1S
msg_enqueue(MSG_SYS_1S);
void usr_tmr5ms_isr(void)
{
//1s timer process
if ((tmr5ms_cnt % 200) == 0) {
msg_enqueue(MSG_SYS_1S);
tmr5ms_cnt = 0;
sys_cb.lpwr_warning_cnt++;
}
}
再蓝牙消息或者公共消息做处理,常用的1秒消息处理有报告电量,连接蓝牙自动播放。
case MSG_SYS_1S:
bt_send_msg(BT_MSG_HFP_REPORT_BAT);
break;
2.4.5 蓝牙消息函数:
三个状态的消息处理,蓝牙模式比较特殊,除了一个func_bt_message还有两个,响铃,通话。
响铃:void sfunc_bt_ring_message(u16 msg)
来电响铃的时候执行消息处理,主要包括接/挂电话,电量报告和按键消息公共处理。
AT(.text.func.btring.msg)
void sfunc_bt_ring_message(u16 msg)
{
switch (msg) {
case KU_PLAY:
case KU_HSF: //接听
case KU_PLAY_POWER:
case KU_PLAY_MODE:
bsp_clr_mute_sta();
bt_call_answer_incoming();
break;
case KD_PLAY:
case KL_HSF:
case KD_HSF:
bsp_clr_mute_sta();
bt_call_terminate(); //挂断
break;
case MSG_SYS_1S:
bt_send_msg(BT_MSG_HFP_REPORT_BAT);
break;
default:
func_message(msg);
break;
}
}
通话中:sfunc_bt_call_message();
通话过程的按键消息处理,主要包括音量调整,三方通话,电量报告
Music: void func_bt_message(u16 msg)
蓝牙音乐模式的消息处理,上下曲切换,暂停播放,音量调整,报告电池电量等
来源:CSDN
作者:CsData
链接:https://blog.csdn.net/qq_40860986/article/details/104596069