Generic Access Profile (GAP) Layer

The GAP layer manages connections, security, and bonded devices.

The GAP layer APIs are built on top of the Host-Controller Interface (HCI), the Security Manager Protocol (SMP), and the Device database.

GAP defines four possible roles that a Bluetooth Low Energy device may have in a Bluetooth Low Energy system:

  • Central

    • Scans for advertisers (Peripherals and Broadcasters)

    • Initiates connection to Peripherals; Central at Link Layer (LL) level

    • Usually acts as a GATT Client, but can also contain a GATT Database itself

  • Peripheral

    • Advertises and accepts connection requests from Central devices; LL Peripheral

    • Usually contains a GATT Database and acts as a GATT Server, but may also be a Client

  • Observer

    • Scans for advertisers, but does not initiate connections; Transmit is optional

  • Broadcaster

    • Advertises, but does not accept connection requests from Central devices; Receive is optional

Figure 1 illustrates the generic GAP topology.

Peripheral setup

The Peripheral starts advertising and waits for scan and connection requests from other Central devices.

Advertising

Before starting advertising, the advertising parameters should be configured. Otherwise, the following defaults are used.

**\#define** gGapDefaultAdvertisingParameters_d \
{ \
   /* minInterval */     gGapAdvertisingIntervalDefault_c, \
   /* maxInterval */     gGapAdvertisingIntervalDefault_c, \
   /* advertisingType */ gConnectableUndirectedAdv_c, \
   /* addressType */     gBleAddrTypePublic_c, \
   /* peerAddressType */  gBleAddrTypePublic_c, \
   /* peerAddress */     {0U, 0U, 0U, 0U, 0U, 0U}, \
   /* channelMap */      
                        (gapAdvertisingChannelMapFlags_t)gGapAdvertisingChannelMapDefault_c,  \
   /* filterPolicy */    gProcessAll_c \
}

To set different advertising parameters, a gapAdvertisingParameters_t structure should be allocated and initialized with defaults. Then, the necessary fields may be modified.

After that, the following function should be called:

bleResult_t **Gap\_SetAdvertisingParameters**
(
    const gapAdvertisingParameters_t *     pAdvertisingParameters
);

The application should listen to the gAdvertisingParametersSetupComplete_c generic event.

Next, the advertising data should be configured and, if the advertising type supports active scanning, the scan response data should also be configured. If either of these is not configured, they are defaulted to empty data.

The function used to configure the advertising and/or scan response data is shown here:

bleResult_t **Gap\_SetAdvertisingData**
(
  const gapAdvertisingData_t *     pAdvertisingData,
  const gapScanResponseData_t *    pScanResponseData
);

Either of the two pointers may be NULL, in which case they are ignored (the corresponding data is left as it was previously configured, or empty if it has never been set), but not both at the same time.

The application should listen to the gAdvertisingDataSetupComplete_c generic event.

After all the necessary setup is done, advertising may be started with this function:

bleResult_t **Gap\_StartAdvertising**
(
    gapAdvertisingCallback_t advertisingCallback,
    gapConnectionCallback_t connectionCallback
);

The advertising callback is used to receive advertising events (advertising state changed or advertising command failed), while the connection callback is only used if a connection is established during advertising.

The connection callback is the same as the callback used by the Central when calling the Gap_Connect function.

When using the common application structure, the application can use the following API defined in app_conn.h:

bleResult_t **BluetoothLEHost\_StartAdvertising**
(
    appAdvertisingParams_t   *pAdvParams,
    gapAdvertisingCallback_t pfAdvertisingCallback,
    gapConnectionCallback_t  pfConnectionCallback
);

The API goes through the steps of setting the advertising data and parameters. Events from the Host task are treated in the App_AdvertiserHandler() function, implemented in app_advertiser.c. To set the advertising parameters and data BluetoothLEHost_StartAdvertising requires a parameter of the following type:

typedef struct appAdvertisingParams_tag { gapAdvertisingParameters_t *pGapAdvParams; /*!< Pointer to the GAP advertising parameters */ const gapAdvertisingData_t *pGapAdvData; /*!< Pointer to the GAP advertising data */ const gapScanResponseData_t *pScanResponseData; /*!< Pointer to the scan response data */ } appAdvertisingParams_t;

If a Central initiates a connection to this Peripheral, the gConnEvtConnected_c connection event is triggered.

To stop advertising while the Peripheral has not yet received any connection requests, use this function:

bleResult_t **Gap\_StopAdvertising** (**void**);

This function should not be called after the Peripheral enters a connection, as the advertising automatically stops in this case.

Parent topic:Peripheral setup

Pairing and bonding (peripheral)

After a connection has been established to a Central, the Peripheral’s role regarding security is a passive one. It is the responsibility of the Central device to start the pairing process. In case, the devices have already bonded in the past, the Central encrypts the link using the shared LTK.

The Peripheral sends error responses (at ATT level) with proper error code if the Central attempts to access sensitive data without authenticating. Examples of such error responses are: Insufficient Authentication, Insufficient Encryption, Insufficient Authorization, and so on. Therefore, it indicates to the Central that it needs to perform security procedures.

All security checks are performed internally by the GAP module and the security error responses are sent automatically. All the application developer needs to do is register the security requirements.

First, when building the GATT Database (see Creating GATT database), the sensitive attributes should have the security built into their access permissions (for example, read-only / read with authentication / write with authentication / write with authorization, and so on.).

Second, if the GATT Database requires additional security besides that already specified in attribute permissions (for example, certain services require higher security in certain situations), the following function must be called:

The parameter is a pointer to a structure which contains a “device security setting” and service-specific security settings. All these security requirements are pointers to gapSecurityRequirements_t structures. The pointers that are to be ignored should be set to NULL.

Although the Peripheral does not initiate any kind of security procedure, it can inform the Central about its security requirements. This is usually done immediately after the connection to avoid exchanging useless packets for requests that might be denied because of insufficient security.

The informing is performed through the Peripheral Security Request packet at SMP level. To use it, the following GAP API is provided:

The gapPairingParameters_t structure includes two important fields. The withBonding field indicates to the Central whether this Peripheral can bond and the securityModeAndLevel field informs about the required security mode and level that the Central should pair for. See Pairing and bonding (Central) for an explanation about security modes and levels, as defined by the GAP module.

This request expects no reply, nor any immediate action from the Central. The Central may easily choose to ignore the Peripheral Security Request.

If the two devices have bonded in the past, the Central proceeds directly to encrypting the link. If the bond was not made using LE Secure Connections, the Peripheral expects to receive a gConnEvtLongTermKeyRequest_c connection event. If the bond was made using LE Secure Connections, the Host provides the LTK automatically to the LE Controller.

When the devices have been previously pairing without using LE Secure Connections, along with the Peripheral’s LTK, the EDIV (2 bytes) and RAND (8 bytes) values were also sent (their meaning is defined by the SMP). Therefore, before providing the key to the Controller, the application should check that the two values match with those received in the gConnEvtLongTermKeyRequest_c event. If they do, the application should reply with:

The LTK size cannot exceed the maximum value of 16.

If the EDIV and RAND values do not match, or if the Peripheral does not recognize the bond, it can reject the encryption request with:

If LE SC Pairing was used then the LTK is generated internally by the Bluetooth LE Host Stack and it is not requested from the application during post-bonding link encryption. In this scenario, the application is only notified of the link encryption through the gConnEvtEncryptionChanged_c connection event.

If the devices are not bonded, the Peripheral should expect to receive the gConnEvtPairingRequest_c, indicating that the Central has initiated pairing.

If the application agrees with the pairing parameters (see Pairing and bonding (Central) for detailed explanations), it can reply with:

This time, the Peripheral sends its own pairing parameters, as defined by the SMP.

After sending this response, the application should expect to receive the same pairing events as the Central (see Pairing and bonding (Central)), with one exception: the gConnEvtPasskeyRequest_c event is not called if the application sets the Passkey (PIN) for pairing before the connection by calling the API:

This is done because, usually, the Peripheral has a static secret PIN that it distributes only to trusted devices. If, for any reason, the Peripheral must dynamically change the PIN, it can call the aforementioned function every time it wants to, before the pairing starts (for example, right before sending the pairing response with Gap_AcceptPairingRequest).

If the Peripheral application never calls Gap_SetLocalPasskey, then the gConnEvtPasskeyRequest_c event is sent to the application as usual.

The Peripheral can use the following API to reject the pairing process:

The reason should indicate why the application rejects the pairing. The value gLinkEncryptionFailed_c is reserved for the gConnEvtAuthenticationRejected_c connection event to indicate the link encryption failure rather than pairing failures. Therefore, it is not meant as a pairing reject reason.

The Gap_RejectPairing function may be called not only after the Pairing Request was received, but also during the pairing process. For example, when handling pairing events or asynchronously, if for any reason the Peripheral decides to abort the pairing, this function can be called. This also holds true for the Central. Figure 1 illustrates the Peripheral pairing flow and lists the main APIs and events. Gap_RejectPairing can be called on any pairing event.

For both the Central and the Peripheral, bonding is performed internally and is not the application’s concern. The gConnEvtPairingComplete_c event parameters inform the application if bonding has occurred.

Parent topic:Peripheral setup

Parent topic:Generic Access Profile (GAP) Layer

Central setup

Usually, a Central must start scanning to find Peripherals. When the Central has scanned a Peripheral it wants to connect to, it stops scanning and initiates a connection to that Peripheral. After the connection has been established, it may start pairing, if the Peripheral requires it, or directly encrypt the link, if the two devices have already bonded in the past.

Scanning

The most basic setup for a Central device begins with scanning, which is performed by the following function from gap_interface.h:

bleResult_t **Gap\_StartScanning**
(
  const gapScanningParameters_t* pScanningParameters,
  gapScanningCallback_t scanningCallback,
  gapFilterDuplicates_t enableFilterDuplicates,
  uint16_t duration,
  uint16_t period
);

