Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Concurrents connections (2 identicals centrals try to connect to the same peripheral at the same time)

Hello,

I have a project (using NUS) that comes in 2 parts:

  1. NRF52840 (peripheral) which generate advertising when they have information to transmit.
  2. PCA10059 USB dongles that constantly scan for the above peripherals

I encounter a problem when several USB dongles (with same firmware) receive advertising from a device...
In this case, sometimes the dongles synchronize perfectly and simultaneously try to communicate with the peripheral which launched its advertising.

Each dongle then generates a BLE_NUS_C_EVT_DISCONNECTED event with which I relaunch a scan_start, and so on a few times for ten seconds !

I tried to modify NRF_BLE_SCAN_SCAN_INTERVAL and NRF_BLE_SCAN_SUPERVISION_TIMEOUT like this (but with some small result) :

// <o> NRF_BLE_SCAN_SCAN_INTERVAL - Scanning interval. Determines the scan interval in units of 0.625 millisecond. 
#ifndef NRF_BLE_SCAN_SCAN_INTERVAL
#define NRF_BLE_SCAN_SCAN_INTERVAL 100
#endif

// <o> NRF_BLE_SCAN_SCAN_DURATION - Duration of a scanning session in units of 10 ms. Range: 0x0001 - 0xFFFF (10 ms to 10.9225 ms). If set to 0x0000, the scanning continues until it is explicitly disabled. 
#ifndef NRF_BLE_SCAN_SCAN_DURATION
#define NRF_BLE_SCAN_SCAN_DURATION 0
#endif

// <o> NRF_BLE_SCAN_SCAN_WINDOW - Scanning window. Determines the scanning window in units of 0.625 millisecond. 
#ifndef NRF_BLE_SCAN_SCAN_WINDOW
#define NRF_BLE_SCAN_SCAN_WINDOW 100
#endif

// <o> NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL - Determines minimum connection interval in milliseconds. 
#ifndef NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL
#define NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL 7.5
#endif

// <o> NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL - Determines maximum connection interval in milliseconds. 
#ifndef NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL
#define NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL 40
#endif

// <o> NRF_BLE_SCAN_SLAVE_LATENCY - Determines the slave latency in counts of connection events. 
#ifndef NRF_BLE_SCAN_SLAVE_LATENCY
#define NRF_BLE_SCAN_SLAVE_LATENCY 4
#endif

// <o> NRF_BLE_SCAN_SUPERVISION_TIMEOUT - Determines the supervision time-out in units of 10 millisecond. 
#ifndef NRF_BLE_SCAN_SUPERVISION_TIMEOUT
#define NRF_BLE_SCAN_SUPERVISION_TIMEOUT 800
#endif

static ble_gap_scan_params_t m_scan_param = 
{
    .active        = 1,
    .interval      = NRF_BLE_SCAN_SCAN_INTERVAL,
    .window        = NRF_BLE_SCAN_SCAN_WINDOW,
    .timeout       = NRF_BLE_SCAN_SCAN_DURATION,
    .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL,
    .scan_phys     = BLE_GAP_PHY_1MBPS,
};
static ble_gap_conn_params_t m_conn_param = 
{
    .min_conn_interval  = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MIN_CONNECTION_INTERVAL, UNIT_1_25_MS),
    .max_conn_interval  = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_MAX_CONNECTION_INTERVAL, UNIT_1_25_MS),
    .slave_latency      = (uint16_t)NRF_BLE_SCAN_SLAVE_LATENCY,
    .conn_sup_timeout   = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_SUPERVISION_TIMEOUT, UNIT_10_MS),
};

static void scan_init(void)
{
    ret_code_t err_code;
    nrf_ble_scan_init_t init_scan;

    m_scan_param.interval = NRF_BLE_SCAN_SCAN_INTERVAL + (NRF_FICR->DEVICEADDR[0] & 0xFF);
    m_scan_param.window = m_scan_param.interval;

    m_conn_param.conn_sup_timeout = (uint16_t)MSEC_TO_UNITS(NRF_BLE_SCAN_SUPERVISION_TIMEOUT + (NRF_FICR->DEVICEADDR[0] & 0xFF)*10, UNIT_10_MS);

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

    init_scan.connect_if_match = true;
    init_scan.conn_cfg_tag = APP_BLE_CONN_CFG_TAG;
    init_scan.p_scan_param = &m_scan_param;
    init_scan.p_conn_param = &m_conn_param;

    err_code = nrf_ble_scan_init(&m_scan, &init_scan, scan_evt_handler);

In this page Connecting to advertisers performing extended advertising, I think I'm in the variant #4 but I never get the timeout event...

What's the best pratice for this case ?

Regards,

Gaétan

Related post: 

  • Hello,

    I'm sorry, but I don't think that the start time of the SCAN function is important.
    Indeed, what matters is how many centrals are listening on the channel at the moment the peripheral is advertising.

    I really feel that the problem is that several centrals are TX their response to the advertising in a perfectly synchronized way.
    In this case, it would be necessary to integrate a random time in the central between the RX of the advertising and the TX of the connection request.

  • For the moment, we regularly observe the situation of synchronization of the centrals during 2 or 3 seconds.
    Do you think that there could be a solution on the central to add a variable time between the reception of the avertising and the sending of the connection request?

  • Hi,

    Sorry for the delay.

    Gaétan said:
    Do you think that there could be a solution on the central to add a variable time between the reception of the avertising and the sending of the connection request?

    No. Not on the link-layer. But you can add some delay for when you call sd_ble_gap_connect(). The advertiser will have the radio in RX mode in a short period after sending the advertising packet. The central/scanner need to send the connection request packet in this short window after receiving the advertising packet. If you add some sending delay here, the advertiser will not receive the connection request(because the radio is no longer in RX mode). When you call sd_ble_gap_connect(), the central will listen/scan for a advertising packet(from the address you set when calling the connect function), and it will send the connection request packet if it receive a advertising packet from the specified address.

Related