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

Swift Pairing for custom gatt service

Hi,

I am using custom gatt service & I have included some of the code which supports swift pairing from ble_hid_mouse example. Here is my sniffer log -

mtu_log.pcapng

& the jlink rtt log -

paired - Copy.txt

For my application, the MTU size is 32 & data length is 36.

Windows keeps negotiating the size to be 512.

After I pair to the peripheral by connecting through the Windows bluetooth menu, it takes 1 minute to establish the ble connection & start data communication. If I dont pair, then the connection is quick. Now I know you will tell me the app has to make a connection. But I would also like to support manual pairing. Our device gets bricked if someone accidentally pairs with the device through Windows bluetooth menu. To avoid this I had to add the swift pairing support.

How do I expedite the connection on Windows for swift pairing? (note the same firmware without swift pairing feature works on Android OS perfectly fine with or without pairing.)

Parents
  • Hi

    Can you try adding a small delay in nrf_ble_gatt.c as shown below? This is supposed to avoid an LMP_RESPONSE_TIMEOUT, which your issue might be a variant of.

    static void on_connected_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
    
    {
    
    …
    
            nrf_delay_ms(100); // #include "nrf_delay.h"
    
            err_code = sd_ble_gattc_exchange_mtu_request(conn_handle, p_link->att_mtu_desired);
    
    …
    
    }

    Best regards,

    Simon

Reply
  • Hi

    Can you try adding a small delay in nrf_ble_gatt.c as shown below? This is supposed to avoid an LMP_RESPONSE_TIMEOUT, which your issue might be a variant of.

    static void on_connected_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
    
    {
    
    …
    
            nrf_delay_ms(100); // #include "nrf_delay.h"
    
            err_code = sd_ble_gattc_exchange_mtu_request(conn_handle, p_link->att_mtu_desired);
    
    …
    
    }

    Best regards,

    Simon

