Radio Control Layer (RCL)
Periodic Advertiser Command Handler

Introduction

In Bluetooth® Low Energy (BLE), periodic advertising (without responses) refers to a feature in which an advertiser can broadcast data at regular intervals without expecting or allowing a response from receiving devices. This advertising method relies on the use of extended advertising PDUs, and is particularly useful for applications requiring consistent data transmission over time, such as broadcasting sensor data, location beacons, or public information in a power-efficient manner. By not waiting for acknowledgments or replies, periodic advertising minimizes power consumption and reduces the complexity of maintaining a connection.

Periodic Advertising with Responses (PAwR) was introduced in Bluetooth Core Specification 5.4 to enable bi-directional communication between an advertiser and multiple scanners within a structured time frame. Unlike standard periodic advertising, PAwR allows devices to send responses within pre-defined response slots, enabling efficient communication while maintaining low power consumption.

A key feature of PAwR is that AUX_CONNECT_REQ PDUs are allowed, meaning that advertisers can act as initiators and trigger a transition from periodic advertising to an active connection with a particular scanner when needed. This enables both connectionless and connection-oriented communication models.

PDU Type PDU Name Physical Channel LE 1M LE 2M LE Coded Currently Supported Used in Direction
0b0101 AUX_CONNECT_REQ Secondary * * * * PAwR Sent
0b0111 ADV_EXT_IND Primary * * * PA Sent
0b0111 AUX_ADV_IND Secondary * * * * PA Sent
0b0111 AUX_SYNC_IND Periodic * * * * PA Sent
0b0111 AUX_CHAIN_IND Secondary and Periodic * * * * PA Sent
0b0111 AUX_SYNC_SUBEVENT_IND Periodic * * * * PAwR Sent
0b0111 AUX_SYNC_SUBEVENT_RSP Periodic * * * * PAwR Received
0b1000 AUX_CONNECT_RSP Secondary * * * * PAwR Received

Usage

The periodic advertising command handler supports both periodic advertising without responses and periodic advertising with responses. It sends the indication PDUs marked with a direction of sent in the table above. When configured for periodic advertising with responses, the handler can also receive response PDUs, such as AUX_SYNC_SUBEVENT_RSP and AUX_CONNECT_RSP.

Periodic Advertising Establishment

Periodic advertising establishment is the procedure where an advertiser informs potential scanners about ongoing periodic advertising. During this procedure, the advertiser sends an ADV_EXT_IND PDU that points to an AUX_ADV_IND PDU. This AUX_ADV_IND contains the SyncInfo, which a scanner uses to synchronize with the periodic advertising events.

To signal the use of periodic advertising with responses, the advertiser includes an ACAD field in the AUX_ADV_IND PDU. This field contains an AD Structure with Periodic Advertising Response Timing Information, which allows a scanner to identify the advertising as PAwR.

To perform periodic advertising establishment, follow these basic steps:

  1. Initialize the RCL (See RCL_init) and provide a handle (See RCL_open).
  2. Initialize and configure a RCL_CMD_BLE5_ADV_t command for periodic advertising establishment.
  3. Provide the necessary Tx buffer(s) such that they have been initialized and configured to contain the necessary syncInfo needed for the periodic advertising.
  4. Submit the command with RCL_Command_submit, and 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.

Periodic Advertising without Responses

When configured for periodic advertising without responses, the periodic advertiser command handler sends AUX_SYNC_IND and AUX_CHAIN_IND PDUs. The AUX_CHAIN_IND PDUs can contain an AuxPtr to chain additional packets.

periodic_advertising_example.png
Example of periodic advertising events from the same advertising set

If the execution of the RCL_CMD_BLE5_ADV_t command is successful, it can be assumed that the periodic advertising establishment is done, and the user can proceed with the periodic advertising.

  1. Initialize and configure a RCL_CMD_BLE5_PER_ADV_t command.
  2. Use the start time of the RCL_CMD_BLE5_ADV_t command, RCL_BLE5_getAuxAdvStartTimeDelta, and the SyncInfo needed to set up the start time of the RCL_CMD_BLE5_PER_ADV_t command.
  3. Provide the necessary Tx buffer(s) such that they have been initialized and configured to contain the desired advertising data.
  4. Submit the command RCL_Command_submit, and 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.
  5. Rely on the start time of the previous RCL_CMD_BLE5_PER_ADV_t command to schedule new periodic advertising commands.

The following code snippet shows how to establish a periodic advertising as an advertiser:

void runPeriodicAdvertiser(void)
{
RCL_Handle h = RCL_open(&rclClient, &LRF_configBle);
/* Tx buffers needed for periodic advertising establishment */
RCL_Buffer_TxBuffer *advExtTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer;
RCL_Buffer_TxBuffer *auxAdvTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer2;
/* Tx buffers needed for periodic advertising */
RCL_Buffer_TxBuffer *auxSyncTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer3;
RCL_Buffer_TxBuffer *auxChainTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer4;
AuxPtr advExtAuxPtr;
AuxPtr auxSyncAuxPtr;
SyncInfo auxAdvSyncInfo;
/* Setup advertiser command handler used for periodic advertising establishment */
advCmd.chanMap = CH_MAP;
advCmd.common.phyFeatures = PHY_FEATURES;
advCmd.ctx = &advCtx;
advCmd.stats = &advStats;
advCmd.common.scheduling = RCL_Schedule_AbsTime;
advCmd.common.runtime.callback = advCallback;
advCmd.common.runtime.lrfCallbackMask.value = 0;
advCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value |
advStats = (RCL_StatsAdvScanInit) { 0 };
advStats.config.accumulate = true;
uint32_t startTimeAdvCmd = RCL_Scheduler_getCurrentTime() + RCL_SCHEDULER_SYSTIM_US(ADV_START_DELAY_US);
advCmd.common.timing.absStartTime = startTimeAdvCmd;
/* AuxPtr to be used for the ADV_EXT_IND indicating that the auxiliary packet (i.e. AUX_ADV_IND) will be sent on:
* BLE 2M PHY, channel 25, and as soon as possible.
*/
advExtAuxPtr.auxOffset = 0;
advExtAuxPtr.offsetUnits = 1;
advExtAuxPtr.auxPhy = 1;
advExtAuxPtr.ca = 0;
advExtAuxPtr.chIndex = 25;
/* SyncInfo to be send in the AUX_ADV_IND to inform potential scanners about the characteristics of the
* periodic advertising event
*/
auxAdvSyncInfo.accessAddress = PER_ADV_ACCESS_ADDRESS;
auxAdvSyncInfo.crcInit = PER_ADV_CRC_INIT;
auxAdvSyncInfo.interval = 500; /* Indicating a periodic advertising interval of 500 x 1.25 [ms] = 625 [ms] */
auxAdvSyncInfo.offsetInfo.adjust = 0;
auxAdvSyncInfo.offsetInfo.base = 2400; /* Indicating an sync packet window offset of 2400 x 30 [us] = 72 [ms] */
auxAdvSyncInfo.offsetInfo.units = 0; /* 30 [us] offset units */
/* All RF channels of the periodic physical channel are used */
auxAdvSyncInfo.chMap.chMap0To7 = 0xFF;
auxAdvSyncInfo.chMap.chMap8To15 = 0xFF;
auxAdvSyncInfo.chMap.chMap16To23 = 0xFF;
auxAdvSyncInfo.chMap.chMap24To31 = 0xFF;
auxAdvSyncInfo.chMap.chMap32To36 = 0x1F;
auxAdvSyncInfo.sleepClockAccuracy = 4; /* Indicating a sleep clock accuracy of 51 ppm to 75 ppm */
auxAdvSyncInfo.periodicEventCounter = 0x78; /* paEventCounter value that applies for the AUX_SYNC_IND */
/* AuxPtr to be used for the AUX_ADV_IND indicating that a chained packet will be sent on:
* Channel 16, and as soon as possible. No PHY change allowed at this point.
*/
auxSyncAuxPtr.auxOffset = 0;
auxSyncAuxPtr.offsetUnits = 1;
auxSyncAuxPtr.ca = 0;
auxSyncAuxPtr.chIndex = 16;
auxSyncAuxPtr.auxPhy = 1;
/* Populate Tx buffer used for the ADV_EXT_IND that will be sent on all primary advertisement channels */
setAdvExtBuffer(advExtTxBuffer, &advExtAuxPtr);
/* Populate Tx buffer used for the AUX_ADV_IND that will be sent on a secondary advertisement channel */
setAuxAdvSyncBuffer(auxAdvTxBuffer, &auxAdvSyncInfo, AUX_ADV_DATA_LEN);
advExtTxBuffer->state = RCL_BufferStatePending;
auxAdvTxBuffer->state = RCL_BufferStatePending;
RCL_TxBuffer_put(&advCtx.txBuffers, advExtTxBuffer);
RCL_TxBuffer_put(&advCtx.txBuffers, auxAdvTxBuffer);
/* Submit command wait for it to conclude */
RCL_Command_submit(h, &advCmd);
RCL_Command_pend(&advCmd);
/* Setup periodic advertiser command handler */
perAdvCmd.ctx = &perAdvCtx;
perAdvCmd.stats = &perAdvStats;
perAdvCmd.common.scheduling = RCL_Schedule_AbsTime;
perAdvCmd.common.runtime.callback = advCallback;
perAdvCmd.common.runtime.lrfCallbackMask.value = 0;
perAdvCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value |
perAdvStats = (RCL_StatsAdvScanInit) { 0 };
perAdvStats.config.accumulate = true;
/* Populate Tx buffer used for the AUX_SYNC_IND */
setAuxSyncBuffer(auxSyncTxBuffer, &auxSyncAuxPtr, AUX_ADV_DATA_LEN);
/* Populate Tx buffer used for the AUX_CHAIN_IND */
setAuxChainBuffer(auxChainTxBuffer, NULL, AUX_CHAIN_DATA_LEN);
auxSyncTxBuffer->state = RCL_BufferStatePending;
auxChainTxBuffer->state = RCL_BufferStatePending;
RCL_TxBuffer_put(&perAdvCtx.txBuffers, auxSyncTxBuffer);
RCL_TxBuffer_put(&perAdvCtx.txBuffers, auxChainTxBuffer);
/* Start time of AUX_ADV_IND is calculated based on the start time of the advertiser command,
* the time delta to the transmitting of the AUX_ADV_IND, the primary and secondary PHYs,
* and the channel map.
*/
uint32_t startTimeAuxAdvInd = startTimeAdvCmd + RCL_BLE5_getAuxAdvStartTimeDelta(PHY_FEATURES,
PHY_FEATURES,
CH_MAP,
ADV_EXT_IND_PAYLOAD_LEN);
uint32_t startTimePerAdvCmd = startTimeAuxAdvInd +
RCL_SCHEDULER_SYSTIM_US(auxAdvSyncInfo.offsetInfo.base * BLE_AUX_OFFSET_30_US);
perAdvCmd.common.timing.absStartTime = startTimePerAdvCmd;
/* Configure periodic advertising based on syncInfo information and start time of AUX_ADV_IND */
perAdvCmd.ctx->accessAddress = PER_ADV_ACCESS_ADDRESS;
perAdvCmd.ctx->crcInit = PER_ADV_CRC_INIT;
/* Use same PHY as the one used to send the AUX_ADV_IND */
perAdvCmd.common.phyFeatures = advExtAuxPtr.auxPhy;
/* Submit command wait for it to conclude. If needed, update start time of the periodic advertising command
* for other periodic advertising events.
*/
RCL_Command_submit(h, &perAdvCmd);
RCL_Command_pend(&perAdvCmd);
}

