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

Determining BLE phy mode of connection

I'm using s140_nrf52_6.1.1_softdevice and nRF5_SDK_15.3.0_59ac345 on a nRF52840.

We are trying to verify that, indeed, we are successfully entering and using coded phy mode. We don't seem to see any effective range difference between 1 Mbps mode and coded mode. Our peripheral requests the mode, and our central agrees to whatever the peripheral wants. I have debug in the central's event handler that lets me know when any event has been raised, and it provides the event name and pertinent details if any.

First, here is the definition of the central's scan params:

static ble_gap_scan_params_t const m_scan_params =
{
    .active = 1,
    .extended = 1,
    .interval = MSEC_TO_UNITS(100, 625),
    .window = MSEC_TO_UNITS(50, 625),
    .timeout = 0,
    .scan_phys = BLE_GAP_PHY_CODED,
    .filter_policy = BLE_GAP_SCAN_FP_ACCEPT_ALL,
};

And here are the relevant event cases in our central's event handler:

case BLE_GAP_EVT_ADV_REPORT:
{
    ble_gap_evt_adv_report_t const *p_adv_report = &p_gap_evt->params.adv_report;

    // Check if BLE MAC ID is allowed to connect before searching through the advertising data list
    if (allow_sensor(p_adv_report->peer_addr.addr))
    {
        if (ble_advdata_uuid_find(p_adv_report->data.p_data, p_adv_report->data.len, &m_nus_uuid))
        {
            comm_debug_print(
                "OBL:BLE_GAP_EVT_ADV_REPORT(connect) pri%s sec%s",
                phy_mode_str(p_adv_report->primary_phy),
                phy_mode_str(p_adv_report->secondary_phy));
            err_code = sd_ble_gap_connect(
                &p_adv_report->peer_addr,
                &m_scan_params,
                &m_connection_param,
                BLE_CONNECTION_ID);
            if (err_code == NRF_SUCCESS)
            {
                // scan is automatically stopped by the connect
                break;
            }
        }
    }

    // If we made it here, we're not connected to our paired sensor. Scan again.
    err_code = sd_ble_gap_scan_start(NULL, &m_scan_buffer);
    APP_ERROR_CHECK(err_code);
    break;
}

case BLE_GAP_EVT_CONNECTED:
{
    err_code = ble_nus_c_handles_assign(&m_ble_nus_c, p_gap_evt->conn_handle, NULL);
    APP_ERROR_CHECK(err_code);

    // Stop scanning.
    sd_ble_gap_scan_stop();

    // Set the power level for this connection
    sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_CONN,
        p_gap_evt->conn_handle,
        CONNECTION_POWER_LEVEL);

    // Start checking for RSSI
    sd_ble_gap_rssi_start(p_ble_evt->evt.gap_evt.conn_handle, RSSI_MIN_CHANGE_THRESHOLD, RSSI_SKIP_COUNT);

    // start discovery of services. The NUS Client waits for a discovery result
    err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
    APP_ERROR_CHECK(err_code);

    comm_debug_print("OBL:BLE_GAP_EVT_CONNECTED");
    break;
}

case BLE_GAP_EVT_PHY_UPDATE:
{
    ble_gap_evt_phy_update_t const *ble_gap_evt_phy_update = &p_ble_evt->evt.gap_evt.params.phy_update;
    comm_debug_print(
        "OBL:BLE_GAP_EVT_PHY_UPDATE [%02X] tx%s rx%s",
        ble_gap_evt_phy_update->status,
        phy_mode_str(ble_gap_evt_phy_update->tx_phy),
        phy_mode_str(ble_gap_evt_phy_update->rx_phy));
    break;
}

case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
{
    // Accepting parameters requested by peer.
    ble_gap_conn_params_t const *ble_gap_conn_params = &p_gap_evt->params.conn_param_update_request.conn_params;
    err_code = sd_ble_gap_conn_param_update(p_gap_evt->conn_handle, ble_gap_conn_params);
    APP_ERROR_CHECK(err_code);
    comm_debug_print(
        "OBL:BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST -int%dus +int%dus lat%d to%dms",
        ble_gap_conn_params->min_conn_interval * 1250,
        ble_gap_conn_params->max_conn_interval * 1250,
        ble_gap_conn_params->slave_latency,
        ble_gap_conn_params->conn_sup_timeout * 10);
    break;
}

