nrf51822程序的分析(二)

nrf51822程序的分析( 二)

接着上篇分析,这次从主函数的协议栈开始分析。


1.3.蓝牙协议栈

1.3.1.协议栈中的变量

蓝牙协议栈开源的部分程序主要放在ble_conn_params.c,softdevice_handler.c等文件中。中间包括一些蓝牙协议栈的变量。
softdevice_handler中会存储一些softdevice相关的变量(整个蓝牙设备)
蓝牙系统主要靠事件驱动进行调度。下面是蓝牙事件的结构体定义:

/**@brief BLE事件头部. */
typedef struct
{
  uint16_t evt_id;                      /**< BLE_<module>_EVT 对应时间编号 */
  uint16_t evt_len;                     /**< 除头部外其他数据的字节长度 */
} ble_evt_hdr_t;

typedef struct
{
  ble_evt_hdr_t header;               /**< 事件头部*/
  union
  {
    ble_common_evt_t  common_evt;     /**< 公共时间, evt_id in BLE_EVT_* series. */
    ble_gap_evt_t     gap_evt;        /**< GAP生成事件, evt_id in BLE_GAP_EVT_* series. */
    ble_l2cap_evt_t   l2cap_evt;      /**< L2CAP生成事件, evt_id in BLE_L2CAP_EVT* series. */
    ble_gattc_evt_t   gattc_evt;      /**< GATT客户端生成事件, evt_id in BLE_GATTC_EVT* series.*/
    ble_gatts_evt_t   gatts_evt;      /**< GATT服务器生成时间, evt_id in BLE_GATTS_EVT* series.*/
  } evt;
} ble_evt_t;

前一部分是事件的头部,用来标识是具体哪种类型的事件。后面是用共用体表示的具体事件的值。

1.3.2.协议栈的初始化

主函数中调用ble_stack_init对蓝牙进行初始化

static void ble_stack_init(void)
{
    uint32_t err_code;

    // 初始化softdevice
    SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);

    //使能协议栈
    err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
    APP_ERROR_CHECK(err_code);

    // 注册SoftDevice处理模块
    err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
    APP_ERROR_CHECK(err_code);
}

BLE协议栈的主要工作为:
1>.初始化蓝牙协议栈的事件处理
2>.绑定ble事件调度函数
3>.绑定sys事件调度函数。

先分析初始化代码。EVT_BUFFER作为存储传入事件缓存传入蓝牙的协议栈内。函数内确定一下事件缓冲区的指向和大小,确定一下回调函数softdevice_evt_schedule,最后进行使能和开中断。其中sd_softdevice_enable和sd_nvic_EnableIRQ为协议栈中不开源的代码,只需要传入对应参数即可。

#define SOFTDEVICE_HANDLER_INIT(CLOCK_SOURCE,                             \
                                USE_SCHEDULER)                          \
    do                                                           \
    {                                                             \
        static uint32_t EVT_BUFFER[CEIL_DIV(MAX(                    \
                                          MAX(BLE_STACK_EVT_MSG_BUF_SIZE, \
                                                    ANT_STACK_EVT_STRUCT_SIZE), \
                                                SYS_EVT_MSG_BUF_SIZE \
                                               ),                               \
                                            sizeof(uint32_t))];             \
        uint32_t ERR_CODE;                                               \
        ERR_CODE = softdevice_handler_init((CLOCK_SOURCE),                \
                                           EVT_BUFFER,                 \
                                           sizeof(EVT_BUFFER),               \
                                  (USE_SCHEDULER) ? softdevice_evt_schedule : NULL);\
        APP_ERROR_CHECK(ERR_CODE);                                         \
    } while (0)

uint32_t softdevice_handler_init(nrf_clock_lfclksrc_t           clock_source,
                                 void *                         p_evt_buffer,
                                 uint16_t                       evt_buffer_size,
                                 softdevice_evt_schedule_func_t evt_schedule_func)
{
    uint32_t err_code;
    // 保存参数
#if defined (BLE_STACK_SUPPORT_REQD) || defined (ANT_STACK_SUPPORT_REQD)
    if (p_evt_buffer == NULL)
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    if (!is_word_aligned(p_evt_buffer))
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    m_evt_buffer = (uint8_t *)p_evt_buffer;        //现在使用蓝牙协议栈
#else
    //如果不在蓝牙协议站或者ANT协议栈下p_evt_buffer不是必须的
    UNUSED_PARAMETER(p_evt_buffer);
#endif

#if defined (BLE_STACK_SUPPORT_REQD)     
    m_ble_evt_buffer_size = evt_buffer_size;
#else
    UNUSED_PARAMETER(evt_buffer_size);
#endif

    m_evt_schedule_func = evt_schedule_func;

    // 初始化
    err_code = sd_softdevice_enable(clock_source, softdevice_assertion_handler);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }

    m_softdevice_enabled = true;

    // 使能蓝牙中断(优先级早就被栈设置好).
    return sd_nvic_EnableIRQ(SWI2_IRQn);
}

