This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

S132: Is it possible to send an empty notification

My previous product uses an empty notification to indicate that a bulk transfer is finished. I attempted to send an empty notification but got error code 0x10 (NRF_ERROR_INVALID_FLAGS).

Is there a way to send an empty notification?

ble_gatts_hvx_params_t hvx_param =
{
    .type   = BLE_GATT_HVX_NOTIFICATION,
    .handle = p_ctx->bulkdata_handle,
    .p_data = data,
    .p_len  = &len,
};
hvx_param.p_len = 0;
err_code = sd_ble_gatts_hvx(p_ctx->conn_handle, &hvx_param);

[Edit]

No empty packet sent when p_data = NULL and p_len = 0.

image description

Example of an empty notification packet being sent by TI CC2540.

image description

[Edit 2]

Alright. Added print on TX_COMPLETE.

Heres the log at the end of the transfer. Its hard to tell if one of these completes correlates to the empty notification.

BULKDATA:INFO:on_tx_complete: 503
BULKDATA:INFO:on_tx_complete: 504
APP:INFO:Sent 10 KBytes
BULKDATA:INFO:on_tx_complete: 505
BULKDATA:INFO:Sent empty packet, error code: 0x0
APP:INFO:Finished.
BULKDATA:INFO:on_tx_complete: 506
BULKDATA:INFO:on_tx_complete: 507
BULKDATA:INFO:on_tx_complete: 508
BULKDATA:INFO:on_tx_complete: 509
BULKDATA:INFO:on_tx_complete: 510
BULKDATA:INFO:on_tx_complete: 511
BULKDATA:INFO:on_tx_complete: 512
BULKDATA:INFO:on_tx_complete: 513

I rebuilt without sending the empty packet and there does appear to be one less "on_tx_complete" after the Finished printout.

BULKDATA:INFO:on_tx_complete: 503
BULKDATA:INFO:on_tx_complete: 504
APP:INFO:Sent 10 KBytes
BULKDATA:INFO:on_tx_complete: 505
APP:INFO:Finished.
BULKDATA:INFO:on_tx_complete: 506
BULKDATA:INFO:on_tx_complete: 507
BULKDATA:INFO:on_tx_complete: 508
BULKDATA:INFO:on_tx_complete: 509
BULKDATA:INFO:on_tx_complete: 510
BULKDATA:INFO:on_tx_complete: 511
BULKDATA:INFO:on_tx_complete: 512

Next I modified the code to send only empty notifications. This is where things get weird. It appears that each notification is 9 bytes of 0xFF. 9 bytes happens to be the initial length of the characteristic however the characteristic is initialized to all zeros.

Char init code, generated by BDS:

ble_app_app_generic_data_rcv_t app_generic_data_rcv_initial_value = p_app_init->ble_app_app_generic_data_rcv_initial_value; 

ble_add_char_params_t add_app_generic_data_rcv_params;
memset(&add_app_generic_data_rcv_params, 0, sizeof(add_app_generic_data_rcv_params));

add_app_generic_data_rcv_params.uuid                = 0xFF25;
add_app_generic_data_rcv_params.uuid_type           = ble_uuid.type; 
add_app_generic_data_rcv_params.max_len             = NRF_BLE_GATT_MAX_MTU_SIZE;
add_app_generic_data_rcv_params.init_len            = app_generic_data_rcv_encode(&app_generic_data_rcv_initial_value, app_generic_data_rcv_encoded_value);
add_app_generic_data_rcv_params.p_init_value        = app_generic_data_rcv_encoded_value; 
add_app_generic_data_rcv_params.is_value_user       = 1; 
add_app_generic_data_rcv_params.char_props.notify   = 1; 
add_app_generic_data_rcv_params.char_props.write    = 1; 
add_app_generic_data_rcv_params.write_access        = SEC_OPEN; 
add_app_generic_data_rcv_params.cccd_write_access   = SEC_OPEN;
// 1 for variable length and 0 for fixed length.
add_app_generic_data_rcv_params.is_var_len          = 1;

err_code = characteristic_add(p_app->service_handle, &add_app_generic_data_rcv_params, &(p_app->app_generic_data_rcv_handles));

How did you setup your characteristic?

  • Two comments:

    1. You have now one more tx_complete so I assume it went through. Are you sure you don't overlook it in RF sniffer trace?
    2. Your code sample have a bug from my point of view. hvx_param.p_len = 0; should be changed to something like uint16_t hvx_len = 0; hvx_params.p_len = &hvx_len;
    1. So yes thanks for pointing this out, I was able to confirm that when I send the empty notification I do receive one extra notification packet. However it is not empty.
    2. Yes I caught that when you posted your recent answer. Fixing this didn't seem to change anything though.
  • Well let's try to follow for little while. Can you show me more of that trace where you send 10kB in "full" ATT Notify packets and then there is one more "empty/non-empty" packet?

  • So it would appear that when I try to send an empty notification, it instead sends whatever is currently contained in the characteristic. So when I send only empty notifications, I receive 9 bytes of 0xFF because thats what I wrote to the start the transfer.

    When I send the count pattern, the last notification is the count that would have been sent next. So it appears that sd_ble_gatts_hvx() updates the characteristcs value even though a BLE_ERROR_NO_TX_PACKETS is returned.

    This leads me to the following code which does send empty notifications. Thanks to @endnote for all the help.

    uint32_t err_code = NRF_SUCCESS;
    uint16_t               hvx_len = 0;
    ble_gatts_hvx_params_t hvx_param_empty =
    {
        .type   = BLE_GATT_HVX_NOTIFICATION,
        .handle = p_ctx->bulkdata_handle,
        .p_data = NULL,
        .p_len  = &hvx_len,
    };
    
     // Set characteristic value to len zero so we can send an empty notification
     ble_gatts_value_t gatts_value;
     memset(&gatts_value, 0, sizeof(gatts_value));
     gatts_value.len = 0;
     err_code = sd_ble_gatts_value_set(p_ctx->conn_handle, p_ctx->bulkdata_handle, &gatts_value);
     APP_ERROR_CHECK(err_code);
    
     err_code = sd_ble_gatts_hvx(p_ctx->conn_handle, &hvx_param_empty);
     if (err_code != NRF_SUCCESS)
     {
         NRF_LOG_ERROR("sd_ble_gatts_hvx() failed: 0x%x\r\n", err_code);
     }
    
Related