Nordic nRF5 SDK 学习笔记之三, 蓝牙 5 从机定时广播,待联结建立交换数据后,主动断开与主机的联结

硬件:  Central: nRF52840, Peripheral: nRF52832

SDK: Ver 15.0.0

目标: Peripheral 从机定时启动蓝牙广播,以及与主机联结,待交换完数据后,主动断开与主机的联结

参考: https://devzone.nordicsemi.com/f/nordic-q-a/29365/advertisment-not-stopping

说明:
Nordic SoftDevice 蓝牙栈内部自动处理广播事务, 只有使用 协议栈 API 请求才能改变其处理流程;
即是仅在用户程序中设置蓝牙广播的 BLE_ADV_MODE_IDLE 模式,或调用 sd_ble_gap_adv_stop(),并不能确保蓝牙广播停止后不再启动; 
通过设置全局变量, 于 ble_advertising.c 中修改 ble_advertising_start() 函数中, 修改 sd_ble_gap_adv_start() 的启动条件, 便可实现真正的广播停止; 


主要步骤:

1. 定义两个定时器 TIMER1, TIMER2, 以及广播停止标识;

    TIMER1 用于从机蓝牙初始化及广播定时器; TIMER2 作为从机与主机断开的定时器;

APP_TIMER_DEF( bt_start_period_timer_id );
APP_TIMER_DEF( bt_cancel_period_timer_id );

#define BT_START_PERIOD_TIMER_INTERVAL    APP_TIMER_TICKS( 10000 )  // 10  秒
#define BT_CANCEL_PERIOD_TIMER_INTERVAL   APP_TIMER_TICKS( 100 )    // 100 毫秒

uint8_t    mark_of_adv_stop = 0;

并于 main.c 函数中初始化 timer, 创建定时器及触发回调函数,并启动 TIMER1;

int main ( void )
{

    //...
    timers_init();

    ret_code_t err_code;
    err_code = app_timer_create(&bt_start_period_timer_id, APP_TIMER_MODE_REPEATED, bt_start_timeout_handler);
    APP_ERROR_CHECK(err_code);

    err_code = app_timer_create(&bt_cancel_period_timer_id, APP_TIMER_MODE_REPEATED, bt_cancel_timeout_handler);
    APP_ERROR_CHECK(err_code);

    err_code = app_timer_start( bt_start_period_timer_id, BT_START_PERIOD_TIMER_INTERVAL, NULL);
    APP_ERROR_CHECK(err_code);

    //...

}

2. 定时器 TIMER1 回调函数, 开始蓝牙初始化和开始广播,并在函数中启动 TIMER2;

static void bt_start_timeout_handler(void * p_context) 
{ 
    UNUSED_PARAMETER(p_context);
    ret_code_t err_code;	

    err_code = app_timer_start( bt_cancel_period_timer_id, BT_CANCEL_PERIOD_TIMER_INTERVAL, NULL);
    APP_ERROR_CHECK(err_code);

    //printf( "adv current before adv-start: %d \r\n",(&m_advertising)->adv_mode_current);	
    if ( m_conn_handle == BLE_CONN_HANDLE_INVALID )
    {
        mark_of_adv_stop = 0;
        advertising_init();	
        advertising_start_with_mode( BLE_ADV_MODE_FAST );		
    }
    //printf( "adv current after adv-start: %d \r\n",(&m_advertising)->adv_mode_current);	
}

3. 定时器 TIMER2 回调函数

static void bt_cancel_timeout_handler(void * p_context) 
{ 
		
    UNUSED_PARAMETER(p_context);
    ret_code_t err_code;
    
	//printf( "adv current before gap-disc: %d \r\n",(&m_advertising)->adv_mode_current );
    
    if ( m_conn_handle != BLE_CONN_HANDLE_INVALID )
    {
        err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
        APP_ERROR_CHECK(err_code);
    }

    mark_of_adv_stop = 1;
    advertising_start_with_mode( BLE_ADV_MODE_IDLE );

    // printf( "adv current after gap-disc: %d \r\n",(&m_advertising)->adv_mode_current );

    // 注:曾用 sd_ble_gap_adv_stop() 测试,主机未扫描时,程序正常,但主机扫描联结后,程序出错
    // 但未进一步测试,故在此备注说明
    // err_code = sd_ble_gap_adv_stop( m_advertising.adv_handle );
    // APP_ERROR_CHECK(err_code);		

    app_timer_stop( bt_cancel_period_timer_id );   
}

4. 广播初始化函数

BLE_ADVERTISING_DEF( m_advertising );

/**@brief Function for initializing the Advertising functionality.*/ 
static void advertising_init(void)
{
    uint32_t                    err_code;
    ble_advertising_init_t      init;

    ble_advdata_manuf_data_t 	adv_manuf_data;
    uint8_array_t            	adv_manuf_data_array;
    uint8_t                  	adv_manuf_data_data[1];
    adv_manuf_data_data[0]      = 0x88;
	
    memset(&init, 0, sizeof(init));

    init.advdata.name_type              = BLE_ADVDATA_FULL_NAME;
    init.advdata.include_appearance     = false;
    init.advdata.flags              	= BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
    init.srdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
    init.srdata.uuids_complete.p_uuids  = m_adv_uuids;

    adv_manuf_data_array.p_data          = adv_manuf_data_data;
    adv_manuf_data_array.size            = sizeof(adv_manuf_data_data);
    adv_manuf_data.company_identifier    = 0x9876;
    adv_manuf_data.data                  = adv_manuf_data_array;
    init.advdata.p_manuf_specific_data   = &adv_manuf_data;	
	
    init.config.ble_adv_whitelist_enabled           = false;
    init.config.ble_adv_directed_high_duty_enabled  = false;
    init.config.ble_adv_directed_enabled            = false;	
    init.config.ble_adv_fast_enabled                = true;
    init.config.ble_adv_fast_interval               = APP_ADV_INTERVAL;
    init.config.ble_adv_fast_timeout                = APP_ADV_DURATION;
    init.evt_handler = on_adv_evt;

    err_code = ble_advertising_init(&m_advertising, &init);
    APP_ERROR_CHECK(err_code);

    ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}

5. 带广播模式的蓝牙广播启动函数

static void advertising_start_with_mode( ble_adv_mode_t mode )
{
    uint32_t err_code = ble_advertising_start(&m_advertising, mode);
    APP_ERROR_CHECK(err_code);
    bsp_board_led_on(ADVERTISING_LED);	
}

6.  添加sd_ble_gap_adv_start() 启动控制条件的 ble_advertising.c

extern uint8_t    mark_of_adv_stop;

uint32_t ble_advertising_start(ble_advertising_t * const p_advertising,
                               ble_adv_mode_t            advertising_mode)
{

    // ...
    if ( mark_of_adv_stop == 0 )
    {
        ret = sd_ble_gap_adv_start(p_advertising->adv_handle, p_advertising->conn_cfg_tag);

        if (ret != NRF_SUCCESS)
        {
            return ret;
        }
    }
    // ...
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值