softdevice_evt_schedule回调函数只有在SWI2_IRQHandler中断发生才被使用。SWI2_IRQHandler中断函数和在开启调度后发送事件的回调函数softdevice_evt_get最终调用的都是intern_softdevice_events_execute函数。

void intern_softdevice_events_execute(void)
{
    if (!m_softdevice_enabled)
         return;

    bool no_more_soc_evts = (m_sys_evt_handler == NULL);    //ble_evt_dispatch
#ifdef BLE_STACK_SUPPORT_REQD
    bool no_more_ble_evts = (m_ble_evt_handler == NULL);   //sys_evt_dispatch
#endif
#ifdef ANT_STACK_SUPPORT_REQD
    bool no_more_ant_evts = (m_ant_evt_handler == NULL);
#endif

    for (;;)
    {
        uint32_t err_code;
        if (!no_more_soc_evts)         //初始化中绑定了sys_evt_dispatch,因此这必进
        {
            uint32_t evt_id;
            //从SOC上得到事件
            err_code = sd_evt_get(&evt_id);
            if (err_code == NRF_ERROR_NOT_FOUND)
            {
                no_more_soc_evts = true;
            }
            else if (err_code != NRF_SUCCESS)
            {
                APP_ERROR_HANDLER(err_code);
            }
            else
            {
                m_sys_evt_handler(evt_id); //调用应用上的SOC事件函数sys_evt_dispatch
            }
        }

#ifdef BLE_STACK_SUPPORT_REQD
        if (!no_more_ble_evts) // 获得BLE事件
        {
            // 从协议栈中得到事件
            uint16_t evt_len = m_ble_evt_buffer_size;
            err_code = sd_ble_evt_get(m_evt_buffer, &evt_len);
            if (err_code == NRF_ERROR_NOT_FOUND)
            {
                no_more_ble_evts = true;
            }
            else if (err_code != NRF_SUCCESS)
            {
                APP_ERROR_HANDLER(err_code);
            }
            else
            {
                //调用应用上的BLE协议栈函数ble_evt_dispatch
                m_ble_evt_handler((ble_evt_t *)m_evt_buffer);
            }
        }
#endif

#ifdef ANT_STACK_SUPPORT_REQD
        if (!no_more_ant_evts)// 获得ANT事件
        {
            //从协议栈上获取事件
            err_code = sd_ant_event_get(&((ant_evt_t *)m_evt_buffer)->channel,
                                        &((ant_evt_t *)m_evt_buffer)->event,
                                        ((ant_evt_t *)m_evt_buffer)->evt_buffer);
            if (err_code == NRF_ERROR_NOT_FOUND)
            {
                no_more_ant_evts = true;
            }
            else if (err_code != NRF_SUCCESS)
            {
                APP_ERROR_HANDLER(err_code);
            }
            else
            {
                m_ant_evt_handler((ant_evt_t *)m_evt_buffer); //回调
            }
        }
#endif

        if (no_more_soc_evts)  //这里no_more_soc_evts=1后才进入
        {
#if defined(ANT_STACK_SUPPORT_REQD) && defined(BLE_STACK_SUPPORT_REQD)
            if (no_more_ble_evts && no_more_ant_evts)
            {
                break;
            }
#elif defined(BLE_STACK_SUPPORT_REQD)
            if (no_more_ble_evts)
            {
                break;
            }
#elif defined(ANT_STACK_SUPPORT_REQD)
            if (no_more_ant_evts)
            {
                break;
            }
#else
            break;
#endif
        }
    }
}

m_sys_evt_handler ,m_ble_evt_handler 在协议栈初始化的时候被赋值,实际指向sys_evt_dispatch,ble_evt_dispatch。ANT协议栈为被用到,忽略。这个函数是获取协议栈中的事件并轮询调度协议栈的事件处理函数,直到事件队列中没有事件,再跳出for循环。
softdevice_ble_evt_handler_set和softdevice_sys_evt_handler_set函数是用来确定蓝牙协议栈的事件调度函数为ble_evt_dispatch和sys_evt_dispatch的。下面具体分析ble_evt_dispatch。

