Hi,
In short, my problem is that my code works when I execute it inside one event handler, but doesn't work inside another event handler, and I don't understand why it fails to succeed.
This is what I want to do: I have a central and a peripheral (both are nrf52840's with SD s140, and SDK 17.0.2) and I want the peripheral to send a large amount of data to the central. I want the data sending to happen automatically, after the devices have negotiated the following parameters:
- 7.5 ms connection interval
- DLE extension and 247 byte MTU
- 2 M PHY
I have taken the ble_app_uart example as my project base. First, I modified the example's uart_event_handle() so that when my peripheral receives an "a", a uint8_t array with length 244 is generated and sent by the function ble_nus_data_send(). Actually, to simulate a large amount of data, I send the same array 1000 times from within a loop like so:
if (command == 'a') { uint8_t byte_array[244]; length = 244; generate_array(byte_array, length); } for (int i=0; i<1000; i++){ do { err_code = ble_nus_data_send(&m_nus, byte_array, &length, 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); }
The above code works fine, I guess, since the central gets all the packets. Whenever the err_code becomes NRF_ERROR_RESOURCES, the while loop tries to execute the message sending, until the resources get freed up. So far so good.
However, now I want to eliminate the keyboard interaction. I want the peripheral to start sending the messages as soon as the aforementioned connection parameters have been negotiated. Therefore, I place the same code in the ble_evt_handler() function, in the BLE_GAP_EVT_CONN_PARAM_UPDATE event, like so:
case BLE_GAP_EVT_CONN_PARAM_UPDATE: NRF_LOG_INFO("Conn params updated"); NRF_LOG_INFO("updated:min_conn_interval: %i*1.25 ms", p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.min_conn_interval); NRF_LOG_INFO("updated:max_conn_interval: %i*1.25 ms", p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params.max_conn_interval); ble_gap_conn_params_t conn_interval = p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params; if (conn_interval.max_conn_interval == MAX_CONN_INTERVAL) { uint16_t length = 244; //byte_array is already generated in main for (int i=0; i<1000; i++) { do { err_code = ble_nus_data_send(&m_nus, byte_array, &length, 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;
What happens during execution is that the ble_nus_data_send() function starts sending the messages when the 7.5 ms connection interval has been negotiated, but after the 3rd message it returns NRF_ERROR_RESOURCES and the rest of the messages never get sent. However, the central and peripheral remain in connection, sending empty packets to each other, according to the nRF Sniffer:
Please help me understand what's wrong with the code! Thanks!