Here is the debug output I see from our central when we successfully connect to our peripheral. Clearly, there is no BLE_GAP_EVT_PHY_UPDATE event, and I have code (above) that would print some debug output if one was received.

ASCII: OBL:BLE_GAP_EVT_ADV_REPORT(connect) priCODED secCODED
ASCII: OBL:BLE_GAP_EVT_CONNECTED
ASCII: OBL:BLE_NUS_C_EVT_DISCOVERY_COMPLETE
ASCII: OBL:BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST -int10000us +int20000us lat0 to4000ms

It appears that before connection with our peripheral, the central receives a BLE_GAP_EVT_ADV_REPORT event with the peer address being the correct address for our peripheral (you can see how the event case checks that) and the primary and secondary phy values both set to a value of 4 (coded). Immediately following, our central receives a BLE_GAP_EVT_CONNECTED event. There was no BLE_GAP_EVT_PHY_UPDATE event on the central at any time, and the central and peripheral are communicating.

1. Is there any way possible that they might not actually be in coded mode?

2. Is there a way that I can simply "get" the phy mode for a given connection? I couldn't find an API function that would tell me that.

3. Am I correct in assuming that we are, indeed, in coded mode since the advertising report was received over the coded phy and there was no BLE_GAP_EVT_PHY_UPDATE ever received by the central?

Parents
  • Hi Jay,

    If the central has received the adv packets on CODED (primary and secondary) then the connect request will also be sent on the same PHY and by defaul the connection established will be on the same PHY as the connect request sent, in your case, that is CODED. Hence your application will not receive any new request of PHY change since it is by spec that the connection is established on CODED and there is no need to let the application know about this. 

    to get the BLE_GAP_EVT_PHY_UPDATE event, you can call sd_ble_gap_phy_update and force the softdevice to give you an BLE_GAP_EVT_PHY_UPDATE  where you can verify which PHY yhe connection is on.

Reply
  • Hi Jay,

    If the central has received the adv packets on CODED (primary and secondary) then the connect request will also be sent on the same PHY and by defaul the connection established will be on the same PHY as the connect request sent, in your case, that is CODED. Hence your application will not receive any new request of PHY change since it is by spec that the connection is established on CODED and there is no need to let the application know about this. 

    to get the BLE_GAP_EVT_PHY_UPDATE event, you can call sd_ble_gap_phy_update and force the softdevice to give you an BLE_GAP_EVT_PHY_UPDATE  where you can verify which PHY yhe connection is on.

Children
  • Okay, this is very good to know. Thank you.

    Your response prompts one more question. Once a connection has been established, can the peripheral device switch phy mode while connected by simply calling sd_ble_gap_phy_update() with a different phy? Or would we have to disconnect and have the peripheral begin advertising over the desired phy? 

  • Hi,

    yes, it can update phy while connected. The change will affect only the requested connection so it's possible to have different phys for different connections. On the local side the BLE_GAP_EVT_PHY_UPDATE_REQUEST event will be generated and to close the deal the local may respond with the sd_ble_gap_phy_update(). In turn, this will generate the BLE_GAP_EVT_PHY_UPDATE event from where you may know that the phy was actually changed and how. The update procedure is nicely described with the SoftDevice message sequence charts.

    By the way, because the code above misses handler for the request case, it might never get into the BLE_GAP_EVT_PHY_UPDATE if the change were originated by a remote. However, since the scan is preformed solely with the coded phy the connection shall also be established over the coded phy - because this is the only phy for the peripheral to advertise on in order to get connected, and AFAIU this is the peripheral which enforces the coded phy for the connection.

    It seems that for the range measurements it might be reasonable to connect over 1M phy, and then explicitly move to the coded phy. The question still though, is there any possibility to know the actual phy for a connection.

  • Thank you. This was very helpful. But, yes, it would be nice for debugging purposes to have an API call that simply reported the phy for a given connection.

Related