If the pScanningParameters pointer is NULL, the currently set parameters are used. If no parameters have been set after a device power-up, the standard default values are used:

**\#define** gGapDefaultScanningParameters_d \
{ \
    /* type */             gGapScanTypePassive_c, \
    /* interval */         gGapScanIntervalDefault_d, \
    /* window */           gGapScanWindowDefault_d, \
    /* ownAddressType */   gBleAddrTypePublic_c, \
    /* filterPolicy */     gScanAll_c \
    /* scanning PHY */     gLePhylMFlag_c\
}

The easiest way to define non-default scanning parameters is to initialize a gapScanningParameters_t structure with the above default and change only the required fields.

For example, to perform active scanning and only scan for devices in the Filter Accept List, the following code can be used:

gapScanningParameters_t scanningParameters = gGapDefaultScanningParameters_d;
scanningParameters.type = gGapScanTypeActive_c;
scanningParameters.filterPolicy = gScanWithFilterAcceptList_c;
Gap_StartScanning(&scanningParamters, scanningCallback, enableFilterDuplicates, duration, period);

When using the common application structure, the application can use the following API defined in app_conn.h:

bleResult_t **BluetoothLEHost\_StartScanning**
(
    appScanningParams_t   *pAppScanParams,
    gapScanningCallback_t pfCallback
);

The API uses the appScanningParams_t structures, which is defined as follows:

typedef struct appScanningParams_tag
{
    gapScanningParameters_t *pHostScanParams;         /*!< Pointer to host scan structure */
    gapFilterDuplicates_t enableDuplicateFiltering;   /*!< Duplicate filtering mode */
    uint16_t duration;                                /*!< scan duration  */
    uint16_t period;                                  /*!< scan period  */
} appScanningParams_t;

The scanningCallback is triggered by the GAP layer to signal events related to scanning.

The most important event is the gDeviceScanned_c event, which is triggered each time an advertising device is scanned. This event data contains information about the advertiser:

typedef struct
{
    bleAddressType_t                  addressType ;
    bleDeviceAddress_t                aAddress ;
    int8_t                            rssi ;
    uint8_t                           dataLength ;
    uint8_t*                          data ;
    bleAdvertisingReportEventType_t   advEventType ;
    bool_t                            directRpaUsed;
    bleDeviceAddress_t                directRpa;
    bool_t                            advertisingAddressResolved;
} gapScannedDevice_t;

If this information signals a known Peripheral that the Central wants to connect to, the latter must stop scanning and connect to the Peripheral.

To stop scanning, call this function:

bleResult_t **Gap\_StopScanning** (**void**);

By default, the GAP layer is configured to report all scanned devices to the application using the gDeviceScanned_c event type. However, some use cases might require to perform specific GAP Discovery Procedures. In such use cases the advertising reports might require the filtering of Flags AD value from the advertising data. Other use cases require the Bluetooth LE Host Stack to automatically initiate a connection when a specific device has been scanned.

To enable filtering based on the Flags AD value or to set device addresses for automatic connections, the following function must be called before the scanning is started:

bleResult_t **Gap\_SetScanMode**
(
    gapScanMode_t           scanMode,
    gapAutoConnectParams_t* pAutoConnectParams,
    gapConnectionCallback_t connCallback
);

The default value for the scan mode is gDefaultScan_c, which reports all packets regardless of their content and does not perform any automatic connection.

To enable Limited Discovery, the gLimitedDiscovery_c value must be used, while the gGeneralDiscovery_c value activates General Discovery.

To enable automatic connection when specific devices are scanned, the gAutoConnect_c value must be set, in which case the pAutoConnectParams parameter must point to the structure that holds the target device addresses and the connection parameters to be used by the Host for these devices.

If scanMode is set to gAutoConnect_c, connCallback must be set and is triggered by GAP to send the events related to the connection.

Parent topic:Central setup

Initiating and closing a connection

To connect to a scanned Peripheral, extract its address and address type from the gDeviceScanned_c event data, stop scanning, and call the following function:

bleResult_t **Gap\_Connect**
(
const gapConnectionRequestParameters_t * pParameters,
gapConnectionCallback_t connCallback
);

When using the common application structure, the application can also use the following API defined in app_conn.h:

bleResult_t **BluetoothLEHost\_Connect**
(
    gapConnectionRequestParameters_t*   pParameters,
    gapConnectionCallback_t             connCallback
);

An easy way to create the connection parameter structure is to initialize it with the defaults, then change only the necessary fields. The default structure is defined as shown here:

**\#define** gGapDefaultConnectionRequestParameters_d \
{ \
    /* scanInterval */       gGapScanIntervalDefault_d, \
    /* scanWindow */         gGapScanWindowDefault_d, \
    /* filterPolicy */       gUseDeviceAddress_c, \
    /* ownAddressType */     gBleAddrTypePublic_c, \
    /* peerAddressType */    gBleAddrTypePublic_c, \
    /* peerAddress */        { 0, 0, 0, 0, 0, 0 }, \
    /* connIntervalMin */    gGapDefaultMinConnectionInterval_d, \
    /* connIntervalMax */    gGapDefaultMaxConnectionInterval_d, \
    /* connLatency */        gGapDefaultConnectionLatency_d, \
    /* supervisionTimeout */ gGapDefaultSupervisionTimeout_d, \
    /* connEventLengthMin */ gGapConnEventLengthMin_d, \
    /* connEventLengthMax */ gGapConnEventLengthMax_d \
    /* initiatingPHYs     */ gLePhylMFlag_c \
}

In the following example, Central scans for a specific Heart Rate Sensor with a known address. When it finds it, it immediately connects to it.

