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

ANCS Code base (bonding) with NUS and strange behaviour with nRF Toolbox

Hello the Nordic Team,

I come here after a lot of research and testing and do not understand what is going on in my program. (is it Embedded or iPhone nRF Toolbox side ?)

I took the ANCS code ( nRF5_SDK_12.2.0_f012efa > ble_app_ancs_c ) as a base code and I mixed the code of the "ble_app_uart" with it and to make it very simple I wrote a small function that sends messages by pressing Simply on the button 0,1,2 or 3 of my nRF52 Development Kit.

void sendMessageWithNus(char message[]) {

    if (m_cur_conn_handle != BLE_CONN_HANDLE_INVALID) {
        ret_code_t err_code;
        err_code = ble_nus_string_send(&m_nus, message, strlen((char*)message));
        APP_ERROR_CHECK(err_code);
            
        blink_led(1, true);            
    } else {
        NRF_LOG_INFO("/!\ No connection to peripheral! Can't send message with NUS! \r\n");
    }
}

The way :

I run the nRF Toolbox application from my iPhone. I connect to my board. I click on the Button 0 of my Board to send me a message:

The LED 0 of my Board flashes quickly and I get my message well in the NORLogger. No problem !

I have an internal timer which means that if I do nothing for 10 seconds my board goes into standby.

void goto_sleep() {

    NRF_LOG_INFO("----------> goto_sleep() \r\n");
    
    device_disconnect();
    nrf_delay_ms(1000);
    sleep_mode_enter();
}

I press on a button my board turns on again ... and I see in the Settings iOS >> Bluetooth >> the Bonding is good ( the blue ( i ) is present ).

I understand that in nRF Toolbox there is a re-connection that is done in a transparent way because if I send messages to my board from the NORLogger I receive them well too (I put listening with NRF_LOG_INFO ("...");) on the messages coming from the iPhone to the Board.

Now I press on the Button 0 of my Board .. The LED 0 blinks well for 1 second then goes off .. But no message arrives on the NORLogger of the iPhone !

And doing this several times it does exactly the same behavior!

————

By doing the same thing on Android. Although, in this case, the bonding is explicitly reserved to the iPhone. The Android does not ask me for an explicit message to accept the Pairing of my Bluetooth device.

I run the nRF Toolbox application from my Android. I connect to my Board.

I click on the Button 0 of my Board to send me a message: The LED 0 of my Board flashes quickly and I get my message well in the NORLogger. No problem !

The Board goes into standby. I turn it back on. Proceed in the same way. (2)

The LED 0 of my Board flashes quickly and I get my message in the NORLogger. No problem !

On the other hand I re-disconnects another time (3) .. and re-attempts to send me a message and that does not work anymore ..

Do you have any idea where that might come from?

Is it Embedded or iPhone nRF Toolbox side ?

————

Here is my code:

Simplified of every things else ; contain only my Mix of ANCS Base + NUS from nRF5_SDK_12.2.0_f012efa example:

ble_app_ancs_c.zip

Thanks a lot for your support :)

————

Also, something as strange as it say before, happens to me!

Is that if I connect on Board from an iPhone X and successfully accept the pairing bonding and I disconnect, unplug and plug the power from the board,

And try to connect to that board with an iPhone Y with nRF Toolbox. The button label remains "Cancel" and I do not receive the iPhone PopUp of acceptance of the bonding / pairing .. and the final connection is never made!

On the other hand if I erase my board with:

Make erase; Make flash_softdevice; Make flash;

I can connect with iPhone Y but event after disconnect and forget that Board, I could no longer connect after with the iPhone X without erasing Board again ..

An idea ?

Thanks a lot for your support :)

Parents
  • I suspect that this check is failing on reconnection:

    if ((p_nus->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_nus->is_notification_enabled))
    {
        return NRF_ERROR_INVALID_STATE;
    }
    

    Because is_notification_enabled is only set to true when the CCCD is written to true by the client:

        if (ble_srv_is_notification_enabled(p_evt_write->data))
        {
            p_nus->is_notification_enabled = true;
        }
    

    But since you are bonded, the client will not write to the CCCD, it will expect you to have saved its state from the last connection.

    You can try to remove the check, or set is_notification_enabled to true somehow, for example when you get the PM_EVT_LOCAL_DB_CACHE_APPLIED event.

Reply
  • I suspect that this check is failing on reconnection:

    if ((p_nus->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_nus->is_notification_enabled))
    {
        return NRF_ERROR_INVALID_STATE;
    }
    

    Because is_notification_enabled is only set to true when the CCCD is written to true by the client:

        if (ble_srv_is_notification_enabled(p_evt_write->data))
        {
            p_nus->is_notification_enabled = true;
        }
    

    But since you are bonded, the client will not write to the CCCD, it will expect you to have saved its state from the last connection.

    You can try to remove the check, or set is_notification_enabled to true somehow, for example when you get the PM_EVT_LOCAL_DB_CACHE_APPLIED event.

Children
  • Hi Petter,

    Thanks for your response,

    I tried to do as you advised, but it does not work at the "re-connection" after a standby of the board and a wake up. The ANCS is well re-connected and in my settings iOS the device connects well, but from the application nRF Toolbox, the last message I received in my log of the application:

    [35] 12: 26: 27.453 | Network | Thread 8 | Error Code: The connection has timed out unexpectedly.
    

    I can always send messages to my board via nRF Toolbox; If I send the command: >LED, the corresponding LED lights up ... but not returning from the Board to the iPhone, when sending a command provided for this purpose.

    Here is what I have changed in the file: ble_nus.c

    /**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the S110 SoftDevice.
     *
     * @param[in] p_nus     Nordic UART Service structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static void on_write(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
    {
        ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    
        **p_nus->is_notification_enabled = true;**
        
        if (
            (p_evt_write->handle == p_nus->rx_handles.cccd_handle)
            &&
            (p_evt_write->len == 2)
           )
        {
            if (ble_srv_is_notification_enabled(p_evt_write->data))
            {
                **p_nus->is_notification_enabled = true;**
            }
            else
            {
    **//            p_nus->is_notification_enabled = false;**
            }
        }
        else if (
                 (p_evt_write->handle == p_nus->tx_handles.value_handle)
                 &&
                 (p_nus->data_handler != NULL)
                )
        {
            p_nus->data_handler(p_nus, p_evt_write->data, p_evt_write->len);
        }
        else
        {
            // Do Nothing. This event is not relevant for this service.
        }
    }
    

    and:

    uint32_t ble_nus_init(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
    {
        uint32_t      err_code;
        ble_uuid_t    ble_uuid;
        ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
    
        VERIFY_PARAM_NOT_NULL(p_nus);
        VERIFY_PARAM_NOT_NULL(p_nus_init);
    
        // Initialize the service structure.
        p_nus->conn_handle             = BLE_CONN_HANDLE_INVALID;
        p_nus->data_handler            = p_nus_init->data_handler;
        **p_nus->is_notification_enabled = true;**
    

    and:

    uint32_t ble_nus_string_send(ble_nus_t * p_nus, uint8_t * p_string, uint16_t length)
    {
        ble_gatts_hvx_params_t hvx_params;
    
        VERIFY_PARAM_NOT_NULL(p_nus);
    
    **//    if ((p_nus->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_nus->is_notification_enabled))
    //    {
    //        return NRF_ERROR_INVALID_STATE;
    //    }**
    
        if (length > BLE_NUS_MAX_DATA_LEN)
        {
            return NRF_ERROR_INVALID_PARAM;
        }
    

    Thank you again, for trying to get me out of this shadow I try to do, in my opinion, something simple.

Related