As mentioned before, periodic advertising establishment requires that an AUX_ADV_IND PDU be sent with the necessary SyncInfo. This information is used by potential scanners to properly follow the periodic advertising events. In the previous code snippet, the Tx buffer corresponding to the AUX_ADV_IND is built with a helper function that populates the Tx buffer with appropriate values for each field in the Common Extended Advertising Payload Format.

typedef struct
{
uint16_t base: 13;
uint16_t units: 1;
uint16_t adjust: 1;
uint16_t reserved: 1;
} packetOffsetInfo;
typedef struct
{
uint8_t chMap0To7;
uint8_t chMap8To15;
uint8_t chMap16To23;
uint8_t chMap24To31;
uint8_t chMap32To36: 5;
uint8_t reserved: 3;
} channelMap;
typedef struct
{
packetOffsetInfo offsetInfo;
uint16_t interval;
channelMap chMap;
uint8_t sleepClockAccuracy;
uint32_t accessAddress;
uint32_t crcInit;
uint16_t periodicEventCounter;
} SyncInfo;
static void setAuxAdvSyncBuffer(RCL_Buffer_TxBuffer *buffer, SyncInfo *auxAdvSyncInfo, uint8_t advDataLen)
{
/* Include extra octet corresponding to the extended header length and AdvMode */
uint8_t payloadLength = 1 + AUX_ADV_SYNC_HDR_LEN + advDataLen;
uint8_t *txData;
txData = RCL_TxBuffer_init(buffer, NUM_PAD, BLE_HDR_LEN, payloadLength);
txData[0] = BLE_HDR_AUX_ADV_IND;
txData[1] = payloadLength;
txData[2] = (BLE_ADV_MODE_NONCONN_NONSCAN << 6) | AUX_ADV_SYNC_HDR_LEN;
txData[3] = BLE5_EXT_HDR_FLAG_ADVA_BM | BLE5_EXT_HDR_FLAG_ADI_BM | BLE5_EXT_HDR_FLAG_SYNC_INFO_BM;
/* AdvA */
txData[4] = 0xAA;
txData[5] = 0xBB;
txData[6] = 0xCC;
txData[7] = 0xDD;
txData[8] = 0xEE;
txData[9] = 0x01;
/* ADI */
txData[10] = 0;
txData[11] = 0;
/* SyncInfo */
txData[12] = auxAdvSyncInfo->offsetInfo.base & 0xFF;
txData[13] = ((auxAdvSyncInfo->offsetInfo.base >> 8) & 0x1F) |
((auxAdvSyncInfo->offsetInfo.units & 0x01) << 5) |
((auxAdvSyncInfo->offsetInfo.adjust & 0x01) << 6);
txData[14] = (auxAdvSyncInfo->interval & 0xFF);
txData[15] = (auxAdvSyncInfo->interval >> 8);
txData[16] = (auxAdvSyncInfo->chMap.chMap0To7);
txData[17] = (auxAdvSyncInfo->chMap.chMap8To15);
txData[18] = (auxAdvSyncInfo->chMap.chMap16To23);
txData[19] = (auxAdvSyncInfo->chMap.chMap24To31);
txData[20] = (auxAdvSyncInfo->chMap.chMap32To36 & 0x1F) |
((auxAdvSyncInfo->sleepClockAccuracy & 0x07) << 5);
txData[21] = (auxAdvSyncInfo->accessAddress & 0xFF);
txData[22] = (auxAdvSyncInfo->accessAddress >> 8) & 0xFF;
txData[23] = (auxAdvSyncInfo->accessAddress >> 16) & 0xFF;
txData[24] = (auxAdvSyncInfo->accessAddress >> 24) & 0xFF;
txData[25] = (auxAdvSyncInfo->crcInit & 0xFF);
txData[26] = (auxAdvSyncInfo->crcInit >> 8) & 0xFF;
txData[27] = (auxAdvSyncInfo->crcInit >> 16) & 0xFF;
txData[28] = (auxAdvSyncInfo->periodicEventCounter & 0xFF);
txData[29] = (auxAdvSyncInfo->periodicEventCounter >> 8);
/* AdvData */
if (advDataLen > 0)
{
for(uint32_t i = 0; i < advDataLen; i++)
{
txData[30 + i] = i & 0xFF;
}
}
}

Notice how the previously defined SyncInfo is used to populate the Tx buffer with the help of a C struct.

Using the periodic advertising command handler requires at least one Tx buffer in the buffer list corresponding to the AUX_SYNC_IND PDU. If needed, the user can rely on the callback to the command to provide additional Tx buffers corresponding to AUX_CHAIN_IND PDUs.

Considering that the syncPacketWindowOffset indicates the transmission time of an AUX_SYNC_IND, and that the reference point is the start time of the AUX_ADV_IND, the RCL provides the RCL_BLE5_getAuxAdvStartTimeDelta API to ease the calculation of the start time of the periodic advertising command.

This API can also be used once periodic advertising is ongoing, but the advertiser needs to inform new scanner devices about the ongoing periodic advertising.

Periodic Advertising with Responses

When configured for periodic advertising with responses, the periodic advertiser command handler sends AUX_SYNC_SUBEVENT_IND and AUX_CONNECT_REQ PDUs.

After transmitting an AUX_SYNC_SUBEVENT_IND PDU, a PAwR advertiser may receive AUX_SYNC_SUBEVENT_RSP PDUs from peer scanners that have subscribed to response slots. The timing between the indication transmission and the reception of responses is determined by several factors, including the PDU payload length, the Periodic Advertising Response Slot Delay, and the Periodic Advertising Response Slot Spacing.

In some cases, such as when a scanner subscribes to the first response slot, the interval between the end of the indication transmission and the start of the first response slot can be very short. This is particularly true when using longer payloads or certain PHYs, where the transmission time of the indication PDU approaches the response slot delay. As a result, the available margin for the receiver to become ready before the response slot begins may be limited.

The table below demonstrates how different combinations of PDU payload length and response slot delay impact the available time margin between the end of the AUX_SYNC_SUBEVENT_IND transmission and the start of the first response slot. These examples assume a PAwR scanner subscribes to the first response slot:

Case PHY AUX_SYNC_SUBEVENT_IND Payload (bytes) Response Slot Delay Transmission Time (µs) Available Margin (µs)
1 LE 1M 125 1.25 ms ~1080 ~170
2 LE 1M 255 2.5 ms ~2120 ~380
3 LE 2M 140 1.25 ms ~604 ~646
4 LE 2M 255 2.5 ms ~1064 ~1436
5 LE Coded S2 49 1.25 ms ~1246 ~4
6 LE Coded S2 255 5.0 ms ~4542 ~458
7 LE Coded S8 4 1.25 ms ~976 ~274
8 LE Coded S8 16 1.25 ms ~1744 N/A

Timing example table notes:

  • An available margin of 4 µs is insufficient, as it violates the minimum T_IFS requirement of 150 µs.
  • A 4-byte payload for AUX_SYNC_SUBEVENT_IND is generally impractical, as it leaves little room for meaningful data for a PAwR scanner.
  • N/A indicates that the available margin is negative, meaning the timing requirements cannot be met under those specific conditions.

