中科蓝讯蓝牙耳机SDK解析

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)
蓝牙音乐模式的消息处理,上下曲切换,暂停播放,音量调整,报告电池电量等

发布了66 篇原创文章 · 获赞 36 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_40860986/article/details/104596069