jj1989 发表于 2018-12-16 14:34

【nRF52840 DK测评】完善自定义服务-发送数据

<div class='showpostmsg'>## 前言
上一篇文章简单介绍了如何添加自定义的BLE服务,结合官方demo,我想你应该会有更深刻的理解。这里的UUID为128位,你可以尝试将其改为16位,看看会有什么变化。接下来,我们将继续完善自定义的服务,最终实现的功能是按下开发板(从机)的按键,开发板通过蓝牙发送数据给手机(主机)。

----
## 完善代码
首先需要添加发送数据功能。如下
```c
uint32_t ble_key_state_data_send(ble_key_state_t * p_key_state,
                           uint8_t   * p_data,
                           uint16_t* p_length,
                           uint16_t    conn_handle)
{
    ret_code_t               err_code;
    ble_gatts_hvx_params_t   hvx_params;
    ble_key_state_client_context_t * p_client;

    VERIFY_PARAM_NOT_NULL(p_key_state);

    err_code = blcm_link_ctx_get(p_key_state->p_link_ctx_storage, conn_handle, (void *) &p_client);
    VERIFY_SUCCESS(err_code);

    if ((conn_handle == BLE_CONN_HANDLE_INVALID) || (p_client == NULL))
    {
      return NRF_ERROR_NOT_FOUND;
    }

    if (!p_client->is_notification_enabled)
    {
      return NRF_ERROR_INVALID_STATE;
    }

    if (*p_length > BLE_KEY_STATE_MAX_DATA_LEN)
    {
      return NRF_ERROR_INVALID_PARAM;
    }

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

    hvx_params.handle = p_key_state->tx_handles.value_handle;
    hvx_params.p_data = p_data;
    hvx_params.p_len= p_length;
    hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;

    return sd_ble_gatts_hvx(conn_handle, &hvx_params);
}
```
注意这里首先要判断是否有连接,然后判断是否使能了notify,否则服务器(从机)不知道将数据发往哪里。
然后在*bsp_event_handler*函数中,添加按键对应的操作,如下代码:
```c
static void bsp_event_handler(bsp_event_t event)
{
    ret_code_t err_code;
    static uint8_t key1_state=0x00;
    uint16_t len = 1;
    switch (event)
    {
      case BSP_EVENT_KEY_0:
            do{
                key1_state = 0x01;
                err_code = ble_key_state_data_send(&m_key_state,&key1_state,&len,m_conn_handle);
                if ((err_code != NRF_ERROR_INVALID_STATE) &&
                  (err_code != NRF_ERROR_RESOURCES) &&
                  (err_code != NRF_ERROR_NOT_FOUND))
                  {
                        APP_ERROR_CHECK(err_code);
                  }
            } while (err_code == NRF_ERROR_RESOURCES);
      break;
      ......
      ......
    }
}
```
这里BSP_EVENT_KEY_0对应开发板上的Button1,当Button1按下时,将调用*ble_key_state_data_send*函数,发送数据*0x01*,长度为1个字节。

## 调试
编译、烧录并运行,LED1开始闪烁,表明程序运行正常。打开lightblue,连接开发板,使能notify。如下图:

图1
此时按下Button1,手机立即收到了0x01,与期望的一致。但是过一会儿,手机显示断开连接。如下图:

图2
再看一下开发板,LED1仍然常亮,代码似乎卡住了。
检查一下代码,未发现异常,log中也未显示异常,看来只能跟踪调试一下。这里使用SES调试,重复之前的操作,发现程序跑飞了。在发送数据的代码处打断点,最终发现在*on_hvx_tx_complete*函数的最后一行,会调用*p_key_state->data_handler(&evt)*;而在*services_init()*函数中,data_handler被初始化成了NULL。由于这里发送完数据后,不需要执行其它操作,所以初始化的时候设置为了NULL。解决这个问题最简单的方法是注释掉这段代码,不进行回调。或者是在初始化的时候,给data_handler分配一个有效的回调函数地址。
再次编译、烧录并运行,按下按键,数据发送成功,再次按下按键,手机再次收到数据,如下图:

图3

----
## 总结
通过本篇和上一篇文章的介绍,我们完成了一个自定义BLE服务的添加,并实现了从机往主机的数据发送。在此基础上,你可以尝试实现主机往从机的数据发送,具体实现可参考SDK中的ble_app_uart例程。下一篇文章将带大家了解一下BLE Mesh。

此内容由EEWORLD论坛网友jj1989原创,如需转载或用于商业用途需征得作者同意并注明出处

</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

star_66666 发表于 2018-12-16 14:46

积累学习一下下了

懒猫爱飞 发表于 2019-1-7 13:52

挺好的,谢谢分享!期待你的大作 !有问题在论坛讨论!
页: [1]
查看完整版本: 【nRF52840 DK测评】完善自定义服务-发送数据