static void **BleApp\_ScanningCallback**
(
    gapScanningEvent_t *pScanningEvent
)
{
    switch (pScanningEvent->eventType)
    {
        case gDeviceScanned_c:
        {
            if (BleApp_CheckScanEvent(&pScanningEvent->eventData.scannedDevice))
            {
                gConnReqParams.peerAddressType = pScanningEvent->eventData.scannedDevice.addressType;
                FLib_MemCpy(gConnReqParams.peerAddress,
                        pScanningEvent->eventData.scannedDevice.aAddress,
                        sizeof(bleDeviceAddress_t));
                (void)Gap_StopScanning();
#if gAppUsePrivacy_d
                gConnReqParams.usePeerIdentityAddress =  pScanningEvent->eventData.scannedDevice.advertisingAddressResolved;
#endif
                (void)BluetoothLEHost_Connect(&gConnReqParams, BleApp_ConnectionCallback);
            }
        }
        break;
}

The connCallback is triggered by GAP to send all events related to the active connection. It has the following prototype:

**typedef** **void** (* gapConnectionCallback_t )
(
    deviceId_t             deviceId,
    gapConnectionEvent_t * pConnectionEvent
);

The very first event that should be listened inside this callback is the gConnEvtConnected_c event. If the application decides to drop the connection establishment before this event is generated, it should call the following macro:

**\#define** Gap_CancelInitiatingConnection()\
    Gap_Disconnect(gCancelOngoingInitiatingConnection_d)

This is useful, for instance, when the application chooses to use an expiration timer for the connection request.

Upon receiving the gConnEvtConnected_c event, the application may proceed to extract the necessary parameters from the event data (pConnectionEvent->event.connectedEvent). The most important parameter to be saved is the deviceId.

The deviceId is a unique 8-bit, unsigned integer, used to identify an active connection for subsequent GAP and GATT API calls. All functions related to a certain connection require a deviceId parameter. For example, to disconnect, call this function:

bleResult_t **Gap\_Disconnect**
(
    deviceId_t deviceId
);

Parent topic:Central setup

Pairing and bonding (Central)

After the user has connected to a Peripheral, use the following function to check whether this device has bonded in the past:

If it has, link encryption can be requested with:

If the link encryption is successful, the gConnEvtEncryptionChanged_c connection event is triggered. Otherwise, a gConnEvtAuthenticationRejected_cevent is received with the rejectReason event data parameter set to gLinkEncryptionFailed_c.

On the other hand, if this is a new device (not bonded), pairing may be started as shown here:

The pairing parameters are shown here:

The names of the parameters are self-explanatory. The withBonding flag should be set to TRUE if the Central must/wants to bond.

When Advanced Secure Mode is enabled, (gAppSecureMode_d id defined as 1 in app_preinclude.h), the security mode and level for pairing is automatically enforced as Mode 1 Level 4, and LE Secure Connection Supported is automatically enforced TRUE. Legacy pairing is not supported in this mode.

For the Security Mode and Level, the GAP layer defines them as follows:

  • Security Mode 1 Level 1 stands for no security requirements.

  • Except for Level 1 (which is only used with Mode 1), Security Mode 1 requires encryption, while Security Mode 2 requires data signing.

  • Mode 1 Level 2 and Mode 2 Level 1 do not require authentication (in other words, they allow Just Works pairing, which has no MITM protection). Mode 1 Level 3 and Mode 2 Level 2 require authentication (must pair with PIN or OOB data, which provide MITM protection).

  • Starting with Bluetooth specification 4.2, OOB pairing offers MITM protection only in certain conditions. The application must inform the stack if the OOB data exchange capabilities offer MITM protection via a dedicated API.

  • Security Mode 1 Level 4 is reserved for authenticated pairing (with MITM protection) using a LE Secure Connections pairing method.

  • If a pairing method is used but it does not offer MITM protection, then the pairing parameters must use Security Mode 1 level 2. If the requested pairing parameters are incompatible (for example, Security Mode 1 Level 4 without LE Secure Connections enabled), a gBleInvalidParameter_c status is returned by the security API functions: Gap_SetDefaultPairingParameters, Gap_SendPeripheralSecurityRequest, Gap_Pair and Gap_AcceptPairingRequest.

No security

No MITM protection

Legacy MITM protection

LE secure connections with MITM protection

Mode 1 (encryption) distributed LTK (EDIV+RAND) or generated LTK

Level 1 no security

Level 2 unauthenticated encryption

Level 3 authenticated encryption

Level 4 LE SC authenticated encryption

Mode 2 (data signing) distributed CSRK

Level 1 unauthenticated data signing

Level 2 authenticated data signing

The centralKeys should have the flags set for all the keys that are available in the application. The IRK is mandatory if the Central is using a Private Resolvable Address, while the CSRK is necessary if the Central wants to use data signing. The LTK is provided by the Peripheral and should only be included if the Central intends on becoming a Peripheral in future reconnections (GAP role change).

The peripheralKeys should follow the same guidelines. The LTK is mandatory if encryption is to be performed, while the peer’s IRK should be requested if the Peripheral is using Private Resolvable Addresses.

See Table 2 for detailed guidelines regarding key distribution.

The first three rows are both guidelines for Pairing Parameters (centralKeys and peripheralKeys) and for distribution of keys with Gap_SendSmpKeys.

If LE Secure Connections Pairing is performed (Bluetooth Low Energy 4.2 and above), then the LTK is generated internally, so the corresponding bits in the key distribution fields from the pairing parameters are ignored by the devices.

The Identity Address is distributed if the IRK is also distributed (its flag has been set in the Pairing Parameters). Therefore, it can be “asked” only by asking for IRK (it does not have a separate flag in a gapSmpKeyFlags_t structure). Therefore, it is N/A.

The negotiation of the distributed keys is as follows:

  • In the SMP Pairing Request (started by Gap_Pair), the Central sets the flags for the keys it wants to distribute (centralKeys) and receive (peripheralKeys).

CENTRAL

PERIPHERAL

Central keys

Peripheral keys

Long Term Key (LTK) +EDIV +RAND

If it wants to be a peripheral in a future reconnection

If it wants encryption

Identity Resolving Key (IRK)

If it uses or intends to use private resolvable addresses

If a peripheral is using a private resolvable address

Connection Signature Resolving Key (CSRK)

If it wants to sign data as GATT Client

If it wants the peripheral to sign data as GATT Client

Identity address

If it distributes the IRK

N/A

  • The Peripheral examines the two distributions and must send an SMP Pairing Response (started by the Gap_AcceptPairingRequest) after performing any changes it deems necessary. The Peripheral is only allowed to set to 0 some flags that are set to 1 by the Central, but not the other way around. For example, it cannot request/distribute keys that were not offered/requested by the Central. If the Peripheral is adverse to the Central’s distributions, it can reject the pairing by using the Gap_RejectPairing function.

  • The Central examines the updated distributions from the Pairing Response. If it is adverse to the changes made by the Peripheral, it can reject the pairing (Gap_RejectPairing). Otherwise, the pairing continues and, during the key distribution phase (the gConnEvtKeyExchangeRequest_c event) only the final negotiated keys are included in the key structure sent with Gap_SendSmpKeys.

  • For LE Secure Connections (both devices set the SC bit in the AuthReq field of the Pairing Request and Pairing Response packets), the LTK is not distributed. It is generated and the corresponding bit in the Initiator Key Distribution and Responder Key Distribution fields of the Pairing Response packet are set to 0.

If LE Secure Connections Pairing (Bluetooth LE 4.2 and above) is used, and OOB data needs to be exchanged, the application must obtain the local LE SC OOB Data from the Bluetooth LE Host Stack by calling the Gap_LeScGetLocalOobData function. The data is contained by the generic gLeScLocalOobData_c event.

The local LE SC OOB Data is refreshed in the following situations:

  • The Gap_LeScRegeneratePublicKey function is called (the gLeScPublicKeyRegenerated_c generic event is also generated as a result of this API).

  • The device is reset (which also causes the Public Key to be regenerated).

If the pairing continues, the following connection events may occur:

  • Request events

    • gConnEvtPasskeyRequest_c: a PIN is required for pairing; the application must respond with the Gap_EnterPasskey(deviceId, passkey).

    • gConnEvtOobRequest_c: if the pairing started with the oobAvailable set to TRUE by both sides; the application must respond with the Gap_ProvideOob(deviceId, oob).

    • gConnEvtKeyExchangeRequest_c: the pairing has reached the key exchange phase; the application must respond with the Gap_SendSmpKeys(deviceId, smpKeys).

    • gConnEvtLeScOobDataRequest_c: the stack requests the LE SC OOB Data received from the peer (r, Cr and Addr); the application must respond with Gap_LeScSetPeerOobData(deviceId, leScOobData).

    • gConnEvtLeScDisplayNumericValue_c: the stack requests the display and confirmation of the LE SC Numeric Comparison Value; the application must respond with Gap_LeScValidateNumericValue(deviceId, ncvValidated).

  • Informational events

    • gConnEvtKeysReceived_c: the key exchange phase is complete; keys are automatically saved in the internal device database and are also provided to the application for immediate inspection; application does not have to save the keys in NVM storage because this is done internally if withBondingwas set to TRUE by both sides.

    • gConnEvtAuthenticationRejected_c: the peer device rejected the pairing; the rejectReason parameter of the event data indicates the reason that the Peripheral does not agree with the pairing parameters (it cannot be gLinkEncryptionFailed_c because that reason is reserved for the link encryption failure).

    • gConnEvtPairingComplete_c: the pairing process is complete, either successfully, or an error may have occurred during the SMP packet exchanges; note that this is different from the gConnEvtKeyExchangeRequest_c event; the latter signals that the pairing was rejected by the peer, while the former is used for failures due to the SMP packet exchanges.

    • gConnEvtLeScKeypressNotification_c: the stack informs the application that a remote SMP Keypress Notification has been received during Passkey Entry Pairing Method.

After the link encryption or pairing is completed successfully, the Central may immediately start exchanging data using the GATT APIs.

|

|

Parent topic:Central setup

Parent topic:Generic Access Profile (GAP) Layer

LE data packet length extension

This new feature extends the maximum data channel payload length from 27 to 251 octets.

The length management is done automatically by the link layer immediately after the connection is established. The stack passes the default values for maximum transmission number of payload octets and maximum packet transmission time that the application configures at compilation time in ble_config.h:


#ifndef gBleDefaultTxOctets_c
#define gBleDefaultTxOctets_c        0x00FB
#endif

#ifndef gBleDefaultTxTime_c
#define gBleDefaultTxTime_c          0x0848
#endif

The device can update the data length anytime, while in connection. The function that triggers this mechanism is the following:

bleResult_t **Gap\_UpdateLeDataLength**
(
    deviceId_t         deviceId,
    uint16_t    txOctets,
    uint16_t    txTime
);

After the procedure executes, a gConnEvtLeDataLengthChanged_c connection event is triggered with the maximum values for number of payload octets and time to transmit and receive a link layer data channel PDU. The event is send event if the remote device initiates the procedure. This procedure is shown in Figure 1.

Parent topic:Generic Access Profile (GAP) Layer

Privacy feature

Introduction

Starting with Bluetooth 4.2, Privacy can be enabled either in the Host or in the Controller:

  • Host Privacy consists of two use cases that are described in detail in the following sections. These are:

    • Random address generation - Periodically regenerating a random address (Resolvable or Non-Resolvable Private Address) inside the Host and then applying it into the Controller.

    • Random address resolution - Trying to resolve incoming RPAs using the IRKs stored in the bonded devices list. The address resolution is performed when a connection is established with a device or for the autoconnect scan. The advertising packets that have an RPA are not resolved automatically due to the high MCU processing that is required.

      The random address resolution is performed by default by the Host whenever the Controller is not able to resolve an RPA. The Host performs random address generation only when Host Privacy is requested to be enabled. During random address generation, the advertising and scan operations, if active, are stopped and restarted. If errors occur during this process and the scan or advertising cannot be started, the application is notified through the corresponding event (gAdvertisingStateChanged_c, gExtAdvertisingStateChanged_c or gScanStateChanged_c)

  • Controller Privacy, introduced by Bluetooth 4.2, consists of writing the local IRK in the Controller, together with all known peer IRKs, and letting the Controller perform hardware, fully automatic RPA generation and resolution. The Controller uses a Resolving List to store these entries. The size of the list is platform dependent and determined by gMaxResolvingListSize_c. For RPA resolution, the entries that do not fit in this list are processed by the Host to be resolved using the IRKs from Bonded Devices list.

Either Host Privacy or Controller Privacy can be enabled at any time. Trying to enable one while the other is in progress generates a gBleInvalidState_c error. The same error is returned when trying to enable the same privacy type twice, or when trying to disable privacy when it is not enabled.

The recommended way of using Privacy is the Controller Privacy. However, enabling Controller Privacy requires at least a pair of local IRK and peer IRK, so this can only be enabled only after a pairing is performed with a peer and the IRKs are exchanged during the Key Distribution phase. When a device starts, if Privacy is required, the workflow is the following:

  1. Enable Host Privacy using the local IRK.

  2. Connect to a peer and perform pairing and bonding to exchange IRKs.

  3. Disable Host Privacy.

  4. Enable Controller Privacy using the local IRK and the peer IRK and peer identity address.

After enabling Host Privacy or Controller Privacy, the application must wait for the gHostPrivacyStateChanged_c or gControllerPrivacyStateChanged_c generic event and verify that privacy has been successfully enabled. Only then it is safe to proceed with setting advertising parameters (via the Gap_SetAdvertisingParameters or Gap_SetExtAdvertisingParameters APIs) or starting scanning (via the Gap_StartScanning API). Failure to do so could result in unwanted behavior, such as the device advertising or scanning with a public address.

Resolvable private addresses

A Resolvable Private Address (RPA) is a random address generated using an Identity Resolving Key (IRK). This address appears completely random to an outside observer, so a device may periodically regenerate its RPA to maintain privacy, as there is no correlation between any two different RPAs generated using the same IRK.

On the other hand, an IRK can also be used to resolve an RPA, in other words, to check if this RPA has been generated with this IRK. This process is called “resolving the identity of a device”. Whoever has the IRK of a device can always try to resolve its identity against an RPA.

For example, assume device A frequently changes its RPA using IRKA. At some point, A bonds with B. A must give B a way to recognize it in a subsequent connection when it (A) has a different address. To achieve this purpose, A distributes the IRKA during the Key Distribution phase of the pairing process. B stores the IRKA it received from A.

Later, B connects to a device X that uses RPAX. This address appears completely random, but B can try to resolve RPAX using IRKA. If the resolving operation is successful, it means that IRKA was used to generate RPAX, and since IRKA belongs to device A, it means that X is A. So B was able to recognize the identity of device X, but nobody else can do that since they do not have IRKA.

Parent topic:Introduction

Non-resolvable private addresses

A Non-Resolvable Private Address (NRPA) is a completely random address that has no generation pattern and therefore cannot be resolved by a peer.

A device that uses an NRPA that is changed frequently is impossible to track because each new address appears to belong to a new device.

Parent topic:Introduction

Multiple identity resolving keys

If a device bonds with multiple peers, all of which are using RPAs, it needs to store the IRK of each in order to be able to recognize them later (see previous section).

This means that whenever the device connects to a peer that uses an unknown RPA, it needs to try and resolve the RPA with each of the stored IRKs. If the number of IRKs is large, then this introduces a lot of computation.

Performing all these resolving operations in the Host can be costly. It is much more efficient to take advantage of hardware acceleration and enable the Controller Privacy.

Parent topic:Introduction

Parent topic:Privacy feature

Host privacy

To enable or disable Host Privacy, the following API may be used:

bleResult_t **Gap\_EnableHostPrivacy**
(
    bool_t              enable,
    const uint8_t *     aIrk
);

When enable is set to TRUE, the aIrkparameter defines which type of Private Address to generate. If aIrk is NULL, then a new NRPA is generated periodically and written into the Controller. Otherwise, an IRK is copied internally from the aIrk address and it is used to periodically generate a new RPA.

The lifetime of the Private Address (NRPA or RPA) is a number of seconds contained by the gGapHostPrivacyTimeoutexternal constant, which is defined in the ble_config.c source file. The default value for this is 900 (15 minutes).

When Host Privacy is enabled, the Host ignores the ownAddressType value for the advertising, scanning or connect parameters. It will always use the random address type in order to use the RPA configured in the Controller in the packets sent over the air.

As mentioned in the Introduction section, call this API for random address generation. For random address resolution there is no need to do so, it is performed by default against the bonded devices list.

Parent topic:Privacy feature

Controller privacy

To enable or disable Controller Privacy, the following API may be used:

bleResult_t **Gap\_EnableControllerPrivacy**
(
    bool_t                               enable,
    const uint8_t *                      aOwnIrk,
    uint8_t                              peerIdCount,
    const gapIdentityInformation_t*      aPeerIdentities
);

When enable is set to TRUE, aOwnIrkparameter shall not be NULL, peerIdCount shall not be zero or greater than gMaxResolvingListSize_c, and aPeerIdentities shall not be NULL.

The IRK defined by aOwnIrk is used by the Controller to periodically generate a new Resolvable Private Address (RPA). The lifetime of the RPA is a number of seconds contained by the gGapControllerPrivacyTimeoutexternal constant, which is defined in the ble_config.c source file. The default value for this is 900 (15 minutes).

The aPeerIdentities is an array of identity information for each bonded device. The identity information contains the device’s identity address (public or random static address) and the device’s IRK. This array can be obtained from the Host with the Gap_GetBondedDevicesIdentityInformationAPI.

Enabling Controller Privacy involves a quick sequence of commands to the Controller. When the sequence is complete, the gControllerPrivacyStateChanged_c generic event is triggered.

Privacy mode

In Bluetooth LE 5.0, the privacy mode has been introduced as an optional feature and is part of the GAP identity structure together with the address and address type. There are two modes: Network Privacy Mode (default) and Device Privacy Mode. These are valid only for Controller Privacy.

A device in network privacy mode only accepts packets from peers using private addresses.

A device in device privacy mode also accepts packets from peers using identity addresses, even if the peer had previously distributed the IRK. Private addresses are also accepted.

The privacy mode of a device is stored in NVM together with the IRK with a default value of Network. If the application wants to change this value it can extract the peer identities, modify the privacy mode from network to device and then enable Controller Privacy with the value.

To change the privacy mode of a device and make the change persistent, the user must call the following API:

bleResult_t **Gap\_SetPrivacyMode **
(
    uint8_t nvmIndex,
    blePrivacyMode_t privacyMode
);

Parent topic:Controller privacy

Scanning and initiating

When a Central device is scanning while Controller Privacy is enabled, the Controller actively tries to resolve any RPA contained in the Advertising Address field of advertising packets. If any match is found against the peer IRK list, then the advertisingAddressResolved parameter from the scanned device structure is set to TRUE.

In this case, the addressType and aAddress fields no longer contain the actual Advertising Address as seen over the air, but instead they contain the identity address of the device whose IRK was able to resolve the Advertising Address. In order to connect to this device, these fields shall be used to complete the peerAddressType and peerAddress fields of the connection request parameter structure, and the usePeerIdentityAddress field shall be set to TRUE.

If advertisingAddressResolved is equal to FALSE, then the advertiser is using a Public or Random Static Address, an NRPA, or a RPA that could not be resolved. Therefore, the connection to this device is initiated as if Controller Privacy was not enabled, by setting usePeerIdentityAddress to FALSE.

Parent topic:Controller privacy

Advertising

When a Peripheral starts advertising while Controller Privacy is enabled, the ownAddressType field of the advertising parameter structure is unused. Instead, the Controller always generates an RPA and advertises with it as Advertising Address.

If directed advertising is used, the Host only allows advertising to a device in the resolving list in order to be able to generate RPAs.

Parent topic:Controller privacy

Connected

When a device connects while Controller Privacy is enabled, the gConnEvtConnected_c connection event parameter structure contains more relevant fields than without Controller Privacy.

The peerRpaResolved field equals TRUE if the peer was using an RPA that was resolved using an IRK from the list. In that case, the peerAddressType and peerAddressfields contain the identity address of the resolved device, and the actual RPA used to create the connection (the RPA that a Central used when initiating the connection, or the RPA that the Peripheral advertised with) is contained by the peerRpa field.

The localRpaUsedfield equals TRUE if the local Controller was automatically generating an RPA when the connection was created, and the actual RPA is contained by the localRpa field.

Parent topic:Controller privacy

Parent topic:Privacy feature

Parent topic:Generic Access Profile (GAP) Layer

Setting PHY mode in a connection

In Bluetooth LE 5.0, the user is able to change the PHY mode in a connection through the Link Layer PHY Update Procedure and choose between default 1 Mbit/s, 2 Mbit/s high data rate or the coded S2 or S8 PHYs with 500 Kbps or 125 Kbps for longer range.

To set the PHY, the user can call:

bleResult_t **Gap\_LeSetPhy**
(
    bool_t       defaultMode,
    deviceId_t   deviceId,
    uint8_t      allPhys,
    uint8_t      txPhys,
    uint8_t      rxPhys,
    uint16_t     phyOptions
);

There are two modes to use this API:

  1. If defaultMode is set to TRUE, the user can call this function without being in a connection, i.e. provide a device ID. The PHY option is used by the Link Layer in the PHY response when a connection is created and the peer device initiates the PHY Update Procedure. The application should listen for gLePhyEvent_c with the gPhySetDefaultComplete_c sub event type for the confirmation of the operation.

  2. If defaultMode is set to FALSE, the user must also provide a valid device ID. The Host asks the Link Layer to initiate the PHY Update Procedure with the peer device using the provided parameters.

The application should listen for gLePhyEvent_c with the gPhyUpdateComplete_c sub event type for the confirmation of the update procedure to have ended. The result of the operation populates in the txPhy and rxPhy of the event. The result is from the negotiation of the local parameters and the peer PHY preferences.

To read the current PHY on a connection, call the following API:

bleResult_t **Gap\_LeReadPhy **
(
    deviceId_t deviceId
);

The application should listen for gLePhyEvent_c with the gPhyRead_c sub event type for the confirmation of the operation. The txPhy and rxPhy indicate the current modes used in the connection.

Parent topic:Generic Access Profile (GAP) Layer

Data management of bonded devices

The Host handles the management of the bonding data without requiring application intervention. The application must provide the NVM write, read, and erase functions presented in Non-Volatile Memory (NVM) access. The Host creates bonds if bonding is required after the pairing.

The bonded data structure is presented below, together with the GAP APIs that access it, for most APIs require a connection to be established with the device in the bonded list, the others can be accessed any time using the NVM index.

  1. Bond Header – identity address and address type that uniquely identify a device together with the IRK and privacy mode.

    • Gap_GetBondedDevicesIdentityInformation – for all bonds

  2. Bond Data Dynamic - security counters for signed operations – managed by the stack

  3. Bond Data Static – LTK, CSRK, Rand, EDIV, security information for read and write authorizations

    • Gap_SaveKeys– NVM index

    • Gap_LoadKeys– NVM index

    • Gap_LoadEncryptionInformation - deviceId

    • Gap_Authorize deviceId - GATT Server only

  4. Bond Data Legacy - Legacy pair information and CSRK

    • Gap_LoadEncryptionInformation - deviceId

  5. Bond Data Device Info - custom peer information (service discovery data) and device name

    • Gap_SaveCustomPeerInformation - deviceId

    • Gap_LoadCustomPeerInformation - deviceId

    • Gap_SaveDeviceName - deviceId

    • Gap_GetBondedDeviceName – NVM index

  6. Bond Data Descriptor List - configuration of indications and notifications for CCCD handles – GATT Server only

    • Gap_CheckNotificationStatus - deviceId

    • Gap_CheckIndicationStatus- deviceId

However, there may be some cases when an application wants to manage this data to read data from a bonded device created by the Host, create a bond obtained out-of-band or update an existing bond. For this use case, two GAP APIs and a GAP event have been added.

  1. Load the Keys of a bonded device.

    The user can call the following function to read the keys exchanged during pairing and stored by the Bluetooth LE Host Stack in the bond area when the pairing is complete.

    The application is informed of the NVM index through the gBondCreatedEvent_c sent by the stack immediately after the bond creation. The application is responsible for passing the memory in the pOutKeys OUT parameter to fill in the keys, if any of the keys are set to NULL, the stack does not fill that information. The pOutKeyFlags OUT parameter indicates to the application which of the keys were stored by the stack as not all of them may have been distributed during pairing.

    The pOutLeSc indicates if Bluetooth LE 4.2 LE Secure Connections Pairing was used, while the pOutAuth indicates if the peer device is authenticated for MITM protection. All these OUT parameters are recommended to be retrieved from the bond and added if later passed as input parameters for the save keys API.

    This function executes synchronously.

    bleResult_t **Gap\_LoadKeys**
    (
        uint8_t            nvmIndex,
        gapSmpKeys_t*      pOutKeys,
        gapSmpKeyFlags_t*  pOutKeyFlags,
        bool_t*            pOutLeSc,
        bool_t*             pOutAuth);
    );
    

    The gapSmpKeys_t is the structure used during the key distribution phase, as well as in the gConnEvtKeysReceived_c event and is as follows. The difference is that the Bluetooth LE device address cannot be set to NULL neither when loading a bond or when creating one as it identifies the bonded device together with the NVM index.

    Event Data

    Data type

    Data Description

    cLtkSize

    uint8_t

    Encryption Key Size filled by the stack. If aLtk is NULL, this is ignored. In Advanced Secure Mode, this should be the size of the LTK encrypted blob of 40 bytes.