Besides, the Bluetooth specification mandates an Inter-Frame Space (T_IFS) of 150 µs, which is the required interval between consecutive transmissions and receptions on the same channel. For PAwR, it is specified that the duration of the AUX_SYNC_SUBEVENT_IND PDU must be less than the Periodic Advertising Response Slot Delay minus T_IFS (150 µs).

These timing constraints present significant challenges for achieving both reliable reception and power efficiency:

  • If the interval between the indication and the response slot is long, opening the receiver window too early results in unnecessary power consumption.
  • Conversely, if the available margin is tight, the receiver must be activated no later than the first response slot to ensure timely reception.

Furthermore, periodic advertising with responses allows for connection creation, requiring the advertiser to support both sending AUX_CONNECT_REQ PDUs and receiving AUX_CONNECT_RSP PDUs. Unlike PAwR synchronization—where the focus is on sending indications and receiving responses—connection creation demands different radio configurations and operational sequences.

To address these diverse timing and operational requirements, the PAwR advertiser handler provides three distinct operating modes. Modes 0 and 1 are optimized for PAwR synchronization, while Mode 2 is specifically designed for creating connections. The following sections describe each mode in detail.

PAwR Advertiser Mode 0

pawr_advertising_mode_zero_example.png
Example of Periodic Advertising with Responses: PAwR Advertiser Mode 0 and Generic Rx

Mode 0 is designed for scenarios where the available time margin between the end of the AUX_SYNC_SUBEVENT_IND transmission and the start of the first response slot is tight. For example, as illustrated in case 1 of the timing examples table, only about 170 µs is available for the receiver to become ready before the first response slot begins. In such cases, using a separate RCL_CMD_BLE5_GENERIC_RX_t radio command may not be practical due to its startup latency.

To address this, Mode 0 enables the PAwR advertiser to automatically switch to receive mode immediately after transmitting an AUX_SYNC_SUBEVENT_IND PDU. The receiver is scheduled to open just before the first response slot, with its timing precisely calculated by subtracting the radio's Rx startup overhead from the Periodic Advertising Response Slot Delay. This approach ensures that the receiver is active only when necessary, minimizing power consumption while still meeting strict timing requirements.

Mode 0 also allows the user to specify the expected number of AUX_SYNC_SUBEVENT_RSP PDUs to be received, which is useful for the scenario where response slots are closely spaced. The operation will conclude when either the specified number of responses has been received or a timeout occurs.

For response slots that are spaced farther apart in time, it is not efficient to keep the receiver active continuously, as this would lead to unnecessary power consumption. Instead, as shown in the figure above, Mode 0 is typically used to handle the first few, closely spaced response slots (for example, the first three). For subsequent response slots that occur later, one or more RCL_CMD_BLE5_GENERIC_RX_t commands can be scheduled to open the receiver window only when needed, further optimizing timing and power efficiency.

According to the Bluetooth Core Specification, AUX_SYNC_SUBEVENT_RSP PDUs use the access address (AA) defined in the Periodic Advertising Timing Information. This AA must differ from the one set in the SyncInfo, which is used for AUX_SYNC_IND PDUs. When configuring the PAwR advertiser in Mode 0, a second access address should be provided using the rspAA field of the RCL_CTX_PER_ADVERTISER_t context structure, and the accessAddress field of the RCL_CTX_GENERIC_RX_t context structure if RCL_CMD_BLE5_GENERIC_RX_t commands are used.

After successful execution of the RCL_CMD_BLE5_ADV_t command, periodic advertising establishment is complete and PAwR advertising can proceed. The following steps outline the process to perform PAwR advertising in Mode 0:

  1. Initialize and configure a RCL_CMD_BLE5_PER_ADV_t command.
  2. Use the start time of the RCL_CMD_BLE5_ADV_t command, RCL_BLE5_getAuxAdvStartTimeDelta, and the SyncInfo to set up the start time of the RCL_CMD_BLE5_PER_ADV_t command.
  3. Provide the necessary Tx buffer(s) that have been initialized and configured to contain the AUX_SYNC_SUBEVENT_IND PDU.
  4. Provide the necessary Multibuffer(s) that have been initialized and configured to receive the AUX_SYNC_SUBEVENT_RSP PDU.
  5. Submit the command with RCL_Command_submit, and 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 submitting new commands.
  6. Initialize and configure one or more RCL_CMD_BLE5_GENERIC_RX_t commands, depending on the response slot subscription.
  7. Provide the necessary Multibuffer(s) that have been initialized and configured to receive the AUX_SYNC_SUBEVENT_RSP PDUs.
  8. For each RCL_CMD_BLE5_GENERIC_RX_t command, use the start time of the RCL_CMD_BLE5_PER_ADV_t command, along with the Periodic Advertising Response Slot Delay, Periodic Advertising Response Slot Spacing, and the response slot subscription to set up the appropriate start time.
  9. Use the start time of the previous RCL_CMD_BLE5_PER_ADV_t command, along with the Periodic Advertising Subevent Interval and the periodic advertising interval, to schedule the next PAwR advertising command.

The following code snippet shows how to configure the PAwR advertiser in Mode 0 and run periodic advertising with responses as an advertiser:

