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

Problem when trying to send multiple data packets as notifications

Dear All,

I am trying to send a bunch of data over BLE, using the notifications of a characteristic of a service. The size of the package data that I am trying to send is 16 bytes.

The way I try to do this at the moment is that once the user enables the notifications and I receive the NOTIFICATION_ENABLED in the service handler, I am reading the data that I need to transmit from the flash storage of the device, I split them in packets of 16 bytes each and then I call the send function. You can see what I am trying to do on the code snippets below:

/** This function recovers and transmits the data over BLE.
* It is called in the service handler onnce the central device enables notifications.
*/
static void transmit_data(void)
{
    NRF_LOG_INFO("Start transmiting data");
    uint8_t retrieve_data_buf[1600] = { 0 };
    int32_t bytes_to_be_sent = retrieve_data_history((uint8_t*)&retrieve_data_buf, sizeof(retrieve_data_buf));
    if (bytes_to_be_sent > 0) {
        uint32_t packets_to_be_sent = bytes_to_be_sent / PACKET_SIZE;
        if (bytes_to_be_sent % PACKET_SIZE) {
            packets_to_be_sent++;
        }
        NRF_LOG_INFO("Packets to be sent: %u", packets_to_be_sent);
        uint32_t err_code;
        for (uint32_t i = 0; i < packets_to_be_sent;) {
            wdt_feed();
            err_code = ble_shs_data_send(&m_shs, &retrieve_data_buf[i * SHOWER_PACKET_SIZE]);
            if (err_code == NRF_ERROR_RESOURCES) {
                do {
                    err_code = ble_shs_data_send(&m_shs, &retrieve_data_buf[i * SHOWER_PACKET_SIZE]);
                    wdt_feed();
                    idle_state_handle();
                } while (err_code != NRF_SUCCESS);
            }
            i++;
        }
    }
    else {
        NRF_LOG_INFO("No data to be sent");
    }
}


The next snippet belongs to my service and it is used to effectively notify the device for the new data:

uint32_t ble_shs_data_send(ble_shs_t* p_shs, uint8_t* history_buffer)
{
    if (p_shs == NULL) {
        return NRF_ERROR_NULL;
    }

    uint32_t err_code = NRF_SUCCESS;
    ble_gatts_value_t gatts_value;

    // Initialize value struct.
    memset(&gatts_value, 0, sizeof(gatts_value));

    gatts_value.len = PACKET_SIZE;
    gatts_value.offset = 0;
    gatts_value.p_value = history_buffer;

    // Update database.
    err_code = sd_ble_gatts_value_set(p_shs->conn_handle,
                                      p_shs->data_value_handles.value_handle,
                                      &gatts_value);
    if (err_code != NRF_SUCCESS) {
        return err_code;
    }

    // Send value if connected and notifying.
    if ((p_shs->conn_handle != BLE_CONN_HANDLE_INVALID)) {
        ble_gatts_hvx_params_t hvx_params;

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

        hvx_params.handle = p_shs->data_handles.value_handle;
        hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
        hvx_params.offset = gatts_value.offset;
        hvx_params.p_len = &gatts_value.len;
        hvx_params.p_data = gatts_value.p_value;

        err_code = sd_ble_gatts_hvx(p_shs->conn_handle, &hvx_params);
    }

    return err_code;
}


What I have seen is that in this way the device will transmit some packets (between 3 and 5) and then it will get stuck.

My service has a priority level set to 2.

What I also tried is instead of calling for the ble_shs_data_send and expect to return with NRF_SUCCESS , after the first failure, to use a bool and when, the ble_shs_data_send wait until the BLE_GATTS_EVT_HVN_TX_COMPLETE occurs and then try to send again a package. Weirdly, I never see this event being triggered.

Any ideas?

Parents
  • The approach looks good to me.

    Do you run your code in the interrupt context after receiving the NOTIFICATION_ENABLED? If yes, my guess is that softdevice cannot give another interrupt once the 3-5 packets are sent. In that case, you should move the code to transmit data into a function that's run inside scheduler or do some other mechanism to run the transmission out of interrupt context.

Reply
  • The approach looks good to me.

    Do you run your code in the interrupt context after receiving the NOTIFICATION_ENABLED? If yes, my guess is that softdevice cannot give another interrupt once the 3-5 packets are sent. In that case, you should move the code to transmit data into a function that's run inside scheduler or do some other mechanism to run the transmission out of interrupt context.

Children
Related