| |aLtk|uint8_t*|Long Term (Encryption) Key or LTK encrypted blob if Advanced Secure Mode is enabled. NULL if LTK is not distributed, else size is given by cLtkSize

.| |aIrk|uint8_t*|Identity Resolving Key. NULL if aIrk is not distributed.| |aCsrk|uint8_t*|Connection Signature Resolving Key. NULL if aCsrk is not distributed.| |cRandSize|uint8_t|Size of RAND filled by the stack; usually equal to gcSmpMaxRandSize_c. If aLtk is NULL, this is ignored.| |aRand|uint8_t*|RAND value used to identify the LTK. If aLtkis NULL, this is ignored.| |ediv|uint16_t|EDIV value used to identify the LTK. If aLtk is NULL, this is ignored.| |addressType|bleAddressType_t|Public or Random address.| |aAddress|uint8_t*|Device Address. It cannot be NULL.|

The structure for the GAP SMP Key Flags is the following:

|Flag Type|Description|
|---------|-----------|
|`gNoKeys_c`|No key is available.|
|`gLtk_c`|Long-Term Key is available.|
|`gIrk_c`|Identity Resolving Key is available.|
|`gCsrk_c`|Connection Signature Resolving Key is available.|
  1. Save the Keys to create a bond or update an existing bonded device.

    The user can call the following function to create a bond on a device based on information obtained Out of Band. For instance, one can use the output of Gap_LoadKeys from the previous section. This can be useful in transferring a bond created by the stack after a pairing procedure or if the application wants to manipulate bonding data. The behavior of the stack remains the same, if the bonding is required after a pairing, the stack stores the bonding information if possible. In this case, the NVM index is passed to the application through gBondCreatedEvent_c.

    This function executes asynchronously, as the stack can create a bond during the execution. The application should listen for the previous mentioned event gBondCreatedEvent_c. The result of the function call is passed synchronously. However, if an asynchronous error has occurred during the actual save, it is passed to the application through the gInternalError_c event with a gSaveKeys_c error source.

    The stack creates a bond if the NVM index is free or update the keys from an NVM index if it stores a valid entry.

    The address from the GAP SMP Keys structure must not be NULL. If other members of the structure are NULL, they are ignored.

    LE SC flag indicates if Bluetooth LE 4.2 Secure Connections was used during pairing and Auth specifies if the peer is authenticated for MITM protection.

    bleResult_t **Gap\_SaveKeys**
    (
        uint8_t         nvmIndex,
        gapSmpKeys_t*   pKeys,
        bool_t          leSc,
        bool_t          auth
    );
    
  2. Bond created event.

    A GAP event is added to the Bluetooth LE Generic Callback to inform the application of the NVM index whenever the stack creates a bond or when a Gap_SaveKeys request succeeds. The event is also generated if the NVM index was a valid occupied entry and only some of the keys in the bonded information have been updated.

    The NVM index is then used in the GAP APIs to save or load information from the bond.

    Event Data

    Data type

    Data Description

    nvmIndex

    uint8_t

    NVM index for the new created bond

    addressType

    bleAddressType_t

    Public or Random (static) address of the bond

    address

    bleDeviceAddress_t

    Address of the bond

