创建自定义GATT服务

本文介绍如何添加一个自定义的GATT 服务。

(1)BLE工程框架

打开工程模板<SDK Dir>\14.2.0\examples\ble_peripheral\ble_app_template。

按F7编译一下,同时下载到开发板中,确保工程能够正常运行。

(2)添加YQS

复制以下两个文件:

  • <SDK Dir>\14.2.0\components\ble\ble_services\ble_nus\ble_nus.c
  • <SDK Dir>\14.2.0\components\ble\ble_services\ble_nus\ble_nus.h

粘贴到ble_app_template目录下,放在main.c的同级目录。

将该目录的相对路径(../../../)添加到工程的User Include Directory中,如下:

假设服务的全名是“Youqun Service”,将文件重命名:

  • ble_yqs.c
  • ble_yqs.h

在工程目录中新建一个目录nRF_BLE_Services,并将两个文件拖放到其中,如下图:

(3)移植YQS

打开ble_yqs.c,做全局替换,注意区分大小写:

  • NUS –> YQS
  • nus –> yqs

对ble_yqs.h做同样操作。

为了区分YQS和NUS两个服务,将YQS_BASE_UUID第一字节减一,即0x9E改成0x9D,如下:

{{0x9D, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}}

打开sdk_config.h,在BLE_TPS_ENABLED下方增加一个项目,如下:

// <q> BLE_TPS_ENABLED  - ble_tps - TX Power Service
#ifndef BLE_TPS_ENABLED
#define BLE_TPS_ENABLED 0
#endif

// <q> BLE_YQS_ENABLED  - ble_yqs - Youqun Service
#ifndef BLE_YQS_ENABLED
#define BLE_YQS_ENABLED 1
#endif

在BLE_TPS_BLE_OBSERVER_PRIO下方添加一个项目如下:

// <o> BLE_TPS_BLE_OBSERVER_PRIO  
// <i> Priority with which BLE events are dispatched to the TX Power Service.
#ifndef BLE_TPS_BLE_OBSERVER_PRIO
#define BLE_TPS_BLE_OBSERVER_PRIO 2
#endif

// <o> BLE_YQS_BLE_OBSERVER_PRIO  
// <i> Priority with which BLE events are dispatched to the Youqun Service.
#ifndef BLE_YQS_BLE_OBSERVER_PRIO
#define BLE_YQS_BLE_OBSERVER_PRIO 2
#endif 

找到NRF_SDH_BLE_VS_UUID_COUNT,将其值设为1,如下:

// <o> NRF_SDH_BLE_VS_UUID_COUNT - The number of vendor-specific UUIDs. 
#ifndef NRF_SDH_BLE_VS_UUID_COUNT
#define NRF_SDH_BLE_VS_UUID_COUNT 1
#endif

编译一下,此时可以通过编译,说明yqs服务文件移植成功。

(4)调用YQS

打开main.c,添加头文件引用:

#include "ble_yqs.h"

添加服务声明的宏BLE_YQS_DEF(m_yqs)

#define DEAD_BEEF                       0xDEADBEEF

BLE_YQS_DEF(m_yqs);
NRF_BLE_GATT_DEF(m_gatt); 
BLE_ADVERTISING_DEF(m_advertising);

填充services_init函数如下:

static void services_init(void)
{
    uint32_t       err_code;
    ble_yqs_init_t yqs_init;

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

    yqs_init.data_handler = yqs_data_handler;

    err_code = ble_yqs_init(&m_yqs, &yqs_init);
    APP_ERROR_CHECK(err_code);
}

添加事件回调函数(根据nus工程对应的函数进行移植),如下:

static void yqs_data_handler(ble_yqs_evt_t * p_evt)
{
    switch (p_evt->type) 
    {
        case BLE_YQS_EVT_RX_DATA:
        {
            NRF_LOG_INFO("Received data from BLE MYS:");
            NRF_LOG_HEXDUMP_INFO(p_evt->params.rx_data.p_data, p_evt->params.rx_data.length);
            
        } break;

        case BLE_YQS_EVT_COMM_STARTED:
        {
            NRF_LOG_INFO("Notification is enabled.");
        } break;
        
        case BLE_YQS_EVT_COMM_STOPPED:
        {
            NRF_LOG_INFO("Notification is disabled.");
        } break;

        default:
        break;
    }
}

此时编译不报错,但是无法运行,因为自定义服务增加了协议栈的内存占用,导致内存问题。

(5)调整内存

编译下载程序到开发板中,打开串口,查看报错信息,如下:

<warning> nrf_sdh_ble: RAM starts at 0x200020E0, can be adjusted to 0x200020F0.
<warning> nrf_sdh_ble: RAM size can be adjusted to 0xDF10.
<error> nrf_sdh_ble: sd_ble_enable() returned NRF_ERROR_NO_MEM.

按照错误提示,设置内存起始地址和大小,如下:

此时编译下载,即可正常运行。nRF Connect APP连接后的效果图为:

(6)重命名服务和特征

上图中YQS显示为Unknown Service,其特征也都是未知(Unknown Characteristic)。

在nrf connect APP界面,长按Unknown Service,可以对该服务重命名,我们重命名为Youqun Service。同样,将两个特征也重命名为:Device RX Char和Device TX Char。

最终效果如下:

(完)