BLE Notification and Indications

在ATT层协议框架内,拥有一组属性的设备称为服务端(Server),读写该属性值的设备称为客户端(Client),Server和Client通过ATT PDU进行交互。属性协议共有6种:


主机RX 从机TX 方向:

 通知:从机端上传数据给主机,不需要主机回复一个响应

 指示:从机端上传数据给主机,需要主机端发一个确认给服务器

通知和指示之间不同之处在于指示有应用层上的确认,而通知没有。


 写

 没有回应的写

 读

/*GATT Characteristic Properties. */

typedef struct

{

  /* Standard properties */

  uint8_t broadcast       :1; /**< Broadcasting of the value permitted. */

  uint8_t read            :1; /**< Reading the value permitted. */

  uint8_t write_wo_resp   :1; /**< Writing the value with Write Command permitted. */

  uint8_t write           :1; /**< Writing the value with Write Request permitted. */

  uint8_t notify          :1; /**< Notification of the value permitted. */

  uint8_t indicate        :1; /**< Indications of the value permitted. */

  uint8_t auth_signed_wr  :1; /**< Writing the value with Signed Write Command permitted. */

} ble_gatt_char_props_t;


Client Characteristic Configuration Descriptor(CCCD)是客户端特征配置描述符

当主机向CCCD中写入0x0001,此时使能notify;当写入0x0000时,此时禁止notify。


从机设备流程

1. 开启广播

2. 被主机成功连接,并交互连接参数

3. 等待主机获取服务

4. 等待主机成功使能notify功能

5. 从机给主机发送相应的notify数据包


初始化服务:

注册的服务句柄p_nus->service_handle。

使能了按键的notify通知属性 add_char_params.char_props.notify = 1;

uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)

{

    ble_uuid_t            ble_uuid;

    ble_uuid128_t         nus_base_uuid = NUS_BASE_UUID;

    ble_add_char_params_t add_char_params;


    // Initialize the service structure.

    p_nus->data_handler = p_nus_init->data_handler;

    // Add a custom base UUID.

    sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);


    ble_uuid.type = p_nus->uuid_type;

    ble_uuid.uuid = BLE_UUID_NUS_SERVICE;

    // Add the service.

    sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,&ble_uuid, &p_nus->service_handle);


    add_char_params.uuid                    = BLE_UUID_NUS_RX_CHARACTERISTIC;

add_char_params.uuid_type              = p_nus->uuid_type;

    add_char_params.max_len                = BLE_NUS_MAX_RX_CHAR_LEN;

add_char_params.init_len                = sizeof(uint8_t);

add_char_params.is_var_len              = true;

add_char_params.char_props.write        = 1; /**< */

add_char_params.char_props.write_wo_resp = 1; /**< */

#ifdef BOND_ENABLE

    add_char_params.read_access  = SEC_MITM;

    add_char_params.write_access  = SEC_MITM;

#else

    add_char_params.read_access  = SEC_OPEN;

    add_char_params.write_access  = SEC_OPEN;

#endif

    characteristic_add(p_nus->service_handle,&add_char_params,&p_nus->rx_handles);


    // Add the TX Characteristic.

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


    add_char_params.uuid              = BLE_UUID_NUS_TX_CHARACTERISTIC;

add_char_params.uuid_type        = p_nus->uuid_type;

add_char_params.max_len          = BLE_NUS_MAX_TX_CHAR_LEN;

add_char_params.init_len          = sizeof(uint8_t);

add_char_params.is_var_len        = true;

add_char_params.char_props.notify  = 1; /* 使能通知 */


#ifdef BOND_ENABLE

    add_char_params.read_access = SEC_MITM; /**< Access possible with 'MITM' security at least. */

    add_char_params.write_access      = SEC_MITM;

    add_char_params.cccd_write_access = SEC_MITM;

#else

    add_char_params.read_access        = SEC_OPEN; /**< Access open. */

    add_char_params.write_access      = SEC_OPEN;

    add_char_params.cccd_write_access  = SEC_OPEN;