Application removal of bonded devices data

The application can remove a bonded device from NVM. The bonded device cannot be deleted if it is in an active connection. The application can remove one or all bonds by calling the following synchronous GAP APIs:

  • **Gap\_RemoveBond**(uint8_t nvmIndex)nvmIndex can be obtained via the Gap_CheckIfBonded API.

  • **Gap\_RemoveAllBonds\(\)** - no connections should be active otherwise the call fails.

Removing a bonded device does not affect the controller address resolution state nor the contents of either the Controller Filter Accept List or the Controller Resolving List. If Controller Privacy is enabled, it remains so until it is disabled or the device is reset.

In a scenario where the user wants to remove a bonded device and all its effects on device behavior (Controller Filter Accept List, Controller Resolving List), the following operations should be executed:

  • **Gap\_ClearFilterAcceptList** or **Gap\_RemoveDeviceFromFilterAcceptList**

    • Clear Controller Filter Accept List or clear a device from Filter Accept List.

  • **Gap\_RemoveAllBonds** or **Gap\_RemoveBond**

    • All bonded devices are removed or one bonded device is removed from NVM.

  • **BleConnManager\_DisablePrivacy**

    • Controller Privacy is disabled, Controller Resolving List is cleared and address resolution is disabled. The device should not be advertising or scanning, otherwise this call fails.

  • **BleConnManager\_EnablePrivacy**

    • Called after the gControllerPrivacyStateChanged_c event is received, confirming Controller Privacy has been disabled. If not all bonds have been deleted, Controller Privacy is reenabled. In the absence of bonds, Host Privacy is enabled.

Parent topic:Data management of bonded devices

Parent topic:Generic Access Profile (GAP) Layer

Controller enhanced notifications

This section describes how the application can configure and monitor the notifications generated by the Bluetooth Controller when advertising, scan, or connection events occur. This feature is proprietary to NXP that is available on selected Controllers.

The user can choose between two options:

  1. Enable notifications from the GAP layer and monitor GAP events in the GAP Generic Callback. The controller issues HCI vendor-specific events processed by the Bluetooth LE Host and presented to the application in the GAP Generic Callback.

  2. Enable notifications from the Controller interface and monitor controller events in a user-defined Application Callback.

  3. Combination of the above two options: configure feature at GAP layer and install an Application Callback through the Controller interface. After setting the callback, the HCI vendor-specific events are not issued and implicitly the GAP events. Instead, the user receives the notifications in the installed callback until setting the callback to NULL again if it wants to revert to GAP events.

  • GAP configuration:

    The user should call the following function to enable various events from the mask or use Event None to disable the feature. The Device ID is valid only for connection events.

    The event type is a bitmask having the following options:

    Event Type

    Event Description

    gNotifEventNone_c

    No enhanced notification event enabled

    gNotifConnEventOver_c

    Connection event over

    gNotifConnRxPdu_c

    Connection RX PDU

    gNotifAdvEventOver_c

    Advertising event over

    gNotifAdvTx_c

    Advertising ADV transmitted

    gNotifAdvScanReqRx_c

    Advertising SCAN REQ RX

    gNotifAdvConnReqRx_c

    Advertising CONN REQ RX

    gNotifScanEventOver_c

    Scanning event over

    gNotifScanAdvPktRx_c

    Scanning ADV PKT RX

    gNotifScanRspRx_c

    Scanning SCAN RSP RX

    gNotifScanReqTx_c

    Scanning SCAN REQ TX

    gNotifConnCreated_c

    Connection created

    gNotifChannelMatrix_c

    Enable channel status monitoring

    gNotifPhyReq_c

    Phy Req Pdu ack received

    gNotifConnChannelMapUpdate_c

    Channel map update

    gNotifConnInd_c

    Connect indication

    gNotifPhyUpdateInd_c

    Phy update indication

    After enabling events, the user should wait for a gControllerNotificationEvent_c GAP Generic Event in the GAP Generic Callback. The first event received should have the event type set to gNotifEventNone_c with a status of success confirming the selected event mask has been enabled. The same event types apply for both the GAP command and the GAP event. The structure for the Controller Notification event is the following:

    Event Data

    Data type

    Data Description

    eventType

    bleNotificationEvent_t

    Enhanced notification event type

    deviceId

    deviceId_t

    Device id of the peer, valid for connection events

    rssi

    int8_t

    RSSI, valid for RX event types

    channel

    uint8_t

    Channel, valid for connection event over or Rx/Tx events

    ce_counter

    uint16_t

    Connection event counter, valid for connection events only

    status

    bleResult_t

    Status of the request to select which events to be enabled/disabled

    timestamp

    uint16_t

    Timestamp in 625 μs slots, valid for Conn RX event and Conn Created event

    adv_handle

    uint8_t

    Advertising Handle, valid for advertising events, if multiple ADV sets supported

  • Controller configuration:

    The user should call the following function to enable various events from the mask or use Event None to disable the feature. The same event types apply as the GAP layer types. The connection handle is valid only for connection events.

    The event monitoring is done in a user-installed callback by calling:

    Where the types are the following:

    The event structure is nearly identical as the GAP one, except there is no status as the function call executes synchronously.

    Event Data

    Data type

    Data Description

    event_type

    bleNotificationEvent_t

    Enhanced notification event type

    conn_handle

    uint16_t

    Connection handle of the peer, valid for connection events

    rssi

    int8_t

    RSSI, valid for RX event types

    channel_index

    uint8_t

    Channel, valid for connection event over or Rx/Tx events

    conn_ev_counter

    uint16_t

    Connection event counter, valid for connection events only

    timestamp

    uint16_t

    Timestamp in 625 μs slots, valid for Conn RX event and Conn Created event

    adv_handle

    uint8_t

    Advertising Handle, valid for advertising events, if multiple ADV sets supported