1.3.3.协议栈事件调度(ble_evt_dispatch)

调度的代码放在应用层。虽然用户可以修改,但整体还是基于一个模板来的。

static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
    on_ble_evt(p_ble_evt);
    ble_conn_params_on_ble_evt(p_ble_evt);
    ble_lbs_on_ble_evt(&m_lbs, p_ble_evt);
}

在协议栈的调度函数中,主要轮询3个部分:
1>.蓝牙事件
对事件的ID号进行区分不同的事件,调用不同的操作。
比如说GAP连接事件进行绑定接口;断开时间负责解绑;安全参数请求调用sd_ble_gap_sec_params_reply;超时睡眠等。这里一般的事件和事件处理都可以看做是模板,我们可以在处理里面加写自己的指示之类的处理。

static void on_ble_evt(ble_evt_t * p_ble_evt)
{
    uint32_t                         err_code;
    static ble_gap_evt_auth_status_t m_auth_status;
    ble_gap_enc_info_t *             p_enc_info;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            nrf_gpio_pin_set(CONNECTED_LED_PIN_NO);
            nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO);
            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
            err_code = app_button_enable();
            APP_ERROR_CHECK(err_code);
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            nrf_gpio_pin_clear(CONNECTED_LED_PIN_NO);
            m_conn_handle = BLE_CONN_HANDLE_INVALID;

            err_code = app_button_disable();
            APP_ERROR_CHECK(err_code);

            advertising_start();
            break;

        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
            err_code = sd_ble_gap_sec_params_reply(m_conn_handle,
                                                   BLE_GAP_SEC_STATUS_SUCCESS,
                                                   &m_sec_params);
            APP_ERROR_CHECK(err_code);
            break;

        case BLE_GATTS_EVT_SYS_ATTR_MISSING:
            err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0);
            APP_ERROR_CHECK(err_code);
            break;

        case BLE_GAP_EVT_AUTH_STATUS:
            m_auth_status = p_ble_evt->evt.gap_evt.params.auth_status;
            break;

        case BLE_GAP_EVT_SEC_INFO_REQUEST:
            p_enc_info = &m_auth_status.periph_keys.enc_info;
            if (p_enc_info->div == p_ble_evt->evt.gap_evt.params.sec_info_request.div)
            {
                err_code = sd_ble_gap_sec_info_reply(m_conn_handle, p_enc_info, NULL);
                APP_ERROR_CHECK(err_code);
            }
            else
            {
                // No keys found for this device
                err_code = sd_ble_gap_sec_info_reply(m_conn_handle, NULL, NULL);
                APP_ERROR_CHECK(err_code);
            }
            break;

        case BLE_GAP_EVT_TIMEOUT:
            if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISEMENT)
            {
                nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO);

                // Configure buttons with sense level low as wakeup source.
                nrf_gpio_cfg_sense_input(WAKEUP_BUTTON_PIN,
                                         BUTTON_PULL,
                                         NRF_GPIO_PIN_SENSE_LOW);

                // Go to system-off mode (this function will not return; wakeup will cause a reset)                
                err_code = sd_power_system_off();
                APP_ERROR_CHECK(err_code);
            }
            break;

        default:
            // No implementation needed.
            break;
    }
}

2>.协议栈连接参数及服务事件。
这里感觉和前面有一部重复???同时和完全用户自定义的ble_lbs_on_ble_evt事件处理也有一致的地方。ble_lbs_on_ble_evt在后续应用中再补充。

void ble_conn_params_on_ble_evt(ble_evt_t * p_ble_evt)
{
    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            on_connect(p_ble_evt);
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            on_disconnect(p_ble_evt);
            break;

        case BLE_GATTS_EVT_WRITE:
            on_write(p_ble_evt);
            break;

        case BLE_GAP_EVT_CONN_PARAM_UPDATE:
            on_conn_params_update(p_ble_evt);
            break;

        default:
           break;
    }
}
static void on_connect(ble_evt_t * p_ble_evt)
{
    // 保存连接参数
    m_conn_handle         = p_ble_evt->evt.gap_evt.conn_handle;
    m_current_conn_params = p_ble_evt->evt.gap_evt.params.connected.conn_params;
    m_update_count        = 0;  
    //检查是否处理连接协商(初始化conn_params_init后默认为BLE_GATT_HANDLE_INVALID)
    if (m_conn_params_config.start_on_notify_cccd_handle == BLE_GATT_HANDLE_INVALID)
    {
        conn_params_negotiation();
    }
}