#endif


    Return characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->tx_handles);

}


接收通知使能:

在BLE 事件处理的函数中,要处理 CCCD_Write 的数据,所以在由 softdevice 返回消息的 ble_nus_on_ble_evt 函数中,需要处理BLE_GATTS_EVT_WRITE 事件。

void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)

{

    ble_nus_t * p_nus = (ble_nus_t *)p_context;


    switch (p_ble_evt->header.evt_id)

    {

        case BLE_GAP_EVT_CONNECTED:

            on_connect(p_nus, p_ble_evt);

            break;

        case BLE_GATTS_EVT_WRITE:

            on_write(p_nus, p_ble_evt);

            break;

        case BLE_GATTS_EVT_HVN_TX_COMPLETE:

            on_hvx_tx_complete(p_nus, p_ble_evt);

            break;

        default:

            // No implementation needed.

            break;

    }

}

static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)

{

    ble_nus_evt_t               evt;

    ble_nus_client_context_t   * p_client;

    ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;


    blcm_link_ctx_get(p_nus->p_link_ctx_storage,

                            p_ble_evt->evt.gatts_evt.conn_handle,(void*)&p_client);


    evt.p_nus          = p_nus;

    evt.conn_handle  = p_ble_evt->evt.gatts_evt.conn_handle;

    evt.p_link_ctx      = p_client;


    /* check cccd_handle and data length, 0100 */

    if ((p_evt_write->handle == p_nus->tx_handles.cccd_handle) && (p_evt_write->len == 2))

    {

        if (p_client != NULL)

        {

            if (ble_srv_is_notification_enabled(p_evt_write->data))

            {

                p_client->is_notification_enabled = true;

                evt.type                      = BLE_NUS_EVT_COMM_STARTED;

            }

            else

            {

                p_client->is_notification_enabled = false;

                evt.type = BLE_NUS_EVT_COMM_STOPPED;

            }


            if (p_nus->data_handler != NULL)

            {

                p_nus->data_handler(&evt);

            }

        }

    }

    else if ((p_evt_write->handle == p_nus->rx_handles.value_handle) &&

             (p_nus->data_handler != NULL))

    {

        evt.type                  = BLE_NUS_EVT_RX_DATA;

        evt.params.rx_data.p_data  = p_evt_write->data;

        evt.params.rx_data.length    = p_evt_write->len;


        p_nus->data_handler(&evt);

    }

    else

    {

    }

}

static void on_hvx_tx_complete(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)

{

    ble_nus_evt_t           evt;

    ble_nus_client_context_t * p_client;


    blcm_link_ctx_get(p_nus->p_link_ctx_storage,

                     p_ble_evt->evt.gatts_evt.conn_handle, (void *) &p_client);


    if (p_client->is_notification_enabled)

    {

        memset(&evt, 0, sizeof(ble_nus_evt_t));

        evt.type        = BLE_NUS_EVT_TX_RDY;

        evt.p_nus        = p_nus;

        evt.conn_handle  = p_ble_evt->evt.gatts_evt.conn_handle;

        evt.p_link_ctx    = p_client;

        p_nus->data_handler(&evt);

    }

}


从机发送notify数据:

uint32_t ble_nus_data_send(ble_nus_t * p_nus,

uint8_t * p_data, 

uint16_t * p_length,

uint16_t conn_handle)

{

    ble_gatts_hvx_params_t     hvx_params;

    ble_nus_client_context_t   * p_client;


    blcm_link_ctx_get(p_nus->p_link_ctx_storage, conn_handle, (void *) &p_client);


    hvx_params.handle = p_nus->tx_handles.value_handle;

    hvx_params.p_data = p_data;

    hvx_params.p_len  = p_length;

    hvx_params.type   = BLE_GATT_HVX_NOTIFICATION; /* notify 属性的数据 */


    return sd_ble_gatts_hvx(conn_handle, &hvx_params);

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容