void runPAwRAdvertiserMode0(void)
{
RCL_Handle h = RCL_open(&rclClient, &LRF_configBle);
/*====== Prepare Extended Advertiser ======*/
/* Setup advertiser command handler used for periodic advertising establishment */
advCmd.chanMap = CH_MAP;
advCmd.common.phyFeatures = PHY_FEATURES;
advCmd.ctx = &advCtx;
advCmd.stats = &advStats;
advCmd.common.scheduling = RCL_Schedule_AbsTime;
advCmd.common.runtime.callback = advCallback;
advCmd.common.runtime.lrfCallbackMask.value = 0;
advCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value |
advStats = (RCL_StatsAdvScanInit) { 0 };
advStats.config.accumulate = true;
/* AuxPtr to be used for the ADV_EXT_IND indicating that the auxiliary packet (i.e. AUX_ADV_IND) will be sent on:
* BLE 2M PHY, channel 25, and as soon as possible.
*/
AuxPtr advExtAuxPtr = { 0U };
advExtAuxPtr.auxOffset = 0;
advExtAuxPtr.offsetUnits = 1;
advExtAuxPtr.auxPhy = 1;
advExtAuxPtr.ca = 0;
advExtAuxPtr.chIndex = 25;
/* SyncInfo to be sent in the AUX_ADV_IND to inform potential scanners about the characteristics of the
* periodic advertising event
*/
SyncInfo auxAdvSyncInfo = { 0U };
auxAdvSyncInfo.accessAddress = PER_ADV_ACCESS_ADDRESS;
auxAdvSyncInfo.crcInit = PER_ADV_CRC_INIT;
auxAdvSyncInfo.interval = 500; /* Indicating a periodic advertising interval of 500 x 1.25 [ms] = 625 [ms] */
auxAdvSyncInfo.offsetInfo.adjust = 0;
auxAdvSyncInfo.offsetInfo.base = 2400; /* Indicating an sync packet window offset of 2400 x 30 [us] = 72 [ms] */
auxAdvSyncInfo.offsetInfo.units = 0; /* 30 [us] offset units */
/* All RF channels of the periodic physical channel are used */
auxAdvSyncInfo.chMap.chMap0To7 = 0xFF;
auxAdvSyncInfo.chMap.chMap8To15 = 0xFF;
auxAdvSyncInfo.chMap.chMap16To23 = 0xFF;
auxAdvSyncInfo.chMap.chMap24To31 = 0xFF;
auxAdvSyncInfo.chMap.chMap32To36 = 0x1F;
auxAdvSyncInfo.sleepClockAccuracy = 4; /* Indicating a sleep clock accuracy of 51 ppm to 75 ppm */
auxAdvSyncInfo.periodicEventCounter = 0x78; /* paEventCounter value that applies for the AUX_SYNC_IND */
/* Tx buffers needed for ADV_EXT_IND and AUX_ADV_IND */
RCL_Buffer_TxBuffer *advExtTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer;
RCL_Buffer_TxBuffer *auxAdvTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer2;
/* Populate Tx buffer used for the ADV_EXT_IND that will be sent on all primary advertisement channels */
setAdvExtBuffer(advExtTxBuffer, &advExtAuxPtr);
/* ACAD of an AUX_ADV_IND contains the Periodic Advertising Timing Information */
SubEventInfo auxAdvSubEventInfo = { 0U };
/* According to BLE Core Specification, AUX_SYNC_SUBEVENT_RSP shall use the rspAA set
* in the Periodic Advertising Timing Information, which is different from the one set
* in the SyncInfo.
*/
auxAdvSubEventInfo.rspAA = PAWR_RESPONSE_ACCESS_ADDRESS;
auxAdvSubEventInfo.numSubevents = 3;
auxAdvSubEventInfo.subeventInterval = 30; /* 30 * 1.25ms = 37.5ms */
auxAdvSubEventInfo.responseSlotDelay = 5; /* 5 * 1.25ms = 6.25ms */
auxAdvSubEventInfo.responseSlotSpacing = 20; /* 20 * 0.125ms = 2.5ms */
/* Use a local array to avoid malloc since the size of the ADStructure flexible array member is known in this example */
uint8_t acadBuffer[sizeof(ADStructure) + sizeof(SubEventInfo)] = { 0U };
ADStructure *acadField = (ADStructure *)acadBuffer;
/* Plus one to count the AD Type */
acadField->length = sizeof(SubEventInfo) + 1;
acadField->adType = AD_TYPE_PAWR_TIMING_INFORMATION;
for (uint8_t i = 0; i < sizeof(SubEventInfo); i++)
{
acadField->adData[i] = ((uint8_t *)&auxAdvSubEventInfo)[i];
}
/* Populate Tx buffer used for the AUX_ADV_IND that will be sent on a secondary advertisement channel */
setAuxAdvPawrBuffer(auxAdvTxBuffer, &auxAdvSyncInfo, acadField, AUX_ADV_DATA_LEN);
advExtTxBuffer->state = RCL_BufferStatePending;
auxAdvTxBuffer->state = RCL_BufferStatePending;
RCL_TxBuffer_put(&advCtx.txBuffers, advExtTxBuffer);
RCL_TxBuffer_put(&advCtx.txBuffers, auxAdvTxBuffer);
/*====== Prepare PAwR Advertiser ======*/
/* Setup periodic advertiser command used for PAwR */
perAdvCtx.accessAddress = PER_ADV_ACCESS_ADDRESS;
perAdvCtx.crcInit = PER_ADV_CRC_INIT;
/* Per spec, the AA set in the Periodic Advertising Timing Information shall be different from the one set in the SyncInfo */
perAdvCtx.rspAA = auxAdvSubEventInfo.rspAA;
/* Channel selection is accomplished using Channel Selection Algorithm #2, and takes place at each periodic advertising subevent. */
perAdvCmd.channel = BLE_EXAMPLE_PAWR_CHANNEL;
perAdvCmd.config.perAdvType = RCL_CMD_BLE_PER_ADV_TYPE_PAWR;
perAdvCmd.config.pawrMode = RCL_CMD_BLE_PAWR_MODE_ZERO;
/* Expect 3 AUX_SYNC_SUBEVENT_RSP in each subevent
* Assume the peer PAwR scanners subscribe response slots 0, 1, and 2 for simplicity
*/
perAdvCmd.expSubeventRspNum = 3;
perAdvCmd.responseSlotDelay = auxAdvSubEventInfo.responseSlotDelay;
perAdvCmd.ctx = &perAdvCtx;
perAdvCmd.stats = &perAdvStats;
perAdvCmd.common.phyFeatures = advExtAuxPtr.auxPhy;
/* Run the PAwR advertiser with absolute start time */
perAdvCmd.common.scheduling = RCL_Schedule_AbsTime;
perAdvCmd.common.allowDelay = false;
perAdvCmd.common.runtime.callback = pawrAdvCallback;
perAdvCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value |
perAdvCmd.common.runtime.lrfCallbackMask.value = LRF_EventTxDone.value;
/* Graceful stop time is calculated based on the response slot subscription
* For example:
* - response slot 0, 1 and 2 are subscribed, then the graceful stop time is at least
* (responseSlotDelay * 1250us + 2 * responseSlotSpacing * 125us)
* - response slot 0, 2, and 26 are subscribed, then this PAwR advertiser in mode 0 should receive
* the first two responses. The response in slot 26 should be received by scheduling a separate
* RCL_CmdBle5GenericRx to save power. Therefore, the graceful stop time is at least
* (responseSlotDelay * 1250us + 2 * responseSlotSpacing * 125us)
*/
perAdvCmd.common.timing.relGracefulStopTime = RCL_SCHEDULER_SYSTIM_US(auxAdvSubEventInfo.responseSlotDelay * PAwR_SUBEVENT_RESPONSE_SLOT_DELAY_US +
(2 * auxAdvSubEventInfo.responseSlotSpacing * PAwR_SUBEVENT_RESPONSE_SLOT_SPACING_US));
/* Prepare a Tx buffer for AUX_SYNC_SUBEVENT_IND */
RCL_Buffer_TxBuffer *auxSyncSubEventTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer3;
setAuxSyncSubEventBuffer(auxSyncSubEventTxBuffer, acadField, AUX_SYNC_SUBEVENT_IND_ADV_DATA_LEN);
auxSyncSubEventTxBuffer->state = RCL_BufferStatePending;
RCL_TxBuffer_put(&perAdvCtx.txBuffers, auxSyncSubEventTxBuffer);
/* Prepare an Rx buffer for AUX_SYNC_SUBEVENT_RSP */
uint32_t rxBuffer[RCL_MultiBuffer_len_u32(BLE_TEST_MULTI_BUF_LEN)];
RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *)rxBuffer;
RCL_MultiBuffer_init(multiBuffer, sizeof(rxBuffer));
RCL_MultiBuffer_put(&perAdvCtx.rxBuffers, multiBuffer);
/*====== Run Radio Commands ======*/
/* Submit command wait for it to conclude */
uint32_t startTimeAdvCmd = RCL_Scheduler_getCurrentTime() + RCL_SCHEDULER_SYSTIM_US(ADV_START_DELAY_US);
advCmd.common.timing.absStartTime = startTimeAdvCmd;
RCL_Command_submit(h, &advCmd);
RCL_Command_pend(&advCmd);
/* Calculate the start time of the PAwR advertiser command based on the start time of the AUX_ADV_IND,
* which is based on the start time of the advertiser command, the time delta to the transmitting of
* the AUX_ADV_IND, the primary and secondary PHYs, and the channel map.
*/
uint32_t startTimeAuxAdvInd = startTimeAdvCmd + RCL_BLE5_getAuxAdvStartTimeDelta(PHY_FEATURES,
PHY_FEATURES,
CH_MAP,
ADV_EXT_IND_PAYLOAD_LEN);
uint32_t startTimePawrAdvCmd = startTimeAuxAdvInd + RCL_SCHEDULER_SYSTIM_US(auxAdvSyncInfo.offsetInfo.units ?
auxAdvSyncInfo.offsetInfo.base * BLE_AUX_OFFSET_300_US :
auxAdvSyncInfo.offsetInfo.base * BLE_AUX_OFFSET_30_US);
/* Pend on the completion of the PAwR advertiser command in this example */
perAdvCmd.common.timing.absStartTime = startTimePawrAdvCmd;
RCL_Command_submit(h, &perAdvCmd);
RCL_Command_pend(&perAdvCmd);
}

To operate in Mode 0, configure the periodic advertiser radio command with perAdvType set to RCL_CMD_BLE_PER_ADV_TYPE_PAWR and pawrMode set to RCL_CMD_BLE_PAWR_MODE_ZERO.

As previously described, the advertiser's Tx buffer for the AUX_ADV_IND must include both the required SyncInfo and the ACAD field containing the Periodic Advertising Response Timing Information. These elements enable scanners to synchronize with periodic advertising events and interpret the response slot configuration. The helper function referenced in the earlier code snippet illustrates how to construct this Tx buffer.