static void on_disconnect(ble_evt_t * p_ble_evt)
{
    uint32_t err_code;
    m_conn_handle = BLE_CONN_HANDLE_INVALID;

    m_update_count = 0; // 连接参数更新需要发生在每一个连接上
    err_code = app_timer_stop(m_conn_params_timer_id); //停止定时器
    if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
    {
        m_conn_params_config.error_handler(err_code); //错误处理
    }
}


static void on_write(ble_evt_t * p_ble_evt)
{
    ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;

    if ( // 检查cccd(描述符)是否正确
        (p_evt_write->handle == m_conn_params_config.start_on_notify_cccd_handle)
        && (p_evt_write->len == 2)
    )
    {
        // 检查是否是'start notification
        if (ble_srv_is_notification_enabled(p_evt_write->data))
        {
            conn_params_negotiation(); //如果必要进行连接参数negotiation
        }
        else
        {
            uint32_t err_code;
            err_code = app_timer_stop(m_conn_params_timer_id);    // 终止定时器
            if ((err_code != NRF_SUCCESS) && 
                 (m_conn_params_config.error_handler != NULL))
            {
                m_conn_params_config.error_handler(err_code);
            }
        }
    }
}


static void on_conn_params_update(ble_evt_t * p_ble_evt)
{
     //拷贝参数
    m_current_conn_params = p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params;
    conn_params_negotiation();
}

中间大部分函数逻辑都很简单。中间有个函数conn_params_negotiation。这个函数是对比当前连接参数m_current_conn_params的最大连接间隔时间是否在参考连接参数m_preferred_conn_params的最大和最小间隔时间内,在范围内通知成功,否则通知失败。并执行m_conn_params_config函数。这里具体的参数连接后面接着说。

1.3.4.系统事件调度(sys_evt_dispatch)

系统事件的调度函数里面调用了pstorage_sys_event_handler函数,该函数用来处理Flash访问结果事件放在 pstorage_platform.h文件中。这部分需要初始化pstorage_init,整个工程中未调用,因此这部分程序不处理if (m_cmd_queue.flash_access == true不成立)。如果后面有这部分的再回来解释。

1.4.连接参数

1.4.1.连接参数初始化

这部分是关于连接参数模块的初始化。这部分结构体定义如下:

typedef struct
{
    ble_gap_conn_params_t *       p_conn_params;    /**< 指向应用程序所需的连接参数的指针。当调用ble_conn_params_init,如果这个参数被设置为null,连接参数将从主机中获得。 */
    uint32_t                      first_conn_params_update_delay;   /**<表示从发起事件 (连接或启动通知) 到第一次sd_ble_gap_conn_param_update被调用的时间(定时器ticks的值). */
    uint32_t                      next_conn_params_update_delay;   /**< 在每次调用sd_ble_gap_conn_param_update后的第一次时间(在定时器滴答数)。按蓝牙规范4版推荐值30秒。 */
    uint8_t                       max_conn_params_update_count; /**< 连接失败前最大的尝试次数 */
    uint16_t                      start_on_notify_cccd_handle;  /**< 如果程序要用来开始通知事件时,这个设置相应的CCCD句柄。 如果程序要开始连接事件,则设置为BLE_GATT_HANDLE_INVALID*/
    bool                          disconnect_on_fail;  /**< 如果连接参数更新失败导致自动断开,则设置为true,否则设置为false。 */
    ble_conn_params_evt_handler_t evt_handler;    /**< 调用事件处理程序来处理连接参数中的事件。*/
    ble_srv_error_handler_t       error_handler;  /**< 出错处理句柄 */
} ble_conn_params_init_t;

下面是初始化过程,在调用ble_conn_params_init初始化

static void conn_params_init(void)
{
    uint32_t               err_code;
    ble_conn_params_init_t cp_init;

    memset(&cp_init, 0, sizeof(cp_init));

    cp_init.p_conn_params                  = NULL;
    cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
    cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
    cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
    cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
    cp_init.disconnect_on_fail             = false;
    cp_init.evt_handler                    = on_conn_params_evt;
    cp_init.error_handler                  = conn_params_error_handler;

    err_code = ble_conn_params_init(&cp_init);
    APP_ERROR_CHECK(err_code);
}