Parent topic:Generic Access Profile (GAP) Layer

Extended advertising

Starting with Bluetooth 5, the advertising channels are separated in primary advertising channels and secondary advertising channels:

  1. Primary advertising channels

    • Use 3 legacy advertising channels 37, 38, and 39.

    • Can use either legacy 1M PHY or new LE Coded PHY.

    • PHY payload can vary from 6 to 37 bytes.

    • Packets on these channels are part of the advertising events.

  2. Secondary advertising channels

    • Use 37 channels, with the same channel index as the data channels.

    • Can use any LE PHY, but the same PHY during an Extended Advertising Event.

    • PHY payload can vary from 0 to 255 bytes.

    • Auxiliary packets on these channels are part of the Extended Advertising Event that begins at the same time with the advertising event on primary channel and ends with the last packet on the secondary channel.

An advertising data set is represented by advertising PDUs belonging together in an advertising event. Each set has different advertising parameters: PDU type, advertising interval, and PHY mode. The advertising data sets are identified by the Advertising SID (Set ID) field from the ADI – Advertising Data Info. Advertising data or Scan response data can be changed for each adverting data set and the random value of DID (Data ID) field is updated to differentiate between them.

Refer to Figure 1 and Figure 2.

Peripheral setup

This section describes the extended advertising GAP API. The application should not use both the extended and legacy API (described in section 4.2.1). If this requirement cannot be met, the application should at least wait for the generated events in the Advertising Callback prior to using the other API. That is, it is advisable to call legacy functions only after the event pertaining to an extended API is received, and vice versa. This GAP constraint can be considered an extension of the HCI constraint from the Bluetooth 5 specification: “A Host should not issue legacy commands to a Controller that supports the LE Feature (Extended Advertising)”.

The application configures extended advertising by going through the following states:

  1. Set the extended advertising parameters by calling:

    bleResult_t **Gap\_SetExtAdvertisingParameters**
    (
    gapExtAdvertisingParameters_t* pAdvertisingParameters
    );
    

    It may use the default set of parameters gGapDefaultExtAdvertisingParameters_d. The application should wait for a gExtAdvertisingParametersSetupComplete_c event in the Generic Callback. Only one advertising set can be configured at a time. Comparing with the legacy Gap_SetAdvertisingParameters command, the new set of parameters is as follows.

    Parameter

    Description

    SID

    Value of the Advertising SID subfield in the ADI field of the PDU.

    handle

    Used to identify an advertising set. Possible values are 0x00 or 0x01 since the current implementation supports two advertising sets.

    extAdvProperties

    BIT0 - Connectable advertising

BIT1 - Scannable advertising

BIT2 - Directed advertising

BIT3 - High Duty Cycle Directed Connectable advertising (≤3.75 ms Advertising Interval)

BIT4 - Use legacy advertising PDUs

BIT5 - Omit advertiser’s address from all PDUs

(“anonymous advertising”)

BIT6 - Include TxPower in the extended header of the advertising PDU.

If legacy advertising PDU types are being used (BIT4 = 1),

permitted properties values are presented in the next table. If the advertising set already contains data, the type shall be one that supports advertising data and the amount of data shall not exceed 31 octets.

If extended advertising PDU types are being used (BIT4 =0), then the advertisement shall not be both connectable and scannable. While high duty cycle directed connectable advertising (≤ 3.75 ms advertising interval) shall not be used (BIT3 = 0).

| |txPower|Maximum power level at which the advertising packets are to be transmitted, the Controller can choose any power level <= txPower. Value 127 to be used if Host has no preference.| |primaryPHY|PHY for ADV_EXT_IND: LE 1 M or LE Coded| |secondaryPHY|PHY for AUX_ADV_IND and periodic advertising: LE 1 M, LE 2 M or LE Coded. Ignored for legacy advertising| |secondaryAdvMaxSkip|Maximum advertising events that the Controller can skip before sending the AUX_ADV_IND packets on the secondary advertising channel. Higher values may result in lower power consumption. Ignored for legacy advertising| |enableScanReqNotification|Whether to enable notifications when scanning PDUs (SCAN_REQ, AUX_SCAN_REQ) are received. If enabled, the application is notified upon scan requests by gExtScanNotification_c events in the Advertising Callback|

When using LE Coded PHY for advertising, the default coding scheme chosen by link layer is S=8 \(125 kb/s data rate\). To change the default coding scheme, the user has two options:

-   At compile time by defining *mLongRangeAdvCodingScheme\_c*, or
-   At run time by calling the API *Controller\_ConfigureAdvCodingScheme\(\)*.
In both cases, the value of the define or the parameter of the API has to be an appropriate value for primary and secondary PHYs as defined by the enumeration *advCodingScheme\_tag* found in *controller\_interface.h*.

|EventType|PDU Type|Advertising Event Properties|
|---------|--------|----------------------------|
|Connectable and scannable undirected|ADV\_IND|00010011b|
|Connectable directed \(low duty cycle\)

|ADV_DIRECT_IND|00010101b| |Connectable directed (high duty cycle)

|ADV_DIRECT_IND|00011101b| |Scannable undirected|ADV_SCAN_IND|00010010b| |Non-connectable and

Nonscannable undirected

|ADV_NONCONN_IND|00010000b|

  1. Set the advertising data and/or scan response data by calling:

    bleResult_t **Gap\_SetExtAdvertisingData**
    (
    uint8_t handle,
    gapAdvertisingData_t* pAdvertisingData,
    gapScanResponseData_t* pScanResponseData
    );
    

    Either of the pAdvertisingData or pScanResponseData parameters can be NULL, but not both. For extended advertising (BIT4 = 0) only one must be different than NULL – the scannable advertising bit (BIT1) indicates whether pAdvertisingData (BIT1 = 0) orpScanResponseData (BIT1 = 1) is accepted. The total amount of Advertising Data shall not exceed 1650 bytes. Application should wait for a gExtAdvertisingDataSetupComplete_c event in the Generic Callback.

  2. Enable extended advertising by calling:

    bleResult_t **Gap\_StartExtAdvertising**
    (
    gapAdvertisingCallback_t advertisingCallback,
    gapConnectionCallback_t connectionCallback,
    uint8_t handle,
    uint16_t duration,
    uint8_t maxExtAdvEvents
    );
    

    When using the common application structure, the application can use the following API defined in app_conn.h:

    bleResult_t **BluetoothLEHost\_StartExtAdvertising**
    (
        appExtAdvertisingParams_t *pExtAdvParams,
        gapAdvertisingCallback_t  pfAdvertisingCallback,
        gapConnectionCallback_t   pfConnectionCallback
    );
    

    The API goes through the steps of setting the advertising data and parameters. Events from the Host task are treated in the App_AdvertiserHandler() function, implemented in app_advertiser.c. To set the extended advertising parameters and data BluetoothLEHost_StartExtAdvertising a parameter of the following type:

    typedef struct **appExtAdvertisingParams\_tag**
    {
        gapExtAdvertisingParameters_t *pGapExtAdvParams;
        gapAdvertisingData_t *pGapAdvData;
        gapScanResponseData_t *pScanResponseData;
        uint8_t                     handle;
        uint16_t                    duration;
        uint8_t                     maxExtAdvEvents;
    } appExtAdvertisingParams_t;
    

    Advertising may be enabled for each previously configured advertising set, identified by the handle parameter. If duration is set to 0, advertising continues until the Host disables it, otherwise advertising is only enabled for this period (multiple of 10 ms). maxExtAdvEvents represent the maximum number of extended advertising events the Controller shall attempt to send prior to terminating the extended advertising, ignored if set to 0. Application should wait for a gExtAdvertisingStateChanged_c or a gAdvertisingCommandFailed_c event in the Advertising Callback.

  3. Disable advertising by calling:

    bleResult_t **Gap\_StopExtAdvertising**
    (
    uint8_t handle
    );
    

    Application should wait for a gExtAdvertisingStateChanged_c or a gAdvertisingCommandFailed_c event in the Advertising Callback.

  4. Remove the advertising set by calling:

    bleResult_t** Gap\_RemoveAdvSet**
    (
    uint8_t handle
    );
    

    Application should wait for a gExtAdvertisingSetRemoveComplete_c event in the Generic Callback.

Parent topic:Extended advertising

Central setup

