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

When using nRF MESH, two BLE event handlers being called

Hi, 

I have set a Mesh Client Node with two BLE services: Mesh Proxy Service and Nordic Uart Service. 

The problem is that when I send a message to the Mesh Client  from nRF Mesh app (for example, binding the Appkey, or the setting the publication address), two "on_ble_evt" handlers are being called: "mesh_gatt_on_ble_evt" (which is correct) but also "ble_nus_on_ble_evt", so the NUS service interprets the incoming packet as a NUS packet, while it is a packet for the Mesh service. 

¿Any idea of why this is happening?

Thank you

  • Due to the Easter holiday, response time can be slower than usual. Sorry for any inconvenience caused by this! It seems that both functions interpret the smartphone message as a regular BLE event, even if you are sending to the mesh proxy service characteristic.

    One of our application engineers has made an example combining the light switch example with the nordic uart example like you have done. Having looked at his code, it seems that he has one ble event handler. This makes sense, as both mesh_gatt_on_ble_evt() from the mesh example & ble_nus_on_ble_evt() from Nordic UART service do look very similar (i.e. they have the same function parameters).

    This documentation may also be helpful if you have not seen it yet.

  • Thanks for your reply!

    If I am not wrong,  the difference between my project and the one you referenced (light switch example with the nordic uart example) is that this example has only one BLE service (NUS), but mine has two: Mesh Provisioning Service and NUS.

    I now have one "global_on_ble_evt" handler (at the bottom of this post), which handles both services. But I still don't know where (inside parameters p_ble_evt and/or p_context) is the handle that each ble event addresses; I need this to be able to run different handlers for each ble event, for example BLE_GATTS_EVT_WRITE and BLE_GATTS_EVT_HVN_TX_COMPLETE. 

    (I found that my problem is the same as https://devzone.nordicsemi.com/f/nordic-q-a/36821/how-to-run-proxy-and-nus-at-the-same-time)

    What I have done up to now is the following: 

    I have deleted the NUS Observer:

    //NRF_SDH_BLE_OBSERVER(m_nus_obs, BLE_NUS_BLE_OBSERVER_PRIO, ble_nus_on_ble_evt, &m_nus);

    and only work with the observer created for Mesh service:

    NRF_SDH_BLE_OBSERVER(m_gatt_obs, NRF_MESH_GATT_BLE_OBSERVER_PRIO, global_on_ble_evt, &m_gatt);

    This observer listens to ble events from Mesh Service and from Nus. 

    The global_on_ble_evt is the following: 

    void global_on_ble_evt(ble_evt_t const *p_ble_evt, void *p_context) {
    
      ble_gatts_evt_write_t const *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
      ble_nus_t *p_nus = (ble_nus_t *)p_context;
      if (p_nus->tx_handles.value_handle >= 0x2AD0) { //This is a provisional way to distinguish between Mesh service and Nus service
        //MESH SERVICE EVENT
        switch (p_ble_evt->header.evt_id) {
        case BLE_GAP_EVT_CONNECTED:
          connect_evt_handle(p_ble_evt);
          break;
        case BLE_GAP_EVT_DISCONNECTED:
          disconnect_evt_handle(p_ble_evt);
          break;
    #if NRF_SD_BLE_API_VERSION == 6
        case BLE_GAP_EVT_ADV_SET_TERMINATED:
          if (p_ble_evt->evt.gap_evt.params.adv_set_terminated.reason ==
              BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT) {
            mesh_gatt_evt_t evt;
            evt.type = MESH_GATT_EVT_TYPE_ADV_TIMEOUT;
            evt.conn_index = p_ble_evt->evt.gap_evt.conn_handle;
            m_gatt.evt_handler(&evt, m_gatt.p_context);
          }
          break;
    #elif NRF_SD_BLE_API_VERSION <= 5
        case BLE_GAP_EVT_TIMEOUT:
          if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISING) {
            mesh_gatt_evt_t evt;
            evt.type = MESH_GATT_EVT_TYPE_ADV_TIMEOUT;
            evt.conn_index = p_ble_evt->evt.gap_evt.conn_handle;
            m_gatt.evt_handler(&evt, m_gatt.p_context);
          }
          break;
    #else
    #error Unsupported SoftDevice version
    #endif
        case BLE_GATTS_EVT_WRITE:
          write_evt_handle(p_ble_evt);
          break;
    
        case BLE_GATTS_EVT_HVN_TX_COMPLETE:
          tx_complete_handle(p_ble_evt->evt.gatts_evt.conn_handle);
          break;
    
        /* TODO: The following events should be handled by an SDK module/the application. */
        case BLE_GATTS_EVT_SYS_ATTR_MISSING: {
          /* This call might have been called already as a result of a failing gatts call, ignore the error code. */
          (void)sd_ble_gatts_sys_attr_set(p_ble_evt->evt.gatts_evt.conn_handle, NULL, 0, 0);
          break;
        }
    
        case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: {
          ble_gap_data_length_params_t dl_params;
          memset(&dl_params, BLE_GAP_DATA_LENGTH_AUTO, sizeof(dl_params));
          NRF_MESH_ERROR_CHECK(sd_ble_gap_data_length_update(p_ble_evt->evt.gap_evt.conn_handle,
              &dl_params,
              NULL));
          break;
        }
    
        case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
          NRF_MESH_ERROR_CHECK(sd_ble_gap_sec_params_reply(p_ble_evt->evt.gap_evt.conn_handle,
              BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP,
              NULL,
              NULL));
          break;
    
        case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
          ble_gap_phys_t const phys =
              {
                  .rx_phys = BLE_GAP_PHY_AUTO,
                  .tx_phys = BLE_GAP_PHY_AUTO,
              };
          NRF_MESH_ERROR_CHECK(sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys));
          break;
        }
    
        case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
          exchange_mtu_req_handle(p_ble_evt);
          break;
    
        case BLE_GATTS_EVT_SC_CONFIRM:
          break;
    
        default:
          break;
        }
        if ((p_context == NULL) || (p_ble_evt == NULL)) {
          return;
        }
    
      } else { //NUS EVENT
    
        switch (p_ble_evt->header.evt_id) {
        case BLE_GAP_EVT_CONNECTED:
          on_connect(p_nus, p_ble_evt);
          break;
    
        case BLE_GATTS_EVT_WRITE:
          on_write(p_nus, p_ble_evt);
          break;
    
        case BLE_GATTS_EVT_HVN_TX_COMPLETE:
          on_hvx_tx_complete(p_nus, p_ble_evt);
          break;
    
        default:
          // No implementation needed.
          break;
        }
      }
    }
    

    (With both Mesh Service and NUService ble events this function only enters the first if condition).

    With this changes I can provision the node with nRF Mesh app, but the NUS service BLE_GATTS_EVT_WRITE and BLE_GATTS_EVT_HVN_TX_COMPLETE handlers (on_write and on_hvx_tx_complete) are never run. 

    As I mentioned, I still don't know where (inside parameters p_ble_evt and/or p_context) is the handle that each ble event addresses. Knowing this could let me distinguish between a NUS event and a MESH ble event. 

    Can you help me?

    Thank you very much

  • Sorry for the delayed response. I have been busy with other support activity unfortunately. I totally forgot that we have a SDK UART coexistence example here, which does exactly what you want to do! 

    ble_nus has a NRF_SDH_BLE_OBSERVER & a related ble_nus_on_ble_evt event handler. ble_gatt also has a BLE observer with the nrf_ble_gatt_on_ble_evt event handler. I would recommend taking a look at the example for more details.

  • Hi Bjørn, thank you for your answer

    The problem with coexist example is that is doesn't implement Mesh Provisioning service (let's call it Mesh Proxy), which shares the "write" BLE event with ble_nus. The Mesh Provisioning service adds a new observer and its handler (mesh_gatt_on_ble_evt), so when either nus or mesh proxy write something, both write handlers are called (on_write for NUS  and write_evt_handle for Mesh Proxy).

    I am debugging the "global_on_ble_evt" (handler for both Mesh proxy and NUS) that I wrote on a previous post, but I'm not sure this is the right way to do it. 

  • I can't think of anything wrong with having a global_on_ble_evt event handler function, as long as you correctly filter out the events correctly for UART & for the proxy service. Maybe one of these links may be helpful: link 1, link 2, link 3. If you cannot get it working, I can see if I can set off a few hours to see if I can get an example working with GATT proxy & UART.

Related