Children
  • Now it takes more than a minute to connect. Disappointed Behavior is still the same..

    Here are the logs - 

    1. Added delay along with the above 4 lines

    with_delay_and_4_lines.pcapng

    RTT_with_delay_and_4_lines.txt

    2. Added delay only

    with_delay.pcapng

    RTT_with_delay.txt

    In both cases, the peripheral connects to Windows OS but it takes more than a minute.

    I also tried increasing/decreasing the time in these 2 lines, but no luck

    opt.gap_opt.auth_payload_timeout.auth_payload_timeout = 3000;

    nrf_delay_ms(100);

  • Have you done any changes to peer_manager_handler.c or the modules it is using? I don't expect you have, but ask anyways.

    Have you set PM_HANDLER_SEC_DELAY_MS to anything beside 0?

    Can you confirm you are using S132v6.1.1?

    Are you somehow initiating security procedure on connected event manually by for instance calling pm_handler_secure_on_connection() in your application?

    From the log of "with_delay_and_4_lines.pcapng" I can see that the LL_LENGTH_REQ is sent from the peripheral after ~20ms. This means that the 100ms delay was not run, so I suggest to add the 100ms delay in the start of on_connected_evt(), e.g.:

    static void on_connected_evt(nrf_ble_gatt_t * p_gatt, ble_evt_t const * p_ble_evt)
    {
    nrf_delay_ms(100); // Place it in the start of function, #include "nrf_delay.h"
    …
    …
    }

    I assume the real problem here is the LL_PING_RSP that is always sent from the master without any preceding LL_PING_REQ. What details can you provide about the Windows 10 version you are using? https://en.wikipedia.org/wiki/Template:Windows_10_versions 

    Have you tried updating Windows 10 to the latest version? Are all BT drivers updated?

    Best regards,
    Kenneth

  • Hi Kenneth,

    Answers to your questions -

    I did not make any changes to peer_manager_handler.c.

    PM_HANDLER_SEC_DELAY_MS is set to 0 in sdk_config.h

    I'm using S132 from SDK16.0, dont know the version though.

    Security procedure is not initiated manually.

    Here are the new logs-

    https://www.dropbox.com/s/nyj104bcryw8cg4/log_4th_may.pcapng?dl=0

    https://www.dropbox.com/s/jlq7o3u5ei37t6r/rtt_log_4th_may.txt?dl=0


    The sniffer trace looks different. I think you are right about LL_PING_RSP.

    My Windows Specifications-

    & now I have updated to 

    Logs after updating -

    https://www.dropbox.com/s/suasjwkssatsqkt/log_after_update.pcapng?dl=0

    https://www.dropbox.com/s/yx0opw4vu4guvh7/rt_log_after_update.txt?dl=0

  • I think the main problem here is that the slave seem to always send a "Security Request: AuthReq: Bonding", which should not be necessary, since the link is already encrypted or in the process of being encrypted. I think that is what is causing the master to misbehave by sending a LL_PING_RSP later.

    If you open any of the other SDK examples as-is that support bonding, you will see that it is not sending a "Security Request: AuthReq: Bonding". So we need to try to find out what is causing this in your application.

    Can you provide the source for peer_manager_init(), sys_evt_dispatch(), ble_evt_dispatch(),  and pm_evt_handler()?

    Is it possible that you are deleting bonds here somewhere?

    *maybe check this first* Is it possible you are calling pm_conn_secure() somewhere?

    Can you provide your defines of FDS*/FSTORAGE* in sdk_config.h?

    What security level have you set for your various characteristics and services? For instance have you set BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM() or other? See ble_gap.h for a list of available BLE_GAP_CONN_SEC_MODE_SET_MACROS.

    Best regards,
    Kenneth

  • Ahh I see, do you need the code snippets for peer_manager_init(), sys_evt_dispatch() and pm_evt_handler() or do you need the location where these are being called?

    static void peer_manager_init()
    {
        ble_gap_sec_params_t sec_param;
        ret_code_t           err_code;
        err_code = pm_init();
        APP_ERROR_CHECK(err_code);
        memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
        // Security parameters to be used for all security procedures.
        sec_param.bond           = SEC_PARAM_BOND;
        sec_param.mitm           = SEC_PARAM_MITM;
        sec_param.lesc           = SEC_PARAM_LESC;
        sec_param.keypress       = SEC_PARAM_KEYPRESS;
        sec_param.io_caps        = SEC_PARAM_IO_CAPABILITIES;
        sec_param.oob            = SEC_PARAM_OOB;
        sec_param.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;
        sec_param.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;
        sec_param.kdist_own.enc  = 1;
        sec_param.kdist_own.id   = 1;
        sec_param.kdist_peer.enc = 1;
        sec_param.kdist_peer.id  = 1;
        err_code = pm_sec_params_set(&sec_param);
        APP_ERROR_CHECK(err_code);
        err_code = pm_register(pm_evt_handler);
        APP_ERROR_CHECK(err_code);
    }

    #define SEC_PARAM_BOND                  1                              /**< Perform bonding. */
    #define SEC_PARAM_MITM                  0                                           /**< Man In The Middle protection not required. */
    #define SEC_PARAM_LESC                  0                                           /**< LE Secure Connections not enabled. */
    #define SEC_PARAM_KEYPRESS              0                                           /**< Keypress notifications not enabled. */
    #define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_NONE                        /**< No I/O capabilities. */
    #define SEC_PARAM_OOB                   0                                           /**< Out Of Band data not available. */
    #define SEC_PARAM_MIN_KEY_SIZE          7                                           /**< Minimum encryption key size. */
    #define SEC_PARAM_MAX_KEY_SIZE          16                                          /**< Maximum encryption key size. */

    I couldnt find sys_evt_dispatch() in my project.

    static void pm_evt_handler(pm_evt_t const * p_evt)
    {
    	ret_code_t err_code;
        pm_handler_on_pm_evt(p_evt);
        pm_handler_flash_clean(p_evt);
    	/*not included*/
    	switch (p_evt->evt_id)
        {
    		case PM_EVT_BONDED_PEER_CONNECTED:
            {
                NRF_LOG_INFO("PM_EVT_BONDED_PEER_CONNECTED - Connected to a previously bonded device.");
            } break;
    		case PM_EVT_CONN_SEC_START:
    			NRF_LOG_INFO("PM_EVT_CONN_SEC_START");
    		break;
    		case PM_EVT_CONN_SEC_SUCCEEDED:
            {
                NRF_LOG_INFO("PM_EVT_CONN_SEC_SUCCEEDED - Connection secured: role: %d, conn_handle: 0x%x, procedure: %d.", ble_conn_state_role(p_evt->conn_handle),
                             p_evt->conn_handle, p_evt->params.conn_sec_succeeded.procedure);
            } break;
    		case PM_EVT_CONN_SEC_FAILED:
            {
    			NRF_LOG_INFO("PM_EVT_CONN_SEC_FAILED");
                /* Often, when securing fails, it shouldn't be restarted, for security reasons. Other times, it can be restarted directly.
                 * Sometimes it can be restarted, but only after changing some Security Parameters. Sometimes, it cannot be restarted until the link is disconnected and reconnected.
                 * Sometimes it is impossible, to secure the link, or the peer device does not support it. How to handle this error is highly application dependent. */
            } break;
    		case PM_EVT_CONN_SEC_CONFIG_REQ:
            {
    			NRF_LOG_INFO("PM_EVT_CONN_SEC_CONFIG_REQ");
                // Reject pairing request from an already bonded peer.
                pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true};
                pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
            } break;
    		case PM_EVT_CONN_SEC_PARAMS_REQ:
    			NRF_LOG_INFO("PM_EVT_CONN_SEC_PARAMS_REQ");
    		break;
    		case PM_EVT_STORAGE_FULL:
            {
    			NRF_LOG_INFO("PM_EVT_STORAGE_FULL");
                // Run garbage collection on the flash.
                err_code = fds_gc();
                if (err_code == FDS_ERR_NO_SPACE_IN_QUEUES)
                {
                    // Retry.
                }
                else
                {
                    APP_ERROR_CHECK(err_code);
                }
            } break;
    		case PM_EVT_ERROR_UNEXPECTED:
            {
    			NRF_LOG_INFO("PM_EVT_ERROR_UNEXPECTED");
                // Assert.
                APP_ERROR_CHECK(p_evt->params.error_unexpected.error);
            } break;
    		case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
    			NRF_LOG_INFO("PM_EVT_PEER_DATA_UPDATE_SUCCEEDED");
    			if (p_evt->params.peer_data_update_succeeded.flash_changed && (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_BONDING))
                {
                    NRF_LOG_INFO("New Bond, add the peer to the whitelist if possible");
    				// Note: You should check on what kind of white list policy your application should use.
                    whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);	/*For Quest*/
                }
            break;
    		case PM_EVT_PEER_DATA_UPDATE_FAILED:
            {
    			NRF_LOG_INFO("PM_EVT_PEER_DATA_UPDATE_FAILED");
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peer_data_update_failed.error);
            } break;		
    		case PM_EVT_PEER_DELETE_SUCCEEDED:
    			NRF_LOG_INFO("PM_EVT_PEER_DELETE_SUCCEEDED");
    		break;
            case PM_EVT_PEERS_DELETE_SUCCEEDED:
    			NRF_LOG_INFO("PM_EVT_PEERS_DELETE_SUCCEEDED");
                advertising_start(false);
            break;		
    		case PM_EVT_PEER_DELETE_FAILED:
            {
    			NRF_LOG_INFO("PM_EVT_PEER_DELETE_FAILED");
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peer_delete_failed.error);
            } break;
    		case PM_EVT_PEERS_DELETE_FAILED:
            {
    			NRF_LOG_INFO("PM_EVT_PEERS_DELETE_FAILED");
                // Assert.
                APP_ERROR_CHECK(p_evt->params.peers_delete_failed_evt.error);
            } break;
            case PM_EVT_LOCAL_DB_CACHE_APPLIED:
    			NRF_LOG_INFO("PM_EVT_LOCAL_DB_CACHE_APPLIED");
    		break;
            case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
    			NRF_LOG_INFO("PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED");
    		break;
                // This can happen when the local DB has changed.
            case PM_EVT_SERVICE_CHANGED_IND_SENT:
    			NRF_LOG_INFO("PM_EVT_SERVICE_CHANGED_IND_SENT");
    		break;
            case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
    			NRF_LOG_INFO("PM_EVT_SERVICE_CHANGED_IND_CONFIRMED");
    		break;
    		case PM_EVT_SLAVE_SECURITY_REQ:
    			NRF_LOG_INFO("PM_EVT_SLAVE_SECURITY_REQ");
    		break;
    		case PM_EVT_FLASH_GARBAGE_COLLECTED:
    			NRF_LOG_INFO("PM_EVT_FLASH_GARBAGE_COLLECTED");
    		break;
    		case PM_EVT_FLASH_GARBAGE_COLLECTION_FAILED:
    			NRF_LOG_INFO("PM_EVT_FLASH_GARBAGE_COLLECTION_FAILED");
    		break;
            default:
                break;
    	}
    }

    FDS defines -

    // <e> FDS_ENABLED - fds - Flash data storage module
    //==========================================================
    #ifndef FDS_ENABLED
    #define FDS_ENABLED 1
    #endif
    // <h> Pages - Virtual page settings
    
    // <i> Configure the number of virtual pages to use and their size.
    //==========================================================
    // <o> FDS_VIRTUAL_PAGES - Number of virtual flash pages to use. 
    // <i> One of the virtual pages is reserved by the system for garbage collection.
    // <i> Therefore, the minimum is two virtual pages: one page to store data and one page to be used by the system for garbage collection.
    // <i> The total amount of flash memory that is used by FDS amounts to @ref FDS_VIRTUAL_PAGES * @ref FDS_VIRTUAL_PAGE_SIZE * 4 bytes.
    
    #ifndef FDS_VIRTUAL_PAGES
    #define FDS_VIRTUAL_PAGES 3
    #endif
    
    // <o> FDS_VIRTUAL_PAGE_SIZE  - The size of a virtual flash page.
     
    
    // <i> Expressed in number of 4-byte words.
    // <i> By default, a virtual page is the same size as a physical page.
    // <i> The size of a virtual page must be a multiple of the size of a physical page.
    // <1024=> 1024 
    // <2048=> 2048 
    
    #ifndef FDS_VIRTUAL_PAGE_SIZE
    #define FDS_VIRTUAL_PAGE_SIZE 1024
    #endif
    
    // <o> FDS_VIRTUAL_PAGES_RESERVED - The number of virtual flash pages that are used by other modules. 
    // <i> FDS module stores its data in the last pages of the flash memory.
    // <i> By setting this value, you can move flash end address used by the FDS.
    // <i> As a result the reserved space can be used by other modules.
    
    #ifndef FDS_VIRTUAL_PAGES_RESERVED
    #define FDS_VIRTUAL_PAGES_RESERVED 0
    #endif
    
    // </h> 
    //==========================================================
    
    // <h> Backend - Backend configuration
    
    // <i> Configure which nrf_fstorage backend is used by FDS to write to flash.
    //==========================================================
    // <o> FDS_BACKEND  - FDS flash backend.
     
    
    // <i> NRF_FSTORAGE_SD uses the nrf_fstorage_sd backend implementation using the SoftDevice API. Use this if you have a SoftDevice present.
    // <i> NRF_FSTORAGE_NVMC uses the nrf_fstorage_nvmc implementation. Use this setting if you don't use the SoftDevice.
    // <1=> NRF_FSTORAGE_NVMC 
    // <2=> NRF_FSTORAGE_SD 
    
    #ifndef FDS_BACKEND
    #define FDS_BACKEND 2
    #endif
    
    // </h> 
    //==========================================================
    
    // <h> Queue - Queue settings
    
    //==========================================================
    // <o> FDS_OP_QUEUE_SIZE - Size of the internal queue. 
    // <i> Increase this value if you frequently get synchronous FDS_ERR_NO_SPACE_IN_QUEUES errors.
    
    #ifndef FDS_OP_QUEUE_SIZE
    #define FDS_OP_QUEUE_SIZE 4
    #endif
    
    // </h> 
    //==========================================================
    
    // <h> CRC - CRC functionality
    
    //==========================================================
    // <e> FDS_CRC_CHECK_ON_READ - Enable CRC checks.
    
    // <i> Save a record's CRC when it is written to flash and check it when the record is opened.
    // <i> Records with an incorrect CRC can still be 'seen' by the user using FDS functions, but they cannot be opened.
    // <i> Additionally, they will not be garbage collected until they are deleted.
    //==========================================================
    #ifndef FDS_CRC_CHECK_ON_READ
    #define FDS_CRC_CHECK_ON_READ 0
    #endif
    // <o> FDS_CRC_CHECK_ON_WRITE  - Perform a CRC check on newly written records.
     
    
    // <i> Perform a CRC check on newly written records.
    // <i> This setting can be used to make sure that the record data was not altered while being written to flash.
    // <1=> Enabled 
    // <0=> Disabled 
    
    #ifndef FDS_CRC_CHECK_ON_WRITE
    #define FDS_CRC_CHECK_ON_WRITE 0
    #endif
    
    // </e>
    
    // </h> 
    //==========================================================
    
    // <h> Users - Number of users
    
    //==========================================================
    // <o> FDS_MAX_USERS - Maximum number of callbacks that can be registered. 
    #ifndef FDS_MAX_USERS
    #define FDS_MAX_USERS 4
    #endif

    FSTORAGE defines -

    // <e> NRF_FSTORAGE_ENABLED - nrf_fstorage - Flash abstraction library
    //==========================================================
    #ifndef NRF_FSTORAGE_ENABLED
    #define NRF_FSTORAGE_ENABLED 1
    #endif
    // <h> nrf_fstorage - Common settings
    
    // <i> Common settings to all fstorage implementations
    //==========================================================
    // <q> NRF_FSTORAGE_PARAM_CHECK_DISABLED  - Disable user input validation
     
    
    // <i> If selected, use ASSERT to validate user input.
    // <i> This effectively removes user input validation in production code.
    // <i> Recommended setting: OFF, only enable this setting if size is a major concern.
    
    #ifndef NRF_FSTORAGE_PARAM_CHECK_DISABLED
    #define NRF_FSTORAGE_PARAM_CHECK_DISABLED 0
    #endif
    
    // </h> 
    //==========================================================
    
    // <h> nrf_fstorage_sd - Implementation using the SoftDevice
    
    // <i> Configuration options for the fstorage implementation using the SoftDevice
    //==========================================================
    // <o> NRF_FSTORAGE_SD_QUEUE_SIZE - Size of the internal queue of operations 
    // <i> Increase this value if API calls frequently return the error @ref NRF_ERROR_NO_MEM.
    
    #ifndef NRF_FSTORAGE_SD_QUEUE_SIZE
    #define NRF_FSTORAGE_SD_QUEUE_SIZE 4
    #endif
    
    // <o> NRF_FSTORAGE_SD_MAX_RETRIES - Maximum number of attempts at executing an operation when the SoftDevice is busy 
    // <i> Increase this value if events frequently return the @ref NRF_ERROR_TIMEOUT error.
    // <i> The SoftDevice might fail to schedule flash access due to high BLE activity.
    
    #ifndef NRF_FSTORAGE_SD_MAX_RETRIES
    #define NRF_FSTORAGE_SD_MAX_RETRIES 8
    #endif
    
    // <o> NRF_FSTORAGE_SD_MAX_WRITE_SIZE - Maximum number of bytes to be written to flash in a single operation 
    // <i> This value must be a multiple of four.
    // <i> Lowering this value can increase the chances of the SoftDevice being able to execute flash operations in between radio activity.
    // <i> This value is bound by the maximum number of bytes that can be written to flash in a single call to @ref sd_flash_write.
    // <i> That is 1024 bytes for nRF51 ICs and 4096 bytes for nRF52 ICs.
    
    #ifndef NRF_FSTORAGE_SD_MAX_WRITE_SIZE
    #define NRF_FSTORAGE_SD_MAX_WRITE_SIZE 4096
    #endif

    pm_conn_secure() is not called in main.c

    I never use the delete_bonds() function & I also dont use BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM().

Related