typedef struct
{
uint16_t base: 13;
uint16_t units: 1;
uint16_t adjust: 1;
uint16_t reserved: 1;
} packetOffsetInfo;
typedef struct
{
uint8_t chMap0To7;
uint8_t chMap8To15;
uint8_t chMap16To23;
uint8_t chMap24To31;
uint8_t chMap32To36: 5;
uint8_t reserved: 3;
} channelMap;
typedef struct
{
packetOffsetInfo offsetInfo;
uint16_t interval;
channelMap chMap;
uint8_t sleepClockAccuracy;
uint32_t accessAddress;
uint32_t crcInit;
uint16_t periodicEventCounter;
} SyncInfo;
typedef struct
{
uint8_t length;
uint8_t adType;
uint8_t adData[];
} ADStructure;
typedef struct __attribute__((packed))
{
uint32_t rspAA;
uint8_t numSubevents;
uint8_t subeventInterval;
uint8_t responseSlotDelay;
uint8_t responseSlotSpacing;
} SubEventInfo;
static void setAuxAdvPawrBuffer(RCL_Buffer_TxBuffer *buffer, SyncInfo *auxAdvSyncInfo, ADStructure *acad, uint8_t advDataLen)
{
/* Include extra octet corresponding to the extended header length and AdvMode */
uint8_t payloadLength = 1 + AUX_ADV_PAWR_HDR_LEN + advDataLen;
uint8_t *txData;
txData = RCL_TxBuffer_init(buffer, NUM_PAD, BLE_HDR_LEN, payloadLength);
txData[0] = BLE_HDR_AUX_ADV_IND;
txData[1] = payloadLength;
txData[2] = (BLE_ADV_MODE_NONCONN_NONSCAN << 6) | AUX_ADV_PAWR_HDR_LEN;
txData[3] = BLE5_EXT_HDR_FLAG_ADVA_BM | BLE5_EXT_HDR_FLAG_ADI_BM | BLE5_EXT_HDR_FLAG_SYNC_INFO_BM;
/* AdvA */
txData[4] = 0xAA;
txData[5] = 0xBB;
txData[6] = 0xCC;
txData[7] = 0xDD;
txData[8] = 0xEE;
txData[9] = 0x01;
/* ADI */
txData[10] = 0;
txData[11] = 0;
/* SyncInfo */
txData[12] = auxAdvSyncInfo->offsetInfo.base & 0xFF;
txData[13] = ((auxAdvSyncInfo->offsetInfo.base >> 8) & 0x1F) |
((auxAdvSyncInfo->offsetInfo.units & 0x01) << 5) |
((auxAdvSyncInfo->offsetInfo.adjust & 0x01) << 6);
txData[14] = (auxAdvSyncInfo->interval & 0xFF);
txData[15] = (auxAdvSyncInfo->interval >> 8);
txData[16] = (auxAdvSyncInfo->chMap.chMap0To7);
txData[17] = (auxAdvSyncInfo->chMap.chMap8To15);
txData[18] = (auxAdvSyncInfo->chMap.chMap16To23);
txData[19] = (auxAdvSyncInfo->chMap.chMap24To31);
txData[20] = (auxAdvSyncInfo->chMap.chMap32To36 & 0x1F) |
((auxAdvSyncInfo->sleepClockAccuracy & 0x07) << 5);
txData[21] = (auxAdvSyncInfo->accessAddress & 0xFF);
txData[22] = (auxAdvSyncInfo->accessAddress >> 8) & 0xFF;
txData[23] = (auxAdvSyncInfo->accessAddress >> 16) & 0xFF;
txData[24] = (auxAdvSyncInfo->accessAddress >> 24) & 0xFF;
txData[25] = (auxAdvSyncInfo->crcInit & 0xFF);
txData[26] = (auxAdvSyncInfo->crcInit >> 8) & 0xFF;
txData[27] = (auxAdvSyncInfo->crcInit >> 16) & 0xFF;
txData[28] = (auxAdvSyncInfo->periodicEventCounter & 0xFF);
txData[29] = (auxAdvSyncInfo->periodicEventCounter >> 8);
/* ACAD */
if (acad != NULL && acad->length > 0)
{
/* AD Structure */
txData[30] = acad->length;
txData[31] = acad->adType;
for (uint8_t i = 0; i < (acad->length - 1); i++)
{
txData[32 + i] = acad->adData[i];
}
}
/* AdvData */
if (advDataLen > 0)
{
uint8_t advDataStartIndex = 30 + ((acad != NULL && acad->length > 0) ? (acad->length + 1) : 0);
for(uint32_t i = 0; i < advDataLen; i++)
{
txData[advDataStartIndex + i] = i & 0xFF;
}
}
}

PAwR Advertiser Mode 1

pawr_advertising_mode_one_example.png
Example of Periodic Advertising with Responses: PAwR Advertiser Mode 1 and Generic Rx

Mode 1 is intended for scenarios where there is a more generous timing margin between the end of the AUX_SYNC_SUBEVENT_IND transmission and the start of the first response slot. For example, as shown in cases 3 and 4 of the timing examples table, a relatively large time window is available. Although the PAwR advertiser is often mains-powered, it is still advantageous to minimize power consumption by limiting the duration the receiver is active.

In Mode 1, after transmitting the AUX_SYNC_SUBEVENT_IND PDU, the PAwR advertiser operation concludes. One or more RCL_CMD_BLE5_GENERIC_RX_t commands can then be scheduled to open the receiver window just before the response slots to which peer PAwR scanners have subscribed. This approach allows the receiver to be active only when necessary, further optimizing power efficiency.

The RCL_CMD_BLE5_GENERIC_RX_t command supports receiving a specified number of AUX_SYNC_SUBEVENT_RSP PDUs, similar to Mode 0. To receive these PDUs, a different access address must be configured in the accessAddress field of the RCL_CTX_GENERIC_RX_t context structure.

After successful execution of the RCL_CMD_BLE5_ADV_t command, periodic advertising establishment is complete and PAwR advertising can proceed. The following steps outline the process to perform PAwR advertising in Mode 1:

  1. Initialize and configure a RCL_CMD_BLE5_PER_ADV_t command.
  2. Use the start time of the RCL_CMD_BLE5_ADV_t command, RCL_BLE5_getAuxAdvStartTimeDelta, and the SyncInfo to set up the start time of the RCL_CMD_BLE5_PER_ADV_t command.
  3. Provide the necessary Tx buffer(s) that have been initialized and configured to contain the AUX_SYNC_SUBEVENT_IND PDU.
  4. Submit the command with RCL_Command_submit, and 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 submitting new commands.
  5. Initialize and configure one or more RCL_CMD_BLE5_GENERIC_RX_t commands, depending on the response slot subscription.
  6. Provide the necessary Multibuffer(s) that have been initialized and configured to receive the AUX_SYNC_SUBEVENT_RSP PDUs.
  7. For each RCL_CMD_BLE5_GENERIC_RX_t command, use the start time of the RCL_CMD_BLE5_PER_ADV_t command, along with the Periodic Advertising Response Slot Delay, Periodic Advertising Response Slot Spacing, and the response slot subscription to set up the appropriate start time.
  8. Use the start time of the previous RCL_CMD_BLE5_PER_ADV_t command, along with the Periodic Advertising Subevent Interval and the periodic advertising interval, to schedule the next PAwR advertising command.

The following code snippet shows how to configure the PAwR advertiser in Mode 1 and run periodic advertising with responses as an advertiser:

void runPAwRAdvertiserMode1(void)
{
RCL_Handle h = RCL_open(&rclClient, &LRF_configBle);
/*====== Prepare Extended Advertiser ======*/
/* Setup advertiser command handler used for periodic advertising establishment */
advCmd.chanMap = CH_MAP;
advCmd.common.phyFeatures = PHY_FEATURES;
advCmd.ctx = &advCtx;
advCmd.stats = &advStats;
advCmd.common.scheduling = RCL_Schedule_AbsTime;
advCmd.common.runtime.callback = advCallback;
advCmd.common.runtime.lrfCallbackMask.value = 0;
advCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value |
advStats = (RCL_StatsAdvScanInit) { 0 };
advStats.config.accumulate = true;
/* AuxPtr to be used for the ADV_EXT_IND indicating that the auxiliary packet (i.e. AUX_ADV_IND) will be sent on:
* BLE 2M PHY, channel 25, and as soon as possible.
*/
AuxPtr advExtAuxPtr = { 0U };
advExtAuxPtr.auxOffset = 0;
advExtAuxPtr.offsetUnits = 1;
advExtAuxPtr.auxPhy = 1;
advExtAuxPtr.ca = 0;
advExtAuxPtr.chIndex = 25;
/* SyncInfo to be send in the AUX_ADV_IND to inform potential scanners about the characteristics of the
* periodic advertising event
*/
SyncInfo auxAdvSyncInfo = { 0U };
auxAdvSyncInfo.accessAddress = PER_ADV_ACCESS_ADDRESS;
auxAdvSyncInfo.crcInit = PER_ADV_CRC_INIT;
auxAdvSyncInfo.interval = 500; /* Indicating a periodic advertising interval of 500 x 1.25 [ms] = 625 [ms] */
auxAdvSyncInfo.offsetInfo.adjust = 0;
auxAdvSyncInfo.offsetInfo.base = 2400; /* Indicating an sync packet window offset of 2400 x 30 [us] = 72 [ms] */
auxAdvSyncInfo.offsetInfo.units = 0; /* 30 [us] offset units */
/* All RF channels of the periodic physical channel are used */
auxAdvSyncInfo.chMap.chMap0To7 = 0xFF;
auxAdvSyncInfo.chMap.chMap8To15 = 0xFF;
auxAdvSyncInfo.chMap.chMap16To23 = 0xFF;
auxAdvSyncInfo.chMap.chMap24To31 = 0xFF;
auxAdvSyncInfo.chMap.chMap32To36 = 0x1F;
auxAdvSyncInfo.sleepClockAccuracy = 4; /* Indicating a sleep clock accuracy of 51 ppm to 75 ppm */
auxAdvSyncInfo.periodicEventCounter = 0x78; /* paEventCounter value that applies for the AUX_SYNC_IND */
/* Tx buffers needed for ADV_EXT_IND and AUX_ADV_IND */
RCL_Buffer_TxBuffer *advExtTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer;
RCL_Buffer_TxBuffer *auxAdvTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer2;
/* Populate Tx buffer used for the ADV_EXT_IND that will be sent on all primary advertisement channels */
setAdvExtBuffer(advExtTxBuffer, &advExtAuxPtr);
/* ACAD of an AUX_ADV_IND contains the Periodic Advertising Timing Information */
SubEventInfo auxAdvSubEventInfo = { 0U };
/* According to BLE Core Specification, AUX_SYNC_SUBEVENT_RSP shall use the rspAA set
* in the Periodic Advertising Timing Information, which is different from the one set
* in the SyncInfo.
*/
auxAdvSubEventInfo.rspAA = PAWR_RESPONSE_ACCESS_ADDRESS;
auxAdvSubEventInfo.numSubevents = 3;
auxAdvSubEventInfo.subeventInterval = 30; /* 30 * 1.25ms = 37.5ms */
auxAdvSubEventInfo.responseSlotDelay = 5; /* 5 * 1.25ms = 6.25ms */
auxAdvSubEventInfo.responseSlotSpacing = 20; /* 20 * 0.125ms = 2.5ms */
/* Use a local array to avoid malloc since the size of the ADStructure flexible array member is known for this example */
uint8_t acadBuffer[sizeof(ADStructure) + sizeof(SubEventInfo)] = { 0U };
ADStructure *acadField = (ADStructure *)acadBuffer;
/* Plus one to count the AD Type */
acadField->length = sizeof(SubEventInfo) + 1;
acadField->adType = AD_TYPE_PAWR_TIMING_INFORMATION;
for (uint8_t i = 0; i < sizeof(SubEventInfo); i++)
{
acadField->adData[i] = ((uint8_t *)&auxAdvSubEventInfo)[i];
}
/* Populate Tx buffer used for the AUX_ADV_IND that will be sent on a secondary advertisement channel */
setAuxAdvPawrBuffer(auxAdvTxBuffer, &auxAdvSyncInfo, acadField, AUX_ADV_DATA_LEN);
advExtTxBuffer->state = RCL_BufferStatePending;
auxAdvTxBuffer->state = RCL_BufferStatePending;
RCL_TxBuffer_put(&advCtx.txBuffers, advExtTxBuffer);
RCL_TxBuffer_put(&advCtx.txBuffers, auxAdvTxBuffer);
/*====== Prepare PAwR Advertiser ======*/
/* Setup periodic advertiser command used for PAwR */
perAdvCtx.accessAddress = PER_ADV_ACCESS_ADDRESS;
perAdvCtx.crcInit = PER_ADV_CRC_INIT;
/* Channel selection is accomplished using Channel Selection Algorithm #2, and takes place at each periodic advertising subevent. */
perAdvCmd.channel = BLE_EXAMPLE_PAWR_CHANNEL;
perAdvCmd.config.perAdvType = RCL_CMD_BLE_PER_ADV_TYPE_PAWR;
perAdvCmd.config.pawrMode = RCL_CMD_BLE_PAWR_MODE_ONE;
perAdvCmd.ctx = &perAdvCtx;
perAdvCmd.stats = &perAdvStats;
perAdvCmd.common.phyFeatures = advExtAuxPtr.auxPhy;
/* Run the PAwR advertiser with absolute start time */
perAdvCmd.common.scheduling = RCL_Schedule_AbsTime;
perAdvCmd.common.allowDelay = false;
perAdvCmd.common.runtime.callback = pawrAdvCallback;
perAdvCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value;
perAdvCmd.common.runtime.lrfCallbackMask.value = LRF_EventTxDone.value;
/* Prepare a Tx buffer for AUX_SYNC_SUBEVENT_IND */
RCL_Buffer_TxBuffer *auxSyncSubEventTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer3;
setAuxSyncSubEventBuffer(auxSyncSubEventTxBuffer, acadField, AUX_SYNC_SUBEVENT_IND_ADV_DATA_LEN);
auxSyncSubEventTxBuffer->state = RCL_BufferStatePending;
RCL_TxBuffer_put(&perAdvCtx.txBuffers, auxSyncSubEventTxBuffer);
/*====== Prepare Generic Rx ======*/
/* Setup Generic Rx command to receive AUX_SYNC_SUBEVENT_RSP PDUs */
genRxCtx.config.repeated = 1; /* Restart sync search after receiving */
genRxCtx.config.disableSync = 0;
genRxCtx.config.discardRxPackets = 0;
genRxCtx.accessAddress = auxAdvSubEventInfo.rspAA;
genRxCtx.crcInit = PER_ADV_CRC_INIT;
genRxCtx.maxPktLen = PAWR_AUX_SYNC_PKT_MAX_PAYLOAD;
genRxCtx.maxPkts = 3; /* Expect to receive 3 AUX_SYNC_SUBEVENT_RSP PDUs */
genRxStats.config.accumulate = true;
/* Per spec, AUX_SYNC_SUBEVENT_RSP PDUs are received on the same channel as AUX_SYNC_SUBEVENT_IND PDUs */
genRxCmd.channel = BLE_EXAMPLE_PAWR_CHANNEL;
genRxCmd.ctx = &genRxCtx;
genRxCmd.stats = &genRxStats;
genRxCmd.common.phyFeatures = advExtAuxPtr.auxPhy;
genRxCmd.common.scheduling = RCL_Schedule_AbsTime;
genRxCmd.common.allowDelay = false;
genRxCmd.common.runtime.callback = scanCallback; /* Re-use the same callback */
genRxCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value |
genRxCmd.common.runtime.lrfCallbackMask.value = 0;
/* Prepare an Rx buffer for AUX_SYNC_SUBEVENT_RSP PDUs */
uint32_t rxBuffer[RCL_MultiBuffer_len_u32(BLE_TEST_MULTI_BUF_LEN)];
RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *)rxBuffer;
RCL_MultiBuffer_init(multiBuffer, sizeof(rxBuffer));
RCL_MultiBuffer_put(&genRxCtx.rxBuffers, multiBuffer);
/* Graceful stop time is calculated based on the response slot subscription
* For example:
* - response slot 0, 1 and 2 are subscribed, then the graceful stop time is at least (2 * responseSlotSpacing * 125us)
* - response slot 10, 12, 14, 16 are subscribed, and only one Generic Rx is used to receive all responses, then
* the graceful stop time is at least (6 * responseSlotSpacing * 125us)
*
* In this example, assume the peer PAwR scanners subscribe response slots 0, 1, and 2 for simplicity.
*/
genRxCmd.common.timing.relGracefulStopTime = RCL_SCHEDULER_SYSTIM_US(2 * auxAdvSubEventInfo.responseSlotSpacing * PAwR_SUBEVENT_RESPONSE_SLOT_SPACING_US);
/*====== Run Radio Commands ======*/
/* Submit command and wait for it to conclude */
uint32_t startTimeAdvCmd = RCL_Scheduler_getCurrentTime() + RCL_SCHEDULER_SYSTIM_US(ADV_START_DELAY_US);
advCmd.common.timing.absStartTime = startTimeAdvCmd;
RCL_Command_submit(h, &advCmd);
RCL_Command_pend(&advCmd);
/* Calculate the start time of the PAwR advertiser command based on the start time of the AUX_ADV_IND,
* which is based on the start time of the advertiser command, the time delta to the transmitting of
* the AUX_ADV_IND, the primary and secondary PHYs, and the channel map.
*/
uint32_t startTimeAuxAdvInd = startTimeAdvCmd + RCL_BLE5_getAuxAdvStartTimeDelta(PHY_FEATURES,
PHY_FEATURES,
CH_MAP,
ADV_EXT_IND_PAYLOAD_LEN);
uint32_t startTimePawrAdvCmd = startTimeAuxAdvInd + RCL_SCHEDULER_SYSTIM_US(auxAdvSyncInfo.offsetInfo.units ?
auxAdvSyncInfo.offsetInfo.base * BLE_AUX_OFFSET_300_US :
auxAdvSyncInfo.offsetInfo.base * BLE_AUX_OFFSET_30_US);
/* Pend on the completion of the PAwR advertiser command in this example */
perAdvCmd.common.timing.absStartTime = startTimePawrAdvCmd;
RCL_Command_submit(h, &perAdvCmd);
RCL_Command_pend(&perAdvCmd);
/* Calculate the start time of the Generic Rx command based on the start time of the PAwR advertiser command */
uint32_t subEventRspSlotTime = (auxAdvSubEventInfo.responseSlotDelay * PAwR_SUBEVENT_RESPONSE_SLOT_DELAY_US) +
/* First response slot is subscribed */
(0 * auxAdvSubEventInfo.responseSlotSpacing * PAwR_SUBEVENT_RESPONSE_SLOT_SPACING_US);
uint32_t startTimeGenRxCmd = startTimePawrAdvCmd + RCL_SCHEDULER_SYSTIM_US(subEventRspSlotTime);
genRxCmd.common.timing.absStartTime = startTimeGenRxCmd;
/* Adjust start time to compensate for internal radio delay */
RCL_Command_submit(h, &genRxCmd);
RCL_Command_pend(&genRxCmd);
}

To operate in Mode 1, configure the periodic advertiser radio command with perAdvType set to RCL_CMD_BLE_PER_ADV_TYPE_PAWR and pawrMode set to RCL_CMD_BLE_PAWR_MODE_ONE.

PAwR Mode 2

Mode 2 is intended for creating connections with peer PAwR scanners. In this mode, the PAwR advertiser transmits an AUX_CONNECT_REQ PDU to initiate a connection and then automatically switches to receive mode to listen for the corresponding AUX_CONNECT_RSP. In this scenario, the advertiser assumes the role of initiator, while the scanner acts as the responder. As a result, the InitA field in the AUX_CONNECT_REQ contains the advertiser's address, and the AdvA field contains the scanner's address. Similarly, in the AUX_CONNECT_RSP, the AdvA field holds the scanner's address, and the TargetA field contains the advertiser's address.

After successful execution of the RCL_CMD_BLE5_ADV_t command, periodic advertising establishment is complete and PAwR advertising can proceed. The following steps outline the process to initiate a connection using PAwR advertising in Mode 2:

  1. Initialize and configure a RCL_CMD_BLE5_PER_ADV_t command.
  2. Use the start time of the RCL_CMD_BLE5_ADV_t command, RCL_BLE5_getAuxAdvStartTimeDelta, and the SyncInfo to set up the start time of the RCL_CMD_BLE5_PER_ADV_t command.
  3. Provide the necessary Tx buffer(s) that have been initialized and configured to contain the AUX_CONNECT_REQ PDU.
  4. Provide the necessary Multibuffer(s) that have been initialized and configured to receive the AUX_CONNECT_RSP PDU.
  5. Submit the command with RCL_Command_submit, and 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 submitting new commands.
  6. Upon the RCL_CMD_BLE5_PER_ADV_t command ending with connected status, use the timestamp of the received AUX_CONNECT_RSP PDU, along with the connection event timing parameters to schedule the RCL_CMD_BLE5_CONNECTION_t command for running connection events.

