Local Event Handling on Bluetooth NCP

Introduction

This document discusses how a network co-processor (NCP) firmware can handle stack events locally instead of sending every event to the host processor. This allows event pre-processing which can be useful on some use cases to prevent overflowing the host with events.

Background

Ordinarily, an NCP device sends and receives Bluetooth packets on behalf of a host processor but does not have any application layer intelligence. It receives commands from and sends events to the host, and the host must tell the NCP what to do.

However, in some cases it may be useful for the NCP to pre-process some of the events itself rather than sending every event to the host. One such use case is where the NCP acts as a scanner in a high-traffic environment. This could result in reporting every single advertisement to the host which can easily be overwhelming for the host to process.

Implementation

This section explains how to modify the standard NCP firmware and assumes that the user is already familiar with the NCP, for instance by reading application note AN1042: Using the Silicon Labs Bluetooth® Stack in Network Co-Processor Mode

By default, the NCP firmware passes all events to the host processor. However, this can be controlled by the implementation of local_handle_event() which is found in main.c. This function performs no handling of events and returns false to indicate that the event passed to it has not been handled and it should be sent to the host. If the function returns true, the event will not be sent to the host device.

To handle a particular event locally, this function can be customized. In this case, let’s assume that the desired behavior is to filter out any advertisements or scan responses that do not come from a device with OUI 00:0B:57 (which is an OUI of Silicon Labs) and not send them to the host. This can be accomplished by adding a case statement to the local_handle_event() function which captures the le_gap_scan_response event and checks the OUI.

/**
 * Handle events meant to be handled locally
 */
static uint32_t local_handle_event(struct gecko_cmd_packet *evt)
{
  bool evt_handled = false;
  switch (BGLIB_MSG_ID(evt->header)) {

  // The case statement below will add OUI based filtering of scan_response events
  case gecko_evt_le_gap_scan_response_id:

      bd_addr address = evt->data.evt_le_gap_scan_response.address;
      if(address.addr[5] == 0x00 && address.addr[4] == 0x0B && address.addr[3] == 0x57) {
          // Scanned device has OUI 00:0B:57, therefore the event shall be sent to the host
          evt_handled = false;
      }
      else
      {
          // Scanned device does *not* have OUI 00:0B:57, therefore the event shall *not* be sent to the host
          evt_handled = true;
      }
  break;

    default:
      break;
  }
  return evt_handled;
}

This section of code checks whether the first three bytes of the Bluetooth address, which come in reverse order, match the desired OUI. If that's the case, then evt_handled is set false and the event will be sent to the host. Otherwise, evt_handled is to true indicating that the event will not be sent to the host. This is a small change but it could dramatically reduce the amount of traffic between NCP and host as well as reducing the burden on the host itself.

In this way the handle_local_event() can be modified to perform any local event handling.