Radio Control Layer (RCL)
Scanner Initiator Command Handler

Introduction

In Bluetooth® Low Energy (BLE), scanning and initiating are key processes for establishing connections between devices.

Scanning is the process by which a central device discovers nearby peripheral devices and can be classified either as passive scanning or active. Passive scanning involves the central device listening on specific advertising channels for advertising packets sent by peripheral devices which contain information about the peripherals, such as their identity, services offered, and signal strength. Active scanning on the other hand occurs when the central device sends scan request PDUs to solicit additional information from specific advertising peripherals after passively receiving their advertising packets.

The initiating process occurs after the scanning phase and involves a central device establishing a connection with a specific peripheral device it has discovered. Initiating differs from scanning in that once the central device has identified a peripheral of interest during the scanning phase, it proceeds to establish a connection by sending connection request PDUs. Unlike scanning, where the central device listens for advertising packets and is not required to respond to them, initiating requires active communication between the central and peripheral devices. The central device sends a connection request PDU to the identified peripheral, indicating its intention to establish a connection and specifying the connection parameters. This triggers a series of negotiation processes, including the exchange of connection parameters and acknowledgment PDUs between both devices, which ultimately leads to the establishment of a BLE connection between the central and peripheral devices.

Just like for the advertiser command handler, before describing how the scanner/initiator command works, it is worth listing the different PDUs involved in the command handler's life cycle.

PDU Type PDU Name Physical Channel LE 1M LE 2M LE Coded Currently Supported
0b0000 ADV_IND Primary * *
0b0001 ADV_DIRECT_IND Primary * *
0b0010 ADV_NONCONN_IND Primary * *
0b0011 SCAN_REQ Primary * *
0b0011 AUX_SCAN_REQ Secondary * * *
0b0100 SCAN_RSP Primary * *
0b0101 CONNECT_IND Primary * *
0b0101 AUX_CONNECT_REQ Secondary * * *
0b0110 ADV_SCAN_IND Primary * *
0b0111 ADV_EXT_IND Primary * * *
0b0111 AUX_ADV_IND Secondary * * * *
0b0111 AUX_SCAN_RSP Secondary * * *
0b0111 AUX_SYNC_IND Periodic * * *
0b0111 AUX_CHAIN_IND Secondary and Periodic * * * *
0b0111 AUX_SYNC_SUBEVENT_IND Periodic * * *
0b0111 AUX_SYNC_SUBEVENT_RSP Periodic * * *
0b1000 AUX_CONNECT_RSP Secondary * * *

Please note that legacy advertising PDUs are limited to primary advertising channels and have a specific payloads, while extended advertising PDUs share the same PDU payload format known as the Common Extended Advertising Payload Format.

The scanner/initiator command handler supports both legacy and extended advertising by extracting the PDU type, and if needed the AdvMode associated with the PDU.

Usage

Even though scanning and initiating are two different processes, their similarities are sufficient to allow for a single command handler that can be configured either for scanning or for initiating. This is because after all, the main difference between both commands (scanner or initiator) is that the expected outcome of an initiator is to establish a connection with the desired peripheral device. Therefore, aspects such as the configuration of the acceptance or rejection of legacy or extended advertising packets are common to both commands.

As any other command handler, the following steps must take place to use the command.

  1. RCL has been initialized (See RCL_init) and a handle must exist (See RCL_open).
  2. The RCL_CMD_BLE5_SCANNER_t or RCL_CMD_BLE5_INITIATOR_t command has been initialized and configured.
  3. The necessary Multibuffer for reception has been initialized and configured.
  4. If needed, the necessary Tx buffer(s) for sending connection requests have been initialized and configured.

Once these steps have been completed, RCL_Command_submit is called to start the command. Upon submitting the command, the caller can either use RCL_Command_pend or a callback to wait for the command's conclusion and proceed with any additional tasks such as post-processing or the submitting of new commands.

Scanner

The scanner command can be configured to behave either as an active or as a passive scanner for both legacy or extended advertising packets. This of course has certain implications on how the command needs to be configured and how it behaves after being submitted.

For instance, if the scanner is expected to scan only for legacy advertising packets, a primary advertising channel must be used.

The following code snippet shows how a passive scanner can be configured to receive both legacy and extended advertising packets.

void runScanner(void)
{
RCL_Handle h = RCL_open(&rclClient, &LRF_configBle);
uint32_t rxBuffer[RCL_MultiBuffer_len_u32(BLE_TEST_MULTI_BUF_LEN)];
scanCmd.common.scheduling = RCL_Schedule_Now;
scanCmd.common.runtime.callback = scanCallback;
/* Scan channel 39 for both legacy and extended advertising packets and stop after the time set by
* SCAN_WINDOW_PASSIVE */
scanCmd.channel = 39;
scanCmd.acceptExtended = true;
scanCmd.acceptLegacy = true;
scanCmd.common.timing.relGracefulStopTime = SCAN_WINDOW_PASSIVE;
/* Use default stats and context configuration and get notified when the command finishes or an Rx
* entry is available */
scanCmd.stats = &scanStats;
scanCmd.ctx = &scanCtx;
scanCmd.common.runtime.lrfCallbackMask = LRF_EventRxOk;
scanCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value |
/* Provide buffer for storing packets. In this case, assume that we expect one packet. */
RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *)rxBuffer;
RCL_MultiBuffer_init(multiBuffer, sizeof(rxBuffer));
RCL_MultiBuffer_put(&scanCtx.rxBuffers, multiBuffer);
RCL_Command_submit(h, &scanCmd);
/* Wait for command to conclude */
RCL_Command_pend(&scanCmd);
/* Check contents of received packet (assuming one was received) */
RCL_Buffer_DataEntry *rxPkt = RCL_MultiBuffer_RxEntry_get(&scanCtx.rxBuffers, NULL);
if (rxPkt != NULL)
{
// Do something with the data
}
}

Initiator

Architecture

The life cycle of the scanner/initiator command handler differs greatly depending on whether it is configured as scanner or as initiator. Therefore, it is recommended to have distinct activity diagrams to illustrate the behavior of the commands.

Scanner