The following code snippet shows how to configure the PAwR advertiser in Mode 2 and initiate a connection as an advertiser:

void runPAwRAdvertiserMode2(void)
{
RCL_Handle h = RCL_open(&rclClient, &LRF_configBle);
/*====== Prepare Extended Advertiser ======*/
/* Setup advertiser command handler used for periodic advertising establishment */
advCmd.chanMap = CH_MAP;
advCmd.common.phyFeatures = PHY_FEATURES;
advCmd.ctx = &advCtx;
advCmd.stats = &advStats;
advCmd.common.scheduling = RCL_Schedule_AbsTime;
advCmd.common.runtime.callback = advCallback;
advCmd.common.runtime.lrfCallbackMask.value = 0;
advCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value |
advStats = (RCL_StatsAdvScanInit) { 0 };
advStats.config.accumulate = true;
/* AuxPtr to be used for the ADV_EXT_IND indicating that the auxiliary packet (i.e. AUX_ADV_IND) will be sent on:
* BLE 2M PHY, channel 25, and as soon as possible.
*/
AuxPtr advExtAuxPtr = { 0U };
advExtAuxPtr.auxOffset = 0;
advExtAuxPtr.offsetUnits = 1;
advExtAuxPtr.auxPhy = 1;
advExtAuxPtr.ca = 0;
advExtAuxPtr.chIndex = 25;
/* SyncInfo to be send in the AUX_ADV_IND to inform potential scanners about the characteristics of the
* periodic advertising event
*/
SyncInfo auxAdvSyncInfo = { 0U };
auxAdvSyncInfo.accessAddress = PER_ADV_ACCESS_ADDRESS;
auxAdvSyncInfo.crcInit = PER_ADV_CRC_INIT;
auxAdvSyncInfo.interval = 500; /* Indicating a periodic advertising interval of 500 x 1.25 [ms] = 625 [ms] */
auxAdvSyncInfo.offsetInfo.adjust = 0;
auxAdvSyncInfo.offsetInfo.base = 2400; /* Indicating an sync packet window offset of 2400 x 30 [us] = 72 [ms] */
auxAdvSyncInfo.offsetInfo.units = 0; /* 30 [us] offset units */
/* All RF channels of the periodic physical channel are used */
auxAdvSyncInfo.chMap.chMap0To7 = 0xFF;
auxAdvSyncInfo.chMap.chMap8To15 = 0xFF;
auxAdvSyncInfo.chMap.chMap16To23 = 0xFF;
auxAdvSyncInfo.chMap.chMap24To31 = 0xFF;
auxAdvSyncInfo.chMap.chMap32To36 = 0x1F;
auxAdvSyncInfo.sleepClockAccuracy = 4; /* Indicating a sleep clock accuracy of 51 ppm to 75 ppm */
auxAdvSyncInfo.periodicEventCounter = 0x78; /* paEventCounter value that applies for the AUX_SYNC_IND */
/* Tx buffers needed for ADV_EXT_IND and AUX_ADV_IND */
RCL_Buffer_TxBuffer *advExtTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer;
RCL_Buffer_TxBuffer *auxAdvTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer2;
/* Populate Tx buffer used for the ADV_EXT_IND that will be sent on all primary advertisement channels */
setAdvExtBuffer(advExtTxBuffer, &advExtAuxPtr);
/* ACAD of an AUX_ADV_IND contains the Periodic Advertising Timing Information */
SubEventInfo auxAdvSubEventInfo = { 0U };
/* According to BLE Core Specification, AUX_SYNC_SUBEVENT_RSP shall use the rspAA set
* in the Periodic Advertising Timing Information, which is different from the one set
* in the SyncInfo.
*/
auxAdvSubEventInfo.rspAA = PAWR_RESPONSE_ACCESS_ADDRESS;
auxAdvSubEventInfo.numSubevents = 3;
auxAdvSubEventInfo.subeventInterval = 30; /* 30 * 1.25ms = 37.5ms */
auxAdvSubEventInfo.responseSlotDelay = 5; /* 5 * 1.25ms = 6.25ms */
auxAdvSubEventInfo.responseSlotSpacing = 20; /* 20 * 0.125ms = 2.5ms */
/* Use a local array to avoid malloc since the size of the ADStructure flexible array member is known in this example */
uint8_t acadBuffer[sizeof(ADStructure) + sizeof(SubEventInfo)] = { 0U };
ADStructure *acadField = (ADStructure *)acadBuffer;
/* Plus one to count the AD Type */
acadField->length = sizeof(SubEventInfo) + 1;
acadField->adType = AD_TYPE_PAWR_TIMING_INFORMATION;
for (uint8_t i = 0; i < sizeof(SubEventInfo); i++)
{
acadField->adData[i] = ((uint8_t *)&auxAdvSubEventInfo)[i];
}
/* Populate Tx buffer used for the AUX_ADV_IND that will be sent on a secondary advertisement channel */
setAuxAdvPawrBuffer(auxAdvTxBuffer, &auxAdvSyncInfo, acadField, AUX_ADV_DATA_LEN);
advExtTxBuffer->state = RCL_BufferStatePending;
auxAdvTxBuffer->state = RCL_BufferStatePending;
RCL_TxBuffer_put(&advCtx.txBuffers, advExtTxBuffer);
RCL_TxBuffer_put(&advCtx.txBuffers, auxAdvTxBuffer);
/*====== Prepare PAwR Advertiser ======*/
/* Setup periodic advertiser command used for PAwR */
DeviceAddr advA = (DeviceAddr) { .addrType = 0, .addrByte = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06} };
DeviceAddr initA = (DeviceAddr) { .addrType = 0, .addrByte = {0x06, 0x05, 0x04, 0x03, 0x02, 0x01} };
perAdvCtx.accessAddress = PER_ADV_ACCESS_ADDRESS;
perAdvCtx.crcInit = PER_ADV_CRC_INIT;
perAdvCtx.ownA[0] = initA.halfword[0];
perAdvCtx.ownA[1] = initA.halfword[1];
perAdvCtx.ownA[2] = initA.halfword[2];
perAdvCtx.addrType.own = initA.addrType;
perAdvCtx.peerA[0] = advA.halfword[0];
perAdvCtx.peerA[1] = advA.halfword[1];
perAdvCtx.peerA[2] = advA.halfword[2];
perAdvCtx.addrType.peer = advA.addrType;
/* Channel selection is accomplished using Channel Selection Algorithm #2, and takes place at each periodic advertising subevent. */
perAdvCmd.channel = BLE_EXAMPLE_PAWR_CHANNEL;
perAdvCmd.config.perAdvType = RCL_CMD_BLE_PER_ADV_TYPE_PAWR;
perAdvCmd.config.pawrMode = RCL_CMD_BLE_PAWR_MODE_TWO;
perAdvCmd.ctx = &perAdvCtx;
perAdvCmd.stats = &perAdvStats;
perAdvCmd.common.phyFeatures = advExtAuxPtr.auxPhy;
/* Run the PAwR advertiser with absolute start time */
perAdvCmd.common.scheduling = RCL_Schedule_AbsTime;
perAdvCmd.common.allowDelay = false;
perAdvCmd.common.runtime.callback = pawrAdvCallback;
perAdvCmd.common.runtime.rclCallbackMask.value = RCL_EventLastCmdDone.value |
perAdvCmd.common.runtime.lrfCallbackMask.value = LRF_EventTxDone.value;
/* Prepare a Tx buffer for AUX_CONNECT_REQ */
RCL_Buffer_TxBuffer *auxConnReqTxBuffer = (RCL_Buffer_TxBuffer *)txBuffer3;
setAuxConnReqBuffer(auxConnReqTxBuffer, &advA, &initA);
auxConnReqTxBuffer->state = RCL_BufferStatePending;
RCL_TxBuffer_put(&perAdvCtx.txBuffers, auxConnReqTxBuffer);
/* Prepare an Rx buffer for AUX_CONNECT_RSP */
uint32_t rxBuffer[RCL_MultiBuffer_len_u32(BLE_TEST_MULTI_BUF_LEN)];
RCL_MultiBuffer *multiBuffer = (RCL_MultiBuffer *)rxBuffer;
RCL_MultiBuffer_init(multiBuffer, sizeof(rxBuffer));
RCL_MultiBuffer_put(&perAdvCtx.rxBuffers, multiBuffer);
/*====== Run Radio Commands ======*/
/* Submit command and wait for it to conclude */
uint32_t startTimeAdvCmd = RCL_Scheduler_getCurrentTime() + RCL_SCHEDULER_SYSTIM_US(ADV_START_DELAY_US);
advCmd.common.timing.absStartTime = startTimeAdvCmd;
RCL_Command_submit(h, &advCmd);
RCL_Command_pend(&advCmd);
/* Calculate the start time of the PAwR advertiser command based on the start time of the AUX_ADV_IND,
* which is based on the start time of the advertiser command, the time delta to the transmitting of
* the AUX_ADV_IND, the primary and secondary PHYs, and the channel map.
*/
uint32_t startTimeAuxAdvInd = startTimeAdvCmd + RCL_BLE5_getAuxAdvStartTimeDelta(PHY_FEATURES,
PHY_FEATURES,
CH_MAP,
ADV_EXT_IND_PAYLOAD_LEN);
uint32_t startTimePawrAdvCmd = startTimeAuxAdvInd + RCL_SCHEDULER_SYSTIM_US(auxAdvSyncInfo.offsetInfo.units ?
auxAdvSyncInfo.offsetInfo.base * BLE_AUX_OFFSET_300_US :
auxAdvSyncInfo.offsetInfo.base * BLE_AUX_OFFSET_30_US);
/* Pend on the completion of the PAwR advertiser command in this example */
perAdvCmd.common.timing.absStartTime = startTimePawrAdvCmd;
RCL_Command_submit(h, &perAdvCmd);
RCL_Command_pend(&perAdvCmd);
/* PAwR advertiser command can ends with the connect status
* which means the advertiser has sent an AUX_CONNECT_REQ and received an AUX_CONNECT_RSP
* to create the connection with the scanner successfully
*/
if (perAdvCmd.common.status == RCL_CommandStatus_Connect)
{
/*====== Calculate the first connection event start time ======*/
List_List finishedBuffers;
List_clearList(&finishedBuffers);
RCL_Buffer_DataEntry *auxConnRspPkt = RCL_MultiBuffer_RxEntry_get(&perAdvCtx.rxBuffers, &finishedBuffers);
uint32_t auxConnRspReceivedTime = RCL_BLE5_getRxTimestamp(auxConnRspPkt);
uint32_t firstConnEventStartTime = calCentralConnEventStartTime(auxConnRspReceivedTime, perAdvCmd.common.phyFeatures, PAWR_CONNECTION_WINOFFSET);
/* Use the variable if needed, otherwise silence unused warning: */
(void) firstConnEventStartTime;
/* Connection created, do something, e.g. run connection events */
}
}