uint32_t ble_conn_params_init(const ble_conn_params_init_t * p_init)
{
    uint32_t err_code;
    m_conn_params_config = *p_init;
    m_change_param = false;
    if (p_init->p_conn_params != NULL)
    {
        m_preferred_conn_params = *p_init->p_conn_params;
        //设置协议栈上的连接参数
        err_code = sd_ble_gap_ppcp_set(&m_preferred_conn_params);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    }
    else
    {
        // 从协议栈中获得连接参数
        err_code = sd_ble_gap_ppcp_get(&m_preferred_conn_params);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    }
    m_conn_handle  = BLE_CONN_HANDLE_INVALID;
    m_update_count = 0;

    return app_timer_create(&m_conn_params_timer_id,
                            APP_TIMER_MODE_SINGLE_SHOT,
                            update_timeout_handler);
}

因为前面定义的p_conn_params为NULL,因此这里从协议栈中读取数据。此外这里开启了一个定时器来处理连接超时,若定时器到时之后会回调update_timeout_handler函数。

static void update_timeout_handler(void * p_context)
{
    UNUSED_PARAMETER(p_context);
    if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
    {
        // 检测是否到达最大尝试次数
        m_update_count++;
        if (m_update_count <= m_conn_params_config.max_conn_params_update_count)
        {
            uint32_t err_code;
            // 参数不正确, 发送连接更新请求
            err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_preferred_conn_params);
            if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
            {
                m_conn_params_config.error_handler(err_code);
            }
        }
        else
        {
            m_update_count = 0;
            // 连接失败,如果没有被配置,则自动断开
            if (m_conn_params_config.disconnect_on_fail)
            {
                uint32_t err_code;

                err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
                if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
                {
                    m_conn_params_config.error_handler(err_code);
                }
            }

            // 通知应用连接失败
            if (m_conn_params_config.evt_handler != NULL)
            {
                ble_conn_params_evt_t evt;

                evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
                m_conn_params_config.evt_handler(&evt);
            }
        }
    }
}

此外前面初始化的时候绑定了一个回调函数on_conn_params_evt来处理连接参数中的事件。该函数处理连接参数失败时间,则会断开连接。

static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
{
    uint32_t err_code;

    if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
    {
        err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
        APP_ERROR_CHECK(err_code);
    }
}

1.4.2.

前面的系统调度中很多事件处理的过程都调用了这个函数。该函数用来判断连接是否成功,不成功再次启动定时器,成功则通知应用。

static void conn_params_negotiation(void)
{
    if (!is_conn_params_ok(&m_current_conn_params)) 
    {
        uint32_t err_code;
        uint32_t timeout_ticks;  
        if (m_change_param)
        {
            if (m_conn_params_config.evt_handler != NULL) // 通知应用过程失败
            {
                ble_conn_params_evt_t evt;
                evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
                m_conn_params_config.evt_handler(&evt);
            }
        }
        else
        {//m_change_param == NULL
            if (m_update_count == 0)
            {
                // 第一个连接更新
                timeout_ticks = m_conn_params_config.first_conn_params_update_delay;
            }
            else
            {
                timeout_ticks = m_conn_params_config.next_conn_params_update_delay;
            }

            err_code = app_timer_start(m_conn_params_timer_id, timeout_ticks, NULL);
            if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
            {
                m_conn_params_config.error_handler(err_code);
            }
        }
    }
    else
    {
        // 通知应用过程成功执行
        if (m_conn_params_config.evt_handler != NULL)
        {
            ble_conn_params_evt_t evt;           
            evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED;
            m_conn_params_config.evt_handler(&evt);
        }
    }
    m_change_param = false;
}

1.5.GAP及安全参数

gap部分程序涉及到的比较少,只有一段初始化。
大概意思是设定一下安全模式,设置为(1,1),绑定一下蓝牙的名字,配置并设置一下gap参数。代码如下:

static void gap_params_init(void)
{
    uint32_t                err_code;
    ble_gap_conn_params_t   gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);

    err_code = sd_ble_gap_device_name_set(&sec_mode,
                                          (const uint8_t *)DEVICE_NAME,
                                          strlen(DEVICE_NAME));
    APP_ERROR_CHECK(err_code);

    memset(&gap_conn_params, 0, sizeof(gap_conn_params));

    gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
    gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
    gap_conn_params.slave_latency     = SLAVE_LATENCY;
    gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;

    err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    APP_ERROR_CHECK(err_code);
}

安全参数初始化部分的密码也就是赋值一下m_sec_params结构体。

static void sec_params_init(void)
{
    m_sec_params.timeout      = SEC_PARAM_TIMEOUT;
    m_sec_params.bond         = SEC_PARAM_BOND;
    m_sec_params.mitm         = SEC_PARAM_MITM;
    m_sec_params.io_caps      = SEC_PARAM_IO_CAPABILITIES;
    m_sec_params.oob          = SEC_PARAM_OOB;
    m_sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
    m_sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值