The application configures the extended scanning by going through the following states:

  1. Start scanning by calling:

    bleResult_t Gap_StartScanning
    (
    const gapScanningParameters_t* pScanningParameters,
    gapScanningCallback_t scanningCallback,
    gapFilterDuplicates_t enableFilterDuplicates,
    uint16_t duration,
    uint16_t period
    )
    

    When using the common application structure, the application can use the following API defined in app_conn.h:

    bleResult_t **BluetoothLEHost\_StartScanning**
    (
        appScanningParams_t   *pAppScanParams,
        gapScanningCallback_t pfCallback
    );
    

    The API starts scanning using the given parameters, which must have the following structure:

    typedef struct appScanningParams_tag
    {
        gapScanningParameters_t *pHostScanParams;         /*!< Pointer to host scan structure */
        gapFilterDuplicates_t enableDuplicateFiltering;        /*!< Duplicate filtering mode */
        uint16_t duration;                                                           /*!< scan duration  */
        uint16_t period;                                                               /*!< scan period  */
    } appScanningParams_t;
    

    Application may use the default set of parameters gGapDefaultExtScanningParameters_d. If the pScanningParameters pointer is NULL, the latest set of parameters are used. The scanningPHYs parameter indicates the PHYs on which the advertising packets should be received on the primary advertising channel. As a result, permitted values for the parameter are 0x01 (scan LE 1M), 0x04 (scan LE Coded) and 0x05 (scan both LE 1M and LE Coded). There are no strict timing rules for scanning, yet if both PHYs are enabled for scanning, the scan interval value must be large enough to accommodate two scan windows (interval >= 2 * window).

    If the advertiser uses legacy advertising PDUs, the device may actively scan by sending a SCAN_REQ PDU to the advertiser on the LE 1M primary advertising channel (no secondary channel in legacy advertising). Respectively, if the advertiser uses extended advertising PDUs, the active scan operation takes place on the secondary advertising channel. After the device receives a scannable ADV_EXT_IND PDU on the primary advertising channel (PHY LE 1M or Coded), it starts listening for the AUX_ADV_IND PDU on the secondary advertising channel (PHY 1M, 2M or Coded). Once received, the device sends an AUX_SCAN_REQ to the advertiser. Next, an AUX_SCAN_RSP PDU should be received, containing the scan response data. Application should wait for a gScanStateChanged_c or a gScanCommandFailed_cin the Scanning Callback.

  2. Collect information by waiting for gDeviceScanned_c (legacy advertising PDUs) or gExtDeviceScanned_c (extended advertising PDUs) event in the Scanning Callback. The gExtDeviceScanned_c event contains additional information pertaining to the extended received PDU, such as: primary PHY, secondary PHY, advertising SID, interval of the periodic advertising if enabled in the set.

    When using the common application structure, the application can use the following API defined in app_conn.h, to search the contents from pData in an advertising element:

    bool_t **BluetoothLEHost\_MatchDataInAdvElementList**
    (
        gapAdStructure_t *pElement,
        void             *pData,
        uint8_t          iDataLen
    );
    
  3. Stop scanning by calling the function below:

    bleResult_t **Gap\_StopScanning**(void);
    

    Application should wait for a gScanStateChanged_c or a gScanCommandFailed_c in the Scanning Callback.

  4. Connect to a device by calling the function below:

    bleResult_t **Gap\_Connect**
    (
    const gapConnectionRequestParameters_t* pParameters,
    gapConnectionCallback_t connCallback
    );
    

    When using the common application structure, the following API can be used:

    bleResult_t **BluetoothLEHost\_Connect**
    (
        gapConnectionRequestParameters_t*   pParameters,
        gapConnectionCallback_t             connCallback
    );
    

    The initiatingPHYs parameter indicates the PHYs on which the advertising packets should be received on the primary advertising channel and the PHYs for which connection parameters have been specified. The parameter is a bitmask of PHYs: BIT0 = LE 1M, BIT1 = LE 2M and BIT2 = LE Coded. The Host may enable one or more initiating PHYs, but it must at least set one bit for a PHY allowed for scanning on the primary advertising channel, i.e., BIT0 for LE 1M PHY or BIT2 for LE Coded PHY.

    If the advertiser uses legacy advertising PDUs, the device may connect by sending a CONNECT_IND PDU to the advertiser on the LE 1M primary advertising channel (no secondary channel in legacy advertising). On the other hand, if the advertiser uses extended advertising PDUs, the extended connect operation takes place on the secondary advertising channel. After the device receives a connectable ADV_EXT_IND PDU on the primary advertising channel (PHY LE 1M or Coded), it starts listening for the connectable AUX_ADV_IND PDU on the secondary advertising channel (PHY 1M, 2M or Coded). Once received, the device sends an AUX_CONNECT_REQ to the advertiser. Next, if AUX_CONNECT_RSP PDU is received, the device enters the Connection State in the Central role on the secondary advertising channel PHY.

    Application should wait for a gConnEvtConnected_c event in the Connection Callback. If the channel selection algorithm #2 is used for this connection, then a gConnEvtChanSelectionAlgorithm2_c event is also generated.

    After the connection is successfully established, the application may choose to read the connection PHY by calling the Gap_LeReadPhy API. It may also opt to change the PHY of the connection by triggering a PHY Update Procedure using the Gap_LeSetPhy API. However, the Controller might not be able to perform the change if, in case the peer does not support the new requested PHY.

Parent topic:Extended advertising

Parent topic:Generic Access Profile (GAP) Layer

Periodic Advertising

Periodic channels are used for periodic broadcast between unconnected devices. A periodic channel is represented by a channel map and a set of hopping and timing parameters.

The set of channels is represented by the 37 data channels. A packet sent by an advertiser can also have a payload of up to 255 bytes and it can be sent on any LE PHY. Figure 1 and Figure 2.

Peripheral Setup

  1. First set the extended advertising parameters using Gap_SetExtAdvertisingParameters. The extended advertising type must be set to non-connectable and non-scannable.

  2. Set the periodic advertising parameters using the same handle as in the previous command.

    bleResult_t **Gap\_SetPeriodicAdvParameters**
    (
        gapPeriodicAdvParameters_t*    pAdvertisingParameters
    );
    

    Wait for a gPeriodicAdvParamSetupComplete_cevent in the generic callback.

  3. Next, set the periodic advertising data by calling:

    bleResult_t **Gap\_SetPeriodicAdvertisingData**
    (
        uint8_t                      handle,
        gapAdvertisingData_t*  pAdvertisingData,
        bool_t bUpdateDID
    );
    

    pAdvertisingData cannot be NULL. If periodic advertising data must be empty, set cNumAdStructures to 0. Wait for a gPeriodicAdvDataSetupComplete_cevent in the generic callback.

  4. Start extended advertising using Gap_StartExtAdvertising.

  5. Last, enable Periodic Advertising. Periodic advertising starts only after extended advertising is started.

    bleResult_t **Gap\_StartPeriodicAdvertising**
    (
        uint8_t handle,
        bool_t  bIncludeADI
    );
    

    Wait for a gPeriodicAdvertisingStateChanged_cevent in the advertising callback.

Parent topic:Periodic Advertising

Central Setup

The application may decide to listen to periodic advertising by going through the following states:

  1. [Optional] Add a known periodic advertiser to the periodic advertiser list held in the Controller by calling:

    **bleResult\_t Gap\_UpdatePeriodicAdvList**
    (
        gapPeriodicAdvListOperation_t operation,
        bleAddressType_t               addrType,
        uint8_t*                       pAddr,
        uint8_t                        SID
    );
    

    Wait for the gPeriodicAdvListUpdateComplete_c event in the Generic Callback.

  2. Synchronize with a periodic advertiser by calling:

    bleResult_t **Gap\_PeriodicAdvCreateSync**
    (
        gapPeriodicAdvSyncReq_t*   pReq,
    );
    

    pReq parameter filterPolicycan be set to gUseCommandParameters_c to synchronize with the given peer, or to gUsePeriodicAdvList_c to start synchronizing with all the devices in the previously populated periodic advertiser list.

    Wait for the gPeriodicAdvSyncEstablished_c event and check the status. If scanning is not enabled at the time this command is sent, synchronization occurs after scanning is started. Synchronization remains pending until gPeriodicAdvSyncEstablished_cevent is received. If synchronization was successful, the syncHandle is returned in this event.

  3. Terminate the synchronization with the periodic advertiser by calling:

    bleResult_t **Gap\_PeriodicAdvTerminateSync**
    (
        uint16_t syncHandle
    );
    

    To cancel a pending synchronization, the application should call Gap_PeriodicAdvTerminateSync with syncHandle set to the reserved value gBlePeriodicAdvOngoingSyncCancelHandle and wait for gPeriodicAdvCreateSyncCancelled_c event.

    Otherwise, to terminate an already established sync with an advertiser, use the syncHandle value from the gPeriodicAdvSyncEstablished_c event and wait for a gPeriodicAdvSyncTerminated_c event.

Parent topic:Periodic Advertising

Parent topic:Generic Access Profile (GAP) Layer

Periodic Advertising with Responses (PAwR) {#periodic_advertizing_with_responses}

This section describes the Central and Peripheral setup for Periodic Advertising with Responses (PAwR).

Central Setup

  1. Start scanning using Gap_StartScanning. Wait for gPeriodicDeviceScannedV2_c events in the scanning callback.

  2. Synchronize with a periodic advertiser by calling Gap_PeriodicAdvCreateSync. Wait for the gPeriodicAdvSyncEstablished_c event in the scanning callback. When PAwR is involved, this event includes additional information such as number of subevents, subevent interval, response slot delay and spacing,

  3. Synchronize to a PAwR subevent by calling Gap_SetPeriodicSyncSubevent. This API instructs the Controller to sync with a subset of the subevents within a PAwR train identified by syncHandle (obtained after synchronizing with the PAwR train in the previous step).

    bleResult_t Gap_SetPeriodicSyncSubevent ( uint16_t syncHandle, const gapPeriodicSyncSubeventParameters_t* pParams );
    

    Wait for the gPeriodicSyncSubeventComplete_c event.

  4. Use Gap_SetPeriodicAdvResponseData to set data in the AD format which would be sent as a Periodic Advertising Response to the broadcaster.

    bleResult_t Gap_SetPeriodicAdvResponseData ( uint16_t syncHandle, const gapPeriodicAdvertisingResponseData_t* pData );
    
  5. Optionally, the periodic advertiser may initiate a connection. If no connection callback was set on the scanner via APIs such as Gap_Connect or Gap_StartAdvertising/Gap_StartExtAdvertising, one must be explicitly set. This is achieved by calling BluetoothLEHost_SetConnectionCallback (defined in app_conn.h), which in turn calls Gap_SetConnectionCallback.

    void Gap_SetConnectionCallback ( gapConnectionCallback_t pfConnectionCallback );
    

Parent topic:Periodic Advertising with Responses (PAwR)

Peripheral Setup

  1. First set the extended advertising parameters using Gap_SetExtAdvertisingParameters. The extended advertising type must be set to non-connectable and non-scannable.

  2. Set the periodic advertising parameters with the same handle as in the previous command. Use the Gap_SetPeriodicAdvParametersV2 command. Compared to Gap_SetPeriodicAdvParameters, this command also configures parameters relevant to PAwR, such as the number of subevents and response slots as well as timing information.

bleResult_t Gap_SetPeriodicAdvParametersV2 
   (gapPeriodicAdvParametersV2_t* pAdvertisingParameters);

Wait for a gPeriodicAdvParamSetupComplete_c event in the generic callback.

  1. Start extended advertising using Gap_StartExtAdvertising.

  2. Start periodic advertising using Gap_StartPeriodicAdvertising.

  3. Wait for gPerAdvSubeventDataRequest_c events. These events are used by the Controller to indicate that it is ready to transmit one or more subevents and it is requesting the advertising data for these subevents. Upon receiving an event, use Gap_SetPeriodicAdvSubeventData to set the advertising data for specific subevents.

bleResult_t Gap_SetPeriodicAdvSubeventData 
      (uint8_t advHandle, const gapPeriodicAdvertisingSubeventData_t* pData);

Wait for the gPeriodicAdvSetSubeventDataComplete_c event in the generic callback.

  1. Wait for gPerAdvResponse_c events. These events contain responses sent by devices who are synchronized to the periodic advertising. They include data in the AD format.

  2. Optionally, PAwR allows the advertising device to initiate a connection to one of the synchronized scanners. The connection can be initiated by calling Gap_ConnectFromPawr.

bleResult_t Gap_ConnectFromPawr 
      (const gapConnectionFromPawrParameters_t* pParameters, gapConnectionCallback_t connCallback);

Parent topic:Periodic Advertising with Responses (PAwR)

Parent topic:Generic Access Profile (GAP) Layer

Encrypted Advertising Data {#encrypted_advertising_data_0}

This section describes the Central and Peripheral setup for encrypted advertising data.

Central Setup

Use the Gap_DecryptAdvertisingData API to decrypt the contents of “Encrypted Advertising Data” (0x31) AD types included in scanned data.

bleResult_t Gap_DecryptAdvertisingData 
    (uint8_t *pData, uint16_t dataLength, const uint8_t *pKey, const uint8_t *pIV, uint8_t *pOutput)

Parent topic:Encrypted Advertising Data

Peripheral Setup

Use the Gap_EncryptAdvertisingData API to obtain the encrypted advertising data, which can then be placed inside the “Encrypted Advertising Data” (0x31) AD type.

bleResult_t Gap_EncryptAdvertisingData 
  ( const gapAdvertisingData_t *pAdvertisingData, const uint8_t *pKey, const uint8_t *pIV, uint8_t *pOutput )

Parent topic:Encrypted Advertising Data

Parent topic:Generic Access Profile (GAP) Layer

Enhanced ATT

The Enhanced ATT protocol allows concurrent transactions to be handled by the stack. The sequential transaction rule still exists when EATT is used, but its scope is now defined as being per instance of the Enhanced ATT Bearer. EATT transactions might execute in parallel if they are supported by distinct L2CAP channels, which use the Enhanced Credit Based Flow Control Mode (that is, distinct Enhanced ATT Bearers).

When using an Enhanced ATT Bearer, ATT MTU and L2CAP MTU are independently configurable and may be reconfigured during a connection. An increase to the MTU is allowed but reducing its size is not. Allowing MTU to be increased without needing to reestablish the connection has an advantage. It eliminates the risk of a second application using the stack, being unable to continue, due to the previously negotiated MTU being too small.

Enhanced ATT bearers are identified through Bearer Ids. Enhanced ATT Bearer Ids are assigned internally and have a valid range between 1 and 251. The Unenhanced ATT bearer is always available for a connected peer device and has the BearerId 0.

EATT Credits management

Credits for the L2CAP channels used by Enhanced ATT bearers may be managed internally if the autoCreditsMgmt parameter is set to TRUE in the **Gap\_EattConnectionRequest** or **Gap\_EattConnectionAccept** function call. Otherwise, the application is responsible for credits management.

If the application chooses to manage the credits of the L2CAP channels used as Enhanced ATT bearers, it should use the following function to send credits for a specified bearer to a peer device:

bleResult_t **Gap\_EattSendCredits**
(
    deviceId_t  deviceId,
    bearerId_t  bearerId,
    uint16_t    credits
);
        

If the local credits or peer credits of the L2CAP channel used by an Enhanced ATT bearer reaches 0, agConnEvtEattBearerStatusNotification_c connection event is updated with a status value ofgEnhancedBearerSuspendedNoLocalCredits_c, or gEnhancedBearerNoPeerCredits_c respectively.

Parent topic:Enhanced ATT

EATT Connection establishment

In order to take advantage of the Enhanced ATT features, first a number of Enhanced Bearers should be opened for a connected peer device. For this, the function below may be used to create up to five Enhanced ATT bearers at a time:

bleResult_t Gap_EattConnectionRequest
(
   deviceId_t  deviceId,
   uint16_t    mtu,
   uint8_t     cBearers,
   uint16_t    initialCredits,
   bool_t      autoCreditsMgmt
);

The mtu parameter specifies the MTU for all the bearers to be established.

The cBearers parameter is used to specify the number of Enhanced ATT bearers to be opened, and should have a value between 1 and 5. The initialCredits parameter specifies the initial number of credits of the L2CAP credit based channels used as Enhanced ATT bearers.

The autoCreditsMgmt parameter is used to tell the Bluetooth LE Host Stack if it should manage L2CAP channel credits automatically. If set to TRUE the Bluetooth LE Host Stack automatically sends credits to a peer device when exhausted in chunks of initialCredits.

For example, to establish two Enhanced ATT bearers with a peer device the application may call the Gap_EattConnectionRequest as shown below:

bleResult_t result = **Gap\_EattConnectionRequest**(peerDeviceId,
                        64U,
                         2U,
                         3U,
                         TRUE);
if (gBleSuccess_c != result)
{
    /* Treat error */
}

If an EATT Connection Request is received from a peer device it would be signaled through the gConnEvtEattConnectionRequest_c connection event of type gapEattConnectionRequest_t sent to the connection callback. The application should handle this event by calling Gap_EattConnectionAccept. The example below shows how an application may accept an incoming EATT Connection Request with the same MTU as requested by the peer device.

case gConnEvtEattConnectionRequest_c:
{
    gapEattConnectionRequest_t *pEattConnectionReq = &pConnectionEvent->eventData.eattConnectionRequest;
    
    bleResult_t result = **Gap\_EattConnectionAccept**(peerDeviceId,
                                                TRUE,
                                                pEattConnectionReq->mtu,
                                                3U,
                                                TRUE);
        
    if (gBleSuccess_c != result)
    {
        /* Treat error */
    }
}
break;

In case the localMtu specified when accepting a connection differs from the MTU requested by the peer device, the minimum of the two would become the MTU of the Enhanced Bearers.

After the **Gap\_EattConnectionRequest** or **Gap\_EattConnectionAccept** is called, for the result the application should wait for the gConnEvtEattConnectionComplete_c connection event of type gapEattConnectionComplete_t shown below:

typedef struct {
    l2caLeCbConnectionRequestResult_t           status;
    uint16_t                                    mtu;
    uint8_t                                     cBearers;
    bearerId_t                                  aBearerIds[gGapEattMaxBearers];
} gapEattConnectionComplete_t;

If successful, the aBearerIds array contains the bearer ids, for the Enhanced ATT bearers established. These ids may be used with the GATT Enhanced APIs in order to trigger GATT procedures over Enhanced ATT bearers.

Parent topic:Enhanced ATT

EATT Bearer reconfiguration

One of the advantages of Enhanced ATT bearers over the Unenhanced ATT bearer is the ability to increase the MTU multiple times. To reconfigure the MTU and/or MPS of existing Enhanced ATT bearers, the **Gap\_EattReconfigureRequest** should be used. If a mps value of 0 is given, the maximum available MPS value for that channel is used.

For example, in order to reconfigure the MTU of two bearers from 64 to 128 the application may call **Gap\_EattReconfigureRequest** as shown below:


bleResult_t result = gBleSuccess_c;
bearerId_t aBearerIds[2] = {1U, 2U};
result = **Gap\_EattReconfigureRequest**(peerDeviceId,
                                    128U,
                                    0U,
                                    2U,
                                    aBearerIds);
if (gBleSuccess_c != result)
{
    /* Treat error */
}

The application should monitor the gConnEvtEattChannelReconfigureResponse_c connection event of type gapEattReconfigureResponse_t for the result.

The procedure triggered by ******Gap\_EattReconfigureRequest** updates only the local MTU. The ATT_MTU for Enhanced ATT bearers is the minimum of the MTU values of the two devices.

Parent topic:Enhanced ATT

EATT Bearer disconnection

Individual Enhanced ATT bearers can be disconnected by calling the Gap_EattDisconnect API as shown below:


bleResult_t result = gBleSuccess_c;
result = Gap_EattDisconnect(peerDeviceId, bearerId);
if (gBleSuccess_c != result)
{
 /* Treat error */
}

The application should look for a connection event of type gEnhancedBearerDisconnected_c in the connection callback.

Parent topic:Enhanced ATT

Parent topic:Generic Access Profile (GAP) Layer