To operate in Mode 2, configure the periodic advertiser radio command with perAdvType set to RCL_CMD_BLE_PER_ADV_TYPE_PAWR and pawrMode set to RCL_CMD_BLE_PAWR_MODE_TWO.

The previous code snippet demonstrates how to calculate the start time for the first connection event (i.e., the RCL_CMD_BLE5_CONNECTION_t command) using the timestamp of the received AUX_CONNECT_RSP PDU. The calCentralConnEventStartTime function performs this calculation by considering the reception timestamp, PHY settings, and the connection window offset.

static uint32_t getExtTransmitWindowDelay(uint16_t phyFeatures)
{
switch (phyFeatures)
{
case RCL_PHY_FEATURE_SUB_PHY_CODED_BLE | RCL_PHY_FEATURE_CODED_TX_RATE_S8_BLE:
case RCL_PHY_FEATURE_SUB_PHY_CODED_BLE | RCL_PHY_FEATURE_CODED_TX_RATE_S2_BLE:
return RCL_SCHEDULER_SYSTIM_US(3750U); /* 3.75ms */
case RCL_PHY_FEATURE_SUB_PHY_1_MBPS_BLE:
case RCL_PHY_FEATURE_SUB_PHY_2_MBPS_BLE:
default:
return RCL_SCHEDULER_SYSTIM_US(2500U); /* 2.5ms */
}
}
static uint32_t calCentralConnEventStartTime(uint32_t auxConnRspTimestamp, uint16_t phyFeatures, uint16_t winOffset)
{
uint32_t connEventStartTime = auxConnRspTimestamp;
/* Start time of the first connection event is relative to the end of AUX_CONNECT_REQ
* auxConnRspTimestamp is the timestamp when the AUX_CONNECT_RSP is received
* Subtract the T_IFS duration
*/
connEventStartTime -= RCL_SCHEDULER_SYSTIM_US(150U);
connEventStartTime += RCL_SCHEDULER_SYSTIM_US((uint32_t) winOffset * 1250U);
connEventStartTime += getExtTransmitWindowDelay(phyFeatures);
/* Ensures the central starts the connection event at the middle of the transmit window
* providing the maximum tolerance for clock drift on both sides */
connEventStartTime += RCL_SCHEDULER_SYSTIM_US(1250U >> 1U);
return connEventStartTime;
}

Architecture

The life cycle of the periodic advertiser command handler is influenced by the type of the periodic advertising event, whether it is periodic advertising without responses or periodic advertising with responses.

For periodic advertising without responses, the life cycle of the periodic advertiser command handler depends on the number of packets that are part of the periodic advertising event. The command handler requires at least one Tx buffer in the buffer list at command start. This buffer will be inspected to determine if an AuxPtr has been provided, and based on this, the operation will either conclude after transmitting the packet or schedule a new operation corresponding to the auxiliary packet.

For periodic advertising with responses, the life cycle of the periodic advertiser command handler depends on the selected PAwR mode:

  • In Mode 1, the command handler completes its operation after transmitting the AUX_SYNC_SUBEVENT_IND PDU.
  • In Mode 2, the command handler concludes after transmitting the AUX_CONNECT_REQ PDU and successfully receiving the corresponding AUX_CONNECT_RSP PDU.
  • In Mode 0, the command handler transmits the AUX_SYNC_SUBEVENT_IND PDU and then automatically switches to receive mode, listening for the configured number of AUX_SYNC_SUBEVENT_RSP PDUs before ending the operation.

It's worth mentioning that only non-connectable/non-scannable PDUs can be sent with the periodic advertising command, and other PDUs will be rejected and the command will end indicating a Tx buffer corruption.

Periodic Advertising without Responses

RCL Event (In) Description
RCL_EventSetup Setup has been performed
RCL_EventTimerStart Timer-based start signalled
RCL_EventGracefulStop Graceful stop has been observed
RCL_EventHardStop Hard stop has been observed
RCL Event (Out) Description
RCL_EventLastCmdDone The RCL is finished with the command
RCL_EventCmdStarted Command handler has accepted and started executing
RCL_EventTxBufferFinished An Tx buffer is finished
LRF Event Description
LRF_EventOpDone The PBE operation has finished
LRF_EventOpError Something went wrong. Cause located in the PBE ENDCAUSE register

Periodic Advertising with Responses - Mode 0

RCL Event (In) Description
RCL_EventSetup Setup has been performed
RCL_EventTimerStart Timer-based start signalled
RCL_EventGracefulStop Graceful stop has been observed
RCL_EventHardStop Hard stop has been observed
RCL_EventRxBufferUpdateRx buffer has been updated
RCL Event (Out) Description
RCL_EventLastCmdDone The RCL is finished with the command
RCL_EventCmdStarted Command handler has accepted and started executing
RCL_EventTxBufferFinished An Tx buffer is finished
RCL_EventRxBufferFinished An Rx buffer is finished
RCL_EventRxEntryAvail An Rx entry is available
LRF Event Description
LRF_EventOpDone The PBE operation has finished
LRF_EventOpError Something went wrong. Cause located in the PBE ENDCAUSE register
Normal completion if the expected number of responses has been received, due to LRF_sendHardStop
LRF_EventRxOk Packet received with CRC OK and not to be ignored by the MCU
LRF_EventRxNok Packet received with CRC error
LRF_EventRxIgnored Packet received, but may be ignored by MCU
LRF_EventRxBufFull Packet received which did not fit in the Rx FIFO and was not to be discarded

Periodic Advertising with Responses - Mode 1

RCL Event (In) Description
RCL_EventSetup Setup has been performed
RCL_EventTimerStart Timer-based start signalled
RCL_EventGracefulStop Graceful stop has been observed
RCL_EventHardStop Hard stop has been observed
RCL Event (Out) Description
RCL_EventLastCmdDone The RCL is finished with the command
RCL_EventCmdStarted Command handler has accepted and started executing
RCL_EventTxBufferFinished An Tx buffer is finished
LRF Event Description
LRF_EventOpDone The PBE operation has finished
LRF_EventOpError Something went wrong. Cause located in the PBE ENDCAUSE register

Periodic Advertising with Responses - Mode 2

RCL Event (In) Description
RCL_EventSetup Setup has been performed
RCL_EventTimerStart Timer-based start signalled
RCL_EventGracefulStop Graceful stop has been observed
RCL_EventHardStop Hard stop has been observed
RCL_EventRxBufferUpdateRx buffer has been updated
RCL Event (Out) Description
RCL_EventLastCmdDone The RCL is finished with the command
RCL_EventCmdStarted Command handler has accepted and started executing
RCL_EventTxBufferFinished An Tx buffer is finished
RCL_EventRxBufferFinished An Rx buffer is finished
RCL_EventRxEntryAvail An Rx entry is available
LRF Event Description
LRF_EventOpDone The PBE operation has finished
LRF_EventOpError Something went wrong. Cause located in the PBE ENDCAUSE register
LRF_EventRxOk Packet received with CRC OK and not to be ignored by the MCU
LRF_EventRxNok Packet received with CRC error
LRF_EventRxIgnored Packet received, but may be ignored by MCU
LRF_EventRxBufFull Packet received which did not fit in the Rx FIFO and was not to be discarded