DA14580主机扫描

本文详细介绍了蓝牙低功耗(BLE)设备在设备配置完成后,主机和从机如何执行不同的任务。主机通过ke_state_set()设置为可连接状态,并发起扫描;从机则设置为初始化数据库,建立服务和特征库后开始广播。扫描分为主动和被动模式,主动扫描可获取更多数据,被动扫描则只接收广播数据。扫描过程中,主机接收到广播报告后会取消扫描,准备建立连接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、发起扫描scan
在收到GAPM_SET_DEV_CONFIG消息后,开始回调void app_set_dev_config_complete_func(void)函数。 该函数在设备配置完成时调用。主机和从机从此处开始分道扬镳,各自执行不同的任务代码。

主机是ke_state_set()函数把状态设置为可连接,然后发起扫描app_start_scanning()。

从机是ke_state_set()函数把状态设置为初始化数据库,然后建立服务和特征数据库,完成后再发起广播。

当然,以上这些操作并不是直接就执行了,也是通过消息传递和对应的回调函数来处理。

可以看出,主机作为扫描者,并不需要创建服务和特征数据库。

主机的(扫描者,连接后是Client):

void app_set_dev_config_complete_func(void)
{
    ke_state_set(TASK_APP, APP_CONNECTABLE);
    
	#if BLE_INTEGRATED_HOST_GTL    
		struct app_ready_ind *ind = KE_MSG_ALLOC(APP_READY_IND, TASK_GTL, TASK_APP, app_ready_ind);
   
		ke_msg_send(ind);
	#else	
   		app_start_scanning();//发起扫描
	#endif //BLE_INTEGRATED_HOST_GTL
	 
    return;
}

下面是从机的(广播者,连接后是server)

void app_set_dev_config_complete_func(void)
{
    ke_state_set(TASK_APP, APP_DB_INIT);
    
    if (app_db_init())
    {
        // No service to add in the DB -> Start Advertising
        app_adv_start();//发起广播
    }
    
	#if BLE_INTEGRATED_HOST_GTL    
		struct app_ready_ind *ind = KE_MSG_ALLOC(APP_READY_IND, TASK_GTL, TASK_APP, app_ready_ind);
   
		ke_msg_send(ind);    
	#endif //BLE_INTEGRATED_HOST_GTL
	
    return;
}

BLE扫描分为2种方式,主动扫描和被动扫描。主动扫描和被动扫描的区别在于:主动扫描可以获得广播数据和扫描回应数据。而被动扫描只能获得广播数据。在实际项目中,如果需要获得对方对扫描的响应,需要主机设置为主动扫描。如果仅仅是需要广播数据则设置为被动扫描。被动扫描是完全只监听3个广播信道。主动扫描是监听3个广播信道收到某个设备的广播数据后,主动发出信息询问该设备。

app_start_scanning(void)函数初始化scan参数结构体,然后发出扫描请求消息。

//向GAP任务管理器发出扫描设备请求消息
void app_start_scanning(void)
{
    
#if !BLE_INTEGRATED_HOST_GTL
    periph_found = 0;
#endif    
    GPIO_SetInactive(ADV_LED_PORT,ADV_LED_PIN);
    struct gapm_start_scan_cmd *msg = KE_MSG_ALLOC(GAPM_START_SCAN_CMD, TASK_GAPM, TASK_APP, gapm_start_scan_cmd);
//填充扫描参数
    msg->mode = GAP_GEN_DISCOVERY;//普通发现模式
    msg->op.code = GAPM_SCAN_PASSIVE;//被动扫描
    msg->op.addr_src = GAPM_PUBLIC_ADDR;//公用地址
    msg->filter_duplic = SCAN_FILT_DUPLIC_EN;//开启重复过滤
    msg->interval = 10;//扫描间隔
    msg->window = 5;//扫描窗口

    ke_msg_send(msg);//发出请求扫描消息

    return;
}

/// Set scan mode Command扫描参数结构体
struct gapm_start_scan_cmd
{
    /// GAPM requested operation:
    /// - GAPM_SCAN_ACTIVE: Start active scan operation
    /// - GAPM_SCAN_PASSIVE: Start passive scan operation
    struct gapm_air_operation op;

    /// Scan interval
    uint16_t             interval;
    /// Scan window size
    uint16_t             window;

    /// Scanning mode :
    /// - GAP_GEN_DISCOVERY: General discovery mode
    /// - GAP_LIM_DISCOVERY: Limited discovery mode
    /// - GAP_OBSERVER_MODE: Observer mode
    uint8_t              mode;

    /// Scan filter policy:
    /// - SCAN_ALLOW_ADV_ALL: Allow advertising packets from anyone
    /// - SCAN_ALLOW_ADV_WLST: Allow advertising packets from White List devices only
    uint8_t              filt_policy;
    /// Scan duplicate filtering policy:
    /// - SCAN_FILT_DUPLIC_DIS: Disable filtering of duplicate packets
    /// - SCAN_FILT_DUPLIC_EN: Enable filtering of duplicate packets
    uint8_t              filter_duplic;
};


/// Air operation default parameters
struct gapm_air_operation
{
    /// Operation code.
    uint8_t  code;


    /** Own BD address source of the device:
     * - GAPM_PUBLIC_ADDR: Public Address
     * - GAPM_PROVIDED_RND_ADDR: Provided random address
     * - GAPM_GEN_STATIC_RND_ADDR: Generated static random address
     * - GAPM_GEN_RSLV_ADDR: Generated resolvable private random address
     * - GAPM_GEN_NON_RSLV_ADDR: Generated non-resolvable private random address
     * - GAPM_PROVIDED_RECON_ADDR: Provided Reconnection address (only for GAPM_ADV_DIRECT)
     */
    uint8_t addr_src;

    /// Dummy data use to retrieve internal operation state (should be set to 0).
    uint16_t state;

    /// Duration of resolvable address before regenerate it.
    uint16_t renew_dur;

    /// Provided own static private random address (addr_src = 1 or 5)
    struct bd_addr addr;
};

发现模式(Discovery Mode)

Non-discoverable mode(不可发现模式)
Limited discoverable mode(受限发现模式)
General discoverable mode(普通发现模式)
Broadcast mode(广播器模式)

发现模式与广播模式相互关联,“不可发现模式”下,只能选择Scannable undirected advertising和Non-connectable undirected advertising两种广播模式,即这种发现模式下,BLE设备不可以被连接。“广播器模式”下也只能选择不可被连接的广播模式。“受限发现模式”和“普通发现模式”下,可以任意选择广播模式。

第一种不可发现模式,使广播设备不被发现,参考 。注意,这里不被发现是指不被执行“普通发现规程”的Central设备发现。如果Central设备执行观察规程(obverving procedure),仍然能够看到广播信号。而手机APP等软件默认为观察规程,所以假如使用手机BLE扫描APP来测试,依旧可以看到设为“不可发现模式”的广播设备。正确的测试方法是使用CySmart(PC),将主机的扫描规程设置为“普通”或“受限”,而不是“观察者”,就能够观察到正确现象。

第二种受限发现模式,这里“受限”是指受时间限制。与普通发现模式相比,这个模式好像只是强制要求广播超时参数,其他相同。但是二者的“含义”是不同的,一个受限发现的设备,即有超时限制的设备,给Central传达一个消息,我很快就不行了,要连接应赶紧。所以Central设备如果发现了多个广播设备,在显示设备列表的时候,应该有意识的将受限发现模式的设备放在前面,而普通发现模式的设备放在后面。广播数据中有两个标志位:LE General Discovery Mode和LE Limited Discovery Mode,分别设置这两个标志位即可设置发现模式。

第三种为普通发现模式,可以选择任意的广播模式,然后自由处理各项参数。

发现规程(Discovery Procedure)

**Limited discovery:受限发现规程
General discovery:普通发现规程
Observation discovery:观察器规程**

前两个发现规程,基本上是为了匹配上面前三种发现模式而设计的。如果Central使用普通发现规程,则能够发现“受限发现模式”和“普通发现模式”的设备,不能发现“不可发现模式”设备。如果Central使用受限发现规程,则仅能够发现“受限发现模式”的设备。对于观察期规程,则能发现各种发现模式下的广播设备。
扫描参数设置里:
msg->mode = GAP_GEN_DISCOVERY;//普通发现模式
msg->op.code = GAPM_SCAN_PASSIVE;//被动扫描
就是执行普通发现规程,使用被动扫描方式。

二、扫描完成处理scan_complete

当主机扫描到一个广播信号后,会发出GAPM_ADV_REPORT_IND事件。该事件的默认回调函数是gapm_adv_report_ind_handler( );
{GAPM_ADV_REPORT_IND, (ke_msg_func_t)gapm_adv_report_ind_handler}, 下面看一下该函数:

/**
 ****************************************************************************************
 * @brief Handles Reception of advertise indication message during scanning.
 ****************************************************************************************
 */                                      
int gapm_adv_report_ind_handler(ke_msg_id_t msgid,
                                struct gapm_adv_report_ind *param,
                                ke_task_id_t dest_id,
                                ke_task_id_t src_id);
{
    
    app_adv_report_ind_func(param);//只处理gapm_adv_report_ind消息,msgid、dest_id、src_id全部舍去了。
            
    return (KE_MSG_CONSUMED);
}

这个GAP层的函数只是简单调用了用户APP层的函数app_adv_report_ind_func( )。可见该函数只是一个接口,具体实现功能留在APP层。先看一下gapm_adv_report_ind消息。

//广播或扫描报告  消息事件
/// Advertising or scanning report information event
struct gapm_adv_report_ind
{
    /// Advertising report structure
    struct adv_report report;
};

该结构体下定义了 adv_report report结构体。

///Advertising report structure
struct adv_report
{
    ///Event type:四种类型广播包
    /// - ADV_CONN_UNDIR: Connectable Undirected advertising
    /// - ADV_CONN_DIR: Connectable directed advertising
    /// - ADV_DISC_UNDIR: Discoverable undirected advertising
    /// - ADV_NONCONN_UNDIR: Non-connectable undirected advertising
    uint8_t        evt_type;
    ///Advertising address type: public/random
    uint8_t        adv_addr_type;
    ///Advertising address value
    struct bd_addr adv_addr;
    ///Data length in advertising packet
    uint8_t        data_len;
    ///Data of advertising packet
    uint8_t        data[ADV_DATA_LEN];
    ///RSSI value for advertising packet
    uint8_t        rssi;
};

adv_report report结构体定义了扫描到的广播包的参数。
Event type参数是事件类型,分为四种:可连接非定向、可连接定向、可发现非定向、不可连接非定向。它们对应四种广播类型:ADV_IND——通用广播、ADV_DIRECT_IND——定向连接广播、ADV_NONCONN_IND——不可连接广播、ADV_SCAN_IND——可扫描广播。

了解了gapm_adv_report_ind消息后,再来看app_adv_report_ind_func( )函数:前面的#if BLE_INTEGRATED_HOST_GTL是预定义使用外部处理器的情况。我们只看后面#else部分:

void app_adv_report_ind_func(struct gapm_adv_report_ind *param)
{
    
#if  BLE_INTEGRATED_HOST_GTL
    struct app_ext_adv_report_ind *cmd = KE_MSG_ALLOC(APP_EXT_ADV_REPORT_IND,
                                               TASK_GTL, TASK_APP, app_ext_adv_report_ind);

    cmd->addr_type =  param->report.adv_addr_type;
    memcpy ((void *)cmd->addr, (void *)&param->report.adv_addr, BD_ADDR_LEN);
		
    // Send the message
    ke_msg_send(cmd);
#else
    periph_found = 1;//发现广播者,置标志位
    periph_addr_type = param->report.adv_addr_type;//广播地址类型,public或随机
    memcpy ((void *)periph_addr, (void *)&param->report.adv_addr, BD_ADDR_LEN);//复制广播者的蓝牙设备地址6*8bit,48位
    
    //cancel scan procedure,发出消息请求取消扫描任务,这里是为了释放内存,准备建立连接了
    struct gapm_cancel_cmd *cmd = KE_MSG_ALLOC(GAPM_CANCEL_CMD,
                                               TASK_GAPM, TASK_APP,
                                               gapm_cancel_cmd);//GAPM_CANCEL_CMD:Cancel ongoing operation,取消正在进行的任务

    cmd->operation = GAPM_CANCEL;

    // Send the message
    ke_msg_send(cmd);//发出取消scan的消息
#endif
}

该APP函数主要干了三件事情:一是置一个标志位periph_found,说明扫描到一个广播信号了。第二是复制了广播者的BD地址。第三是发消息申请取消扫描。这里是为建立连接做准备。当然,开发者可以根据不同的需求功能,自己写这个函数。

void app_scanning_completed_func(void)
{
    
#if BLE_INTEGRATED_HOST_GTL    //使用外部MCU时
            /* EXT Processor - TASK APP over UART */
            /* send scan completed indication to external app*/
            void *cmd = ke_msg_alloc( APP_EXT_SCAN_CMP_IND, TASK_GTL, TASK_APP, 0);

            // Send the message
            ke_msg_send(cmd);
#else 

        if (periph_found)//发现广播者了
        {
            app_connect(periph_addr_type, periph_addr, 80);
        }
        else
        {
            app_start_scanning();//再次配置参数并扫描
        }
    
#endif
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ydgd118

您的鼓励是我最大的动力!谢赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值