Mistake on this page?
Report an issue in GitHub or email us

GAP

The Generic Access Profile is the layer of the stack that handles connectivity tasks. This includes link establishment and termination, advertising and scanning.

Devices with data to publish can use GAP to advertise. They can include the data in the advertisement itself, inside the scan response, or leave a peer device to query it after the connection has been established.

The other side of the process is the act of scanning, which listens for advertisements, allows you to query the advertisers for more data through a scan request or connect in order to query the peer device for the data you want.

Advertising, scanning and connection all have parameters that let you find a compromise between desired power consumption levels, latency and efficiency of these processes.

Advertising

Advertising consists of broadcasting at a regular interval a small amount of data containing valuable information about the device. Peer devices listening on BLE advertising channels may scan these packets.

Scanners may also request additional information from device advertising by sending a scan request. If the broadcaster accepts scan requests, it can reply with a scan response packet containing additional information.

Scanning

Scanning consists of listening for peer advertising packets. From a scan, a device can identify devices available in its environment.

If the device scans actively, it sends scan request to scannable advertisers and collects their scan responses.

Extended and periodic advertising

BLE controllers supporting Bluetooth 5.0 may offer additional advertising and scanning options. Use isFeatureSupported() to check feature availability.

Extended advertising may use multiple PHYs and spread the payload across many packets. This allows for much larger payloads. In this scenario, advertising is split across primary advertising on the advertising channels and secondary advertising using channels normally used for sending data to connected devices.

Similarly, if the controller supports periodic advertising, you may use periodic advertising to send changing data to many peers. Each peer needs to scan the advertisements on the primary channels and create a sync with a periodic advertisement it's interested in.

There may be many advertising sets active at one time on a single advertiser. This allows it to advertise different data at the same time, possibly to different peers.

Devices that do not support extended and periodic advertising will not see these advertisements. You may use legacy advertising alongside extended advertising, running at the same time, to support older devices in the environment.

Privacy

Privacy is a feature that allows a device to avoid being tracked by other (untrusted) devices. The device achieves it by periodically generating a new random address. The random address may be a resolvable random address, enabling trusted devices to recognize it as belonging to the same device. These trusted devices receive an Identity Resolution Key (IRK) during pairing. The SecurityManager handles this and relies on the other device accepting and storing the IRK.

You need to enable privacy by calling enablePrivacy() after initializing the SecurityManager because privacy requires SecurityManager to handle IRKs. Set the behavior of privacy enabled devices by using setCentralPrivacyConfiguration(), which specifies what the device should be with devices using random addresses, and setPeripheralPrivacyConfiguration. Random addresses that privacy enabled devices generate can be of two types: resolvable (by devices who have the IRK) and unresolvable. You can't use unresolvable addresses for connecting and connectable advertising; therefore, use a resolvable one for these, regardless of the privacy configuration.

Modulation schemes

When supported by the host and controller, you can select different modulation schemes:

  • LE 1M PHY.
  • LE 2M PHY.
  • LE coded PHY.

These provide different compromises between bandwidth, power usage and error resiliency (see BLUETOOTH SPECIFICATION Version 5.0 Vol 1, Part A - 1.2).

You may set preferred PHYs (separately for RX and TX) using setPreferredPhys(). You may also set the currently used PHYs on a selected connection using setPhy(). Both of these settings are only advisory. The controller is allowed to make its own decision on the best PHY to use based on your request, the peer's supported features and the connection's physical conditions.

You may query the currently used PHY using readPhy(), which returns the result through a call to the registered event handler. You may register the handler with setEventHandler(). The events inform about the currently used PHY and of any changes to PHYs, which the controller or the peer may trigger autonomously.

GAP class reference

Data Structures
struct  AdvertisementCallbackParams_t
 Representation of a scanned advertising packet. More...
struct  ConnectionCallbackParams_t
 Connection events. More...
struct  ConnectionParams_t
 Parameters of a BLE connection. More...
struct  DisconnectionCallbackParams_t
 Disconnection event. More...
struct  GapState_t
 Description of the states of the device. More...
struct  Whitelist_t
 Representation of a whitelist of addresses. More...
Public Types
typedef BLEProtocol::AddressType_t AddressType_t
 Address-type for BLEProtocol addresses. More...
typedef BLEProtocol::AddressType_t addr_type_t
 Address-type for BLEProtocol addresses. More...
typedef BLEProtocol::AddressBytes_t Address_t
 48-bit address, LSB format. More...
typedef BLEProtocol::AddressBytes_t address_t
 48-bit address, LSB format. More...
typedef ble::connection_handle_t Handle_t
 Opaque value type representing a connection handle. More...
typedef ble::random_address_type_t RandomAddressType_t
 Enumeration of random address types. More...
typedef ble::peer_address_type_t PeerAddressType_t
 Enumeration of peer address types. More...
typedef ble::phy_t Phy_t
 Enumeration of BLE PHY. More...
typedef ble::phy_set_t PhySet_t
 Set of BLE PHYs. More...
typedef ble::coded_symbol_per_bit_t CodedSymbolPerBit_t
 Enumeration of type of symbols that can be used with LE coded PHY. More...
typedef FunctionPointerWithContext< const AdvertisementCallbackParams_t * > AdvertisementReportCallback_t
 Type of the callback handling scanned advertisement packets. More...
typedef ble::peripheral_privacy_configuration_t PeripheralPrivacyConfiguration_t
 Privacy Configuration of the peripheral role. More...
typedef ble::central_privay_configuration_t CentralPrivacyConfiguration_t
 Privacy configuration of the central role. More...
typedef FunctionPointerWithContext< TimeoutSource_tTimeoutEventCallback_t
 Timeout event handler. More...
typedef CallChainOfFunctionPointersWithContext< TimeoutSource_tTimeoutEventCallbackChain_t
 Callchain of timeout event handlers. More...
typedef FunctionPointerWithContext< const ConnectionCallbackParams_t * > ConnectionEventCallback_t
 Connection event handler. More...
typedef CallChainOfFunctionPointersWithContext< const ConnectionCallbackParams_t * > ConnectionEventCallbackChain_t
 Callchain of connection event handlers. More...
typedef FunctionPointerWithContext< const DisconnectionCallbackParams_t * > DisconnectionEventCallback_t
 Disconnection event handler. More...
typedef CallChainOfFunctionPointersWithContext< const DisconnectionCallbackParams_t * > DisconnectionEventCallbackChain_t
 Callchain of disconnection event handlers. More...
typedef FunctionPointerWithContext< bool > RadioNotificationEventCallback_t
 Radio notification event handler. More...
typedef FunctionPointerWithContext< const Gap * > GapShutdownCallback_t
 Gap shutdown event handler. More...
typedef CallChainOfFunctionPointersWithContext< const Gap * > GapShutdownCallbackChain_t
 Callchain of gap shutdown event handler. More...
Public Member Functions
virtual ble_error_t setAddress (BLEProtocol::AddressType_t type, const BLEProtocol::AddressBytes_t address)
 Set the device MAC address and type. More...
virtual ble_error_t getAddress (BLEProtocol::AddressType_t *typeP, BLEProtocol::AddressBytes_t address)
 Fetch the current address and its type. More...
virtual uint16_t getMinAdvertisingInterval (void) const
 Get the minimum advertising interval in milliseconds, which can be used for connectable advertising types. More...
virtual uint16_t getMinNonConnectableAdvertisingInterval (void) const
 Get the minimum advertising interval in milliseconds, which can be used for nonconnectable advertising type. More...
virtual uint16_t getMaxAdvertisingInterval (void) const
 Get the maximum advertising interval in milliseconds. More...
virtual ble_error_t stopAdvertising (void)
 Stop the ongoing advertising procedure. More...
virtual ble_error_t connect (const BLEProtocol::AddressBytes_t peerAddr, PeerAddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams)
 Initiate a connection to a peer. More...
virtual ble_error_t connect (const BLEProtocol::AddressBytes_t peerAddr, BLEProtocol::AddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams)
 Initiate a connection to a peer. More...
ble_error_t connect (const BLEProtocol::AddressBytes_t peerAddr, DeprecatedAddressType_t peerAddrType, const ConnectionParams_t *connectionParams, const GapScanningParams *scanParams)
 Initiate a connection to a peer. More...
virtual ble_error_t disconnect (Handle_t connectionHandle, DisconnectionReason_t reason)
 Initiate a disconnection procedure. More...
virtual ble_error_t disconnect (DisconnectionReason_t reason)
 Initiate a disconnection procedure. More...
virtual ble_error_t getPreferredConnectionParams (ConnectionParams_t *params)
 Returned the preferred connection parameters exposed in the GATT Generic Access Service. More...
virtual ble_error_t setPreferredConnectionParams (const ConnectionParams_t *params)
 Set the value of the preferred connection parameters exposed in the GATT Generic Access Service. More...
virtual ble_error_t updateConnectionParams (Handle_t handle, const ConnectionParams_t *params)
 Update connection parameters of an existing connection. More...
virtual ble_error_t setDeviceName (const uint8_t *deviceName)
 Set the value of the device name characteristic in the Generic Access Service. More...
virtual ble_error_t getDeviceName (uint8_t *deviceName, unsigned *lengthP)
 Get the value of the device name characteristic in the Generic Access Service. More...
virtual ble_error_t setAppearance (GapAdvertisingData::Appearance appearance)
 Set the value of the appearance characteristic in the GAP service. More...
virtual ble_error_t getAppearance (GapAdvertisingData::Appearance *appearanceP)
 Get the value of the appearance characteristic in the GAP service. More...
virtual ble_error_t setTxPower (int8_t txPower)
 Set the radio's transmit power. More...
virtual void getPermittedTxPowerValues (const int8_t **valueArrayPP, size_t *countP)
 Query the underlying stack for allowed Tx power values. More...
virtual uint8_t getMaxWhitelistSize (void) const
 Get the maximum size of the whitelist. More...
virtual ble_error_t getWhitelist (Whitelist_t &whitelist) const
 Get the Link Layer to use the internal whitelist when scanning, advertising or initiating a connection depending on the filter policies. More...
virtual ble_error_t setWhitelist (const Whitelist_t &whitelist)
 Set the value of the whitelist to be used during GAP procedures. More...
virtual ble_error_t setAdvertisingPolicyMode (AdvertisingPolicyMode_t mode)
 Set the advertising policy filter mode to be used during the next advertising procedure. More...
virtual ble_error_t setScanningPolicyMode (ScanningPolicyMode_t mode)
 Set the scan policy filter mode to be used during the next scan procedure. More...
virtual ble_error_t setInitiatorPolicyMode (InitiatorPolicyMode_t mode)
 Set the initiator policy filter mode to be used during the next connection initiation. More...
virtual AdvertisingPolicyMode_t getAdvertisingPolicyMode (void) const
 Get the current advertising policy filter mode. More...
virtual ScanningPolicyMode_t getScanningPolicyMode (void) const
 Get the current scan policy filter mode. More...
virtual InitiatorPolicyMode_t getInitiatorPolicyMode (void) const
 Get the current initiator policy filter mode. More...
GapState_t getState (void) const
 Get the current advertising and connection states of the device. More...
void setAdvertisingType (GapAdvertisingParams::AdvertisingType_t advType)
 Set the advertising type to use during the advertising procedure. More...
void setAdvertisingInterval (uint16_t interval)
 Set the advertising interval. More...
void setAdvertisingTimeout (uint16_t timeout)
 Set the advertising duration. More...
ble_error_t startAdvertising (void)
 Start the advertising procedure. More...
void clearAdvertisingPayload (void)
 Reset the value of the advertising payload advertised. More...
ble_error_t accumulateAdvertisingPayload (uint8_t flags)
 Set gap flags in the advertising payload. More...
ble_error_t accumulateAdvertisingPayload (GapAdvertisingData::Appearance app)
 Set the appearance field in the advertising payload. More...
ble_error_t accumulateAdvertisingPayloadTxPower (int8_t power)
 Set the Tx Power field in the advertising payload. More...
ble_error_t accumulateAdvertisingPayload (GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
 Add a new field in the advertising payload. More...
ble_error_t updateAdvertisingPayload (GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
 Update a particular field in the advertising payload. More...
ble_error_t setAdvertisingPayload (const GapAdvertisingData &payload)
 Set the value of the payload advertised. More...
const GapAdvertisingDatagetAdvertisingPayload (void) const
 Get a reference to the current advertising payload. More...
ble_error_t accumulateScanResponse (GapAdvertisingData::DataType type, const uint8_t *data, uint8_t len)
 Add a new field in the advertising payload. More...
void clearScanResponse (void)
 Reset the content of the scan response. More...
ble_error_t setScanParams (uint16_t interval=GapScanningParams::SCAN_INTERVAL_MAX, uint16_t window=GapScanningParams::SCAN_WINDOW_MAX, uint16_t timeout=0, bool activeScanning=false)
 Set the parameters used during a scan procedure. More...
ble_error_t setScanParams (const GapScanningParams &scanningParams)
 Set the parameters used during a scan procedure. More...
ble_error_t setScanInterval (uint16_t interval)
 Set the interval parameter used during scanning procedures. More...
ble_error_t setScanWindow (uint16_t window)
 Set the window parameter used during scanning procedures. More...
ble_error_t setScanTimeout (uint16_t timeout)
 Set the timeout parameter used during scanning procedures. More...
ble_error_t setActiveScanning (bool activeScanning)
 Enable or disable active scanning. More...
ble_error_t startScan (void(*callback)(const AdvertisementCallbackParams_t *params))
 Start the scanning procedure. More...
template<typename T >
ble_error_t startScan (T *object, void(T::*callbackMember)(const AdvertisementCallbackParams_t *params))
 Start the scanning procedure. More...
virtual ble_error_t initRadioNotification (void)
 Enable radio-notification events. More...
GapAdvertisingParamsgetAdvertisingParams (void)
 Get the current advertising parameters. More...
const GapAdvertisingParamsgetAdvertisingParams (void) const
 Const alternative to Gap::getAdvertisingParams(). More...
void setAdvertisingParams (const GapAdvertisingParams &newParams)
 Set the advertising parameters. More...
void onTimeout (TimeoutEventCallback_t callback)
 Register a callback handling timeout events. More...
TimeoutEventCallbackChain_tonTimeout ()
 Get the callchain of registered timeout event handlers. More...
void onConnection (ConnectionEventCallback_t callback)
 Register a callback handling connection events. More...
template<typename T >
void onConnection (T *tptr, void(T::*mptr)(const ConnectionCallbackParams_t *))
 Register a callback handling connection events. More...
ConnectionEventCallbackChain_tonConnection ()
 Get the callchain of registered connection event handlers. More...
void onDisconnection (DisconnectionEventCallback_t callback)
 Register a callback handling disconnection events. More...
template<typename T >
void onDisconnection (T *tptr, void(T::*mptr)(const DisconnectionCallbackParams_t *))
 Register a callback handling disconnection events. More...
DisconnectionEventCallbackChain_tonDisconnection ()
 Get the callchain of registered disconnection event handlers. More...
void onRadioNotification (void(*callback)(bool param))
 Set the radio-notification events handler. More...
template<typename T >
void onRadioNotification (T *tptr, void(T::*mptr)(bool))
 Set the radio-notification events handler. More...
void onShutdown (const GapShutdownCallback_t &callback)
 Register a Gap shutdown event handler. More...
template<typename T >
void onShutdown (T *objPtr, void(T::*memberPtr)(const Gap *))
 Register a Gap shutdown event handler. More...
GapShutdownCallbackChain_tonShutdown ()
 Access the callchain of shutdown event handler. More...
virtual ble_error_t reset (void)
 Reset the Gap instance. More...
void processConnectionEvent (Handle_t handle, Role_t role, PeerAddressType_t peerAddrType, const BLEProtocol::AddressBytes_t peerAddr, BLEProtocol::AddressType_t ownAddrType, const BLEProtocol::AddressBytes_t ownAddr, const ConnectionParams_t *connectionParams, const uint8_t *peerResolvableAddr=NULL, const uint8_t *localResolvableAddr=NULL)
 Notify all registered connection event handlers of a connection event. More...
void processConnectionEvent (Handle_t handle, Role_t role, BLEProtocol::AddressType_t peerAddrType, const BLEProtocol::AddressBytes_t peerAddr, BLEProtocol::AddressType_t ownAddrType, const BLEProtocol::AddressBytes_t ownAddr, const ConnectionParams_t *connectionParams, const uint8_t *peerResolvableAddr=NULL, const uint8_t *localResolvableAddr=NULL)
 Notify all registered connection event handlers of a connection event. More...
void processDisconnectionEvent (Handle_t handle, DisconnectionReason_t reason)
 Notify all registered disconnection event handlers of a disconnection event. More...
void processAdvertisementReport (const BLEProtocol::AddressBytes_t peerAddr, int8_t rssi, bool isScanResponse, GapAdvertisingParams::AdvertisingType_t type, uint8_t advertisingDataLen, const uint8_t *advertisingData, PeerAddressType_t addressType)
 Forward a received advertising packet to all registered event handlers listening for scanned packet events. More...
void processAdvertisementReport (const BLEProtocol::AddressBytes_t peerAddr, int8_t rssi, bool isScanResponse, GapAdvertisingParams::AdvertisingType_t type, uint8_t advertisingDataLen, const uint8_t *advertisingData, BLEProtocol::AddressType_t addressType=BLEProtocol::AddressType::RANDOM_STATIC)
 Forward a received advertising packet to all registered event handlers listening for scanned packet events. More...
void processTimeoutEvent (TimeoutSource_t source)
 Notify the occurrence of a timeout event to all registered timeout events handler. More...
void setEventHandler (EventHandler *handler)
 Assign the event handler implementation that will be used by the gap module to signal events back to the application. More...
virtual bool isFeatureSupported (controller_supported_features_t feature)
 Check controller support for a specific feature. More...
virtual uint8_t getMaxAdvertisingSetNumber ()
 Return currently available number of supported advertising sets. More...
virtual uint16_t getMaxAdvertisingDataLength ()
 Return maximum advertising data length supported. More...
virtual ble_error_t createAdvertisingSet (advertising_handle_t *handle, const AdvertisingParameters &parameters)
 Create an advertising set and apply the passed in parameters. More...
virtual ble_error_t destroyAdvertisingSet (advertising_handle_t handle)
 Remove the advertising set (resets its set parameters). More...
virtual ble_error_t setAdvertisingParameters (advertising_handle_t handle, const AdvertisingParameters &params)
 Set advertising parameters of an existing set. More...
virtual ble_error_t setAdvertisingPayload (advertising_handle_t handle, mbed::Span< const uint8_t > payload)
 Set new advertising payload for a given advertising set. More...
virtual ble_error_t setAdvertisingScanResponse (advertising_handle_t handle, mbed::Span< const uint8_t > response)
 Set new advertising scan response for a given advertising set. More...
virtual ble_error_t startAdvertising (advertising_handle_t handle, adv_duration_t maxDuration=adv_duration_t::forever(), uint8_t maxEvents=0)
 Start advertising using the given advertising set. More...
virtual ble_error_t stopAdvertising (advertising_handle_t handle)
 Stop advertising given advertising set. More...
virtual bool isAdvertisingActive (advertising_handle_t handle)
 Check if advertising is active for a given advertising set. More...
virtual ble_error_t setPeriodicAdvertisingParameters (advertising_handle_t handle, periodic_interval_t periodicAdvertisingIntervalMin, periodic_interval_t periodicAdvertisingIntervalMax, bool advertiseTxPower=true)
 Set periodic advertising parameters for a given advertising set. More...
virtual ble_error_t setPeriodicAdvertisingPayload (advertising_handle_t handle, mbed::Span< const uint8_t > payload)
 Set new periodic advertising payload for a given advertising set. More...
virtual ble_error_t startPeriodicAdvertising (advertising_handle_t handle)
 Start periodic advertising for a given set. More...
virtual ble_error_t stopPeriodicAdvertising (advertising_handle_t handle)
 Stop periodic advertising for a given set. More...
virtual bool isPeriodicAdvertisingActive (advertising_handle_t handle)
 Check if periodic advertising is active for a given advertising set. More...
virtual ble_error_t setScanParameters (const ScanParameters &params)
 Set new scan parameters. More...
virtual ble_error_t startScan (scan_duration_t duration=scan_duration_t::forever(), duplicates_filter_t filtering=duplicates_filter_t::DISABLE, scan_period_t period=scan_period_t(0))
 Start scanning. More...
virtual ble_error_t stopScan ()
 Stop the ongoing scanning procedure. More...
virtual ble_error_t createSync (peer_address_type_t peerAddressType, const address_t &peerAddress, uint8_t sid, slave_latency_t maxPacketSkip, sync_timeout_t timeout)
 Synchronize with periodic advertising from an advertiser and begin receiving periodic advertising packets. More...
virtual ble_error_t createSync (slave_latency_t maxPacketSkip, sync_timeout_t timeout)
 Synchronize with periodic advertising from an advertiser and begin receiving periodic advertising packets. More...
virtual ble_error_t cancelCreateSync ()
 Cancel sync attempt. More...
virtual ble_error_t terminateSync (periodic_sync_handle_t handle)
 Stop reception of the periodic advertising identified by the handle. More...
virtual ble_error_t addDeviceToPeriodicAdvertiserList (peer_address_type_t peerAddressType, const address_t &peerAddress, advertising_sid_t sid)
 Add device to the periodic advertiser list. More...
virtual ble_error_t removeDeviceFromPeriodicAdvertiserList (peer_address_type_t peerAddressType, const address_t &peerAddress, advertising_sid_t sid)
 Remove device from the periodic advertiser list. More...
virtual ble_error_t clearPeriodicAdvertiserList ()
 Remove all devices from periodic advertiser list. More...
virtual uint8_t getMaxPeriodicAdvertiserListSize ()
 Get number of devices that can be added to the periodic advertiser list. More...
virtual ble_error_t connect (peer_address_type_t peerAddressType, const address_t &peerAddress, const ConnectionParameters &connectionParams)
 Initiate a connection to a peer. More...
virtual ble_error_t cancelConnect ()
 Cancel the connection attempt. More...
virtual ble_error_t updateConnectionParameters (connection_handle_t connectionHandle, conn_interval_t minConnectionInterval, conn_interval_t maxConnectionInterval, slave_latency_t slaveLatency, supervision_timeout_t supervision_timeout, conn_event_length_t minConnectionEventLength=conn_event_length_t(0), conn_event_length_t maxConnectionEventLength=conn_event_length_t(0))
 Update connection parameters of an existing connection. More...
virtual ble_error_t manageConnectionParametersUpdateRequest (bool userManageConnectionUpdateRequest)
 Allows the application to accept or reject a connection parameters update request. More...
virtual ble_error_t acceptConnectionParametersUpdate (connection_handle_t connectionHandle, conn_interval_t minConnectionInterval, conn_interval_t maxConnectionInterval, slave_latency_t slaveLatency, supervision_timeout_t supervision_timeout, conn_event_length_t minConnectionEventLength=conn_event_length_t(0), conn_event_length_t maxConnectionEventLength=conn_event_length_t(0))
 Accept update of the connection parameters. More...
virtual ble_error_t rejectConnectionParametersUpdate (connection_handle_t connectionHandle)
 Reject a request to change the connection parameters. More...
virtual ble_error_t disconnect (connection_handle_t connectionHandle, local_disconnection_reason_t reason)
 Initiate a disconnection procedure. More...
virtual ble_error_t readPhy (connection_handle_t connection)
 Read the PHY used by the transmitter and the receiver on a connection. More...
virtual ble_error_t setPreferredPhys (const phy_set_t *txPhys, const phy_set_t *rxPhys)
 Set the preferred PHYs to use in a connection. More...
virtual ble_error_t setPhy (connection_handle_t connection, const phy_set_t *txPhys, const phy_set_t *rxPhys, coded_symbol_per_bit_t codedSymbol)
 Update the PHY used by a connection. More...
virtual ble_error_t enablePrivacy (bool enable)
 Enable or disable privacy mode of the local device. More...
virtual ble_error_t setPeripheralPrivacyConfiguration (const peripheral_privacy_configuration_t *configuration)
 Set the privacy configuration used by the peripheral role. More...
virtual ble_error_t getPeripheralPrivacyConfiguration (peripheral_privacy_configuration_t *configuration)
 Get the privacy configuration used by the peripheral role. More...
virtual ble_error_t setCentralPrivacyConfiguration (const central_privay_configuration_t *configuration)
 Set the privacy configuration used by the central role. More...
virtual ble_error_t getCentralPrivacyConfiguration (central_privay_configuration_t *configuration)
 Get the privacy configuration used by the central role. More...
Static Public Member Functions
static uint16_t MSEC_TO_GAP_DURATION_UNITS (uint32_t durationInMillis)
 Convert milliseconds into 1.25ms units. More...
static ble_error_t getRandomAddressType (const BLEProtocol::AddressBytes_t address, RandomAddressType_t *addressType)
 Return the type of a random address. More...
Static Public Attributes
static const unsigned ADDR_LEN = BLEProtocol::ADDR_LEN
 Length (in octets) of the BLE MAC address. More...
static const uint16_t UNIT_1_25_MS = 1250
 Number of microseconds in 1.25 milliseconds. More...
static const peripheral_privacy_configuration_t default_peripheral_privacy_configuration
 Default peripheral privacy configuration. More...
static const central_privay_configuration_t default_central_privacy_configuration
 Default peripheral privacy configuration. More...
Protected Member Functions
virtual ble_error_t startRadioScan (const GapScanningParams &scanningParams)
 Start scanning procedure in the underlying BLE stack. More...
 Gap ()
 Construct a Gap instance. More...
Protected Attributes
GapAdvertisingParams _advParams
 Current advertising parameters. More...
GapAdvertisingData _advPayload
 Current advertising data. More...
GapScanningParams _scanningParams
 Current scanning parameters. More...
GapAdvertisingData _scanResponse
 Current scan response. More...
uint8_t connectionCount
 Number of open connections. More...
GapState_t state
 Current GAP state. More...
bool scanningActive
 Active scanning flag. More...
TimeoutEventCallbackChain_t timeoutCallbackChain
 Callchain containing all registered callback handlers for timeout events. More...
RadioNotificationEventCallback_t radioNotificationCallback
 The registered callback handler for radio notification events. More...
AdvertisementReportCallback_t onAdvertisementReport
 The registered callback handler for scanned advertisement packet notifications. More...
ConnectionEventCallbackChain_t connectionCallChain
 Callchain containing all registered callback handlers for connection events. More...
DisconnectionEventCallbackChain_t disconnectionCallChain
 Callchain containing all registered callback handlers for disconnection events. More...

GAP example

Here is an example demonstrating how to use the GAP API to advertise, scan, connect and disconnect and how parameters influence efficiency of these actions.

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <events/mbed_events.h>
#include <mbed.h>
#include "ble/BLE.h"

/** This example demonstrates all the basic setup required
 *  to advertise, scan and connect to other devices.
 *
 *  It contains a single class that performs both scans and advertisements.
 *
 *  The demonstrations happens in sequence, after each "mode" ends
 *  the demo jumps to the next mode to continue. There are several modes
 *  that show scanning and several showing advertising. These are configured
 *  according to the two arrays containing parameters. During scanning
 *  a connection will be made to a connectable device upon its discovery.
 */

static const uint8_t DEVICE_NAME[]        = "GAP_device";

/* Duration of each mode in milliseconds */
static const size_t MODE_DURATION_MS      = 6000;

/* Time between each mode in milliseconds */
static const size_t TIME_BETWEEN_MODES_MS = 2000;

/* how long to wait before disconnecting in milliseconds */
static const size_t CONNECTION_DURATION = 3000;

typedef struct {
    GapAdvertisingParams::AdvertisingType_t adv_type;
    uint16_t interval;
    uint16_t timeout;
} AdvModeParam_t;

typedef struct {
    uint16_t interval;
    uint16_t window;
    uint16_t timeout;
    bool active;
} ScanModeParam_t;

/** the entries in this array are used to configure our advertising
 *  parameters for each of the modes we use in our demo */
static const AdvModeParam_t advertising_params[] = {
    /*            advertising type                        interval  timeout */
    { GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED,      40,/*ms*/ 3/*s*/},
    { GapAdvertisingParams::ADV_SCANNABLE_UNDIRECTED,       100,       4     },
    { GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED, 100,       0     }
};

/* when we cycle through all our advertising modes we will move to scanning modes */

/** the entries in this array are used to configure our scanning
 *  parameters for each of the modes we use in our demo */
static const ScanModeParam_t scanning_params[] = {
/* interval      window    timeout       active */
    {   4,/*ms*/   4,/*ms*/   0,/*s*/    false },
    { 160,       100,         3,         false },
    { 160,        40,         0,         true  },
    { 500,        10,         0,         false }
};

/* parameters to use when attempting to connect to maximise speed of connection */
static const GapScanningParams connection_scan_params(
    GapScanningParams::SCAN_INTERVAL_MAX,
    GapScanningParams::SCAN_WINDOW_MAX,
    3,
    false
);

/* get number of items in our arrays */
static const size_t SCAN_PARAM_SET_MAX =
    sizeof(scanning_params) / sizeof(GapScanningParams);
static const size_t ADV_PARAM_SET_MAX  =
    sizeof(advertising_params) / sizeof(GapAdvertisingParams);

static const char* to_string(Gap::Phy_t phy) {
    switch(phy.value()) {
        case Gap::Phy_t::LE_1M:
            return "LE 1M";
        case Gap::Phy_t::LE_2M:
            return "LE 2M";
        case Gap::Phy_t::LE_CODED:
            return "LE coded";
        default:
            return "invalid PHY";
    }
}

/** Demonstrate advertising, scanning and connecting
 */
class GAPDevice : private mbed::NonCopyable<GAPDevice>, public Gap::EventHandler
{
public:
    GAPDevice() :
        _ble(BLE::Instance()),
        _led1(LED1, 0),
        _set_index(0),
        _is_in_scanning_mode(false),
        _is_connecting(false),
        _on_duration_end_id(0),
        _scan_count(0) { };

    ~GAPDevice()
    {
        if (_ble.hasInitialized()) {
            _ble.shutdown();
        }
    };

    /** Start BLE interface initialisation */
    void run()
    {
        ble_error_t error;

        if (_ble.hasInitialized()) {
            printf("Ble instance already initialised.\r\n");
            return;
        }

        /* this will inform us off all events so we can schedule their handling
         * using our event queue */
        _ble.onEventsToProcess(
            makeFunctionPointer(this, &GAPDevice::schedule_ble_events)
        );

        /* handle timeouts, for example when connection attempts fail */
        _ble.gap().onTimeout(
            makeFunctionPointer(this, &GAPDevice::on_timeout)
        );

        /* handle gap events */
        _ble.gap().setEventHandler(this);

        error = _ble.init(this, &GAPDevice::on_init_complete);

        if (error) {
            printf("Error returned by BLE::init.\r\n");
            return;
        }

        /* to show we're running we'll blink every 500ms */
        _event_queue.call_every(500, this, &GAPDevice::blink);

        /* this will not return until shutdown */
        _event_queue.dispatch_forever();
    };

private:
    /** This is called when BLE interface is initialised and starts the first mode */
    void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
    {
        if (event->error) {
            printf("Error during the initialisation\r\n");
            return;
        }

        /* print device address */
        Gap::AddressType_t addr_type;
        Gap::Address_t addr;
        _ble.gap().getAddress(&addr_type, addr);
        printf("Device address: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
               addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);

        /* setup the default phy used in connection to 2M to reduce power consumption */
        Gap::PhySet_t tx_phys(/* 1M */ false, /* 2M */ true, /* coded */ false);
        Gap::PhySet_t rx_phys(/* 1M */ false, /* 2M */ true, /* coded */ false);
        ble_error_t err = _ble.gap().setPreferredPhys(&tx_phys, &rx_phys);
        if (err) {
            printf("INFO: GAP::setPreferedPhys failed with error code %s", BLE::errorToString(err));
        }

        /* all calls are serialised on the user thread through the event queue */
        _event_queue.call(this, &GAPDevice::demo_mode_start);
    };

    /** queue up start of the current demo mode */
    void demo_mode_start()
    {
        if (_is_in_scanning_mode) {
            /* when scanning we want to connect to a peer device so we need to
             * attach callbacks that are used by Gap to notify us of events */
            _ble.gap().onConnection(this, &GAPDevice::on_connect);
            _ble.gap().onDisconnection(this, &GAPDevice::on_disconnect);

            _event_queue.call(this, &GAPDevice::scan);
        } else {
            _event_queue.call(this, &GAPDevice::advertise);
        }

        /* for performance measurement keep track of duration of the demo mode */
        _demo_duration.start();
        /* keep track of our state */
        _is_connecting = false;

        /* queue up next demo mode */
        _on_duration_end_id = _event_queue.call_in(
            MODE_DURATION_MS, this, &GAPDevice::on_duration_end
        );

        printf("\r\n");
    }

    /** Set up and start advertising */
    void advertise()
    {
        ble_error_t error;
        GapAdvertisingData advertising_data;

        /* add advertising flags */
        advertising_data.addFlags(GapAdvertisingData::LE_GENERAL_DISCOVERABLE
                                  | GapAdvertisingData::BREDR_NOT_SUPPORTED);

        /* add device name */
        advertising_data.addData(
            GapAdvertisingData::COMPLETE_LOCAL_NAME,
            DEVICE_NAME,
            sizeof(DEVICE_NAME)
        );

        error = _ble.gap().setAdvertisingPayload(advertising_data);

        if (error) {
            printf("Error during Gap::setAdvertisingPayload\r\n");
            return;
        }

        /* set the advertising parameters according to currently selected set,
         * see @AdvertisingType_t for explanation of modes */
        GapAdvertisingParams::AdvertisingType_t adv_type =
            advertising_params[_set_index].adv_type;

        /* how many milliseconds between advertisements, lower interval
         * increases the chances of being seen at the cost of more power */
        uint16_t interval = advertising_params[_set_index].interval;

        /* advertising will continue for this many seconds or until connected */
        uint16_t timeout = advertising_params[_set_index].timeout;

        _ble.gap().setAdvertisingType(adv_type);
        _ble.gap().setAdvertisingInterval(interval);
        _ble.gap().setAdvertisingTimeout(timeout);

        error = _ble.gap().startAdvertising();

        if (error) {
            printf("Error during Gap::startAdvertising.\r\n");
            return;
        }

        printf("Advertising started (type: 0x%x, interval: %dms, timeout: %ds)\r\n",
               adv_type, interval, timeout);
    };

    /** Set up and start scanning */
    void scan()
    {
        ble_error_t error;

        /* scanning happens repeatedly, interval is the number of milliseconds
         * between each cycle of scanning */
        uint16_t interval = scanning_params[_set_index].interval;

        /* number of milliseconds we scan for each time we enter
         * the scanning cycle after the interval set above */
        uint16_t window = scanning_params[_set_index].window;

        /* how long to repeat the cycles of scanning in seconds */
        uint16_t timeout = scanning_params[_set_index].timeout;

        /* active scanning will send a scan request to any scanable devices that
         * we see advertising */
        bool active = scanning_params[_set_index].active;

        /* set the scanning parameters according to currently selected set */
        error = _ble.gap().setScanParams(interval, window, timeout, active);

        if (error) {
            printf("Error during Gap::setScanParams\r\n");
            return;
        }

        /* start scanning and attach a callback that will handle advertisements
         * and scan requests responses */
        error = _ble.gap().startScan(this, &GAPDevice::on_scan);

        if (error) {
            printf("Error during Gap::startScan\r\n");
            return;
        }

        printf("Scanning started (interval: %dms, window: %dms, timeout: %ds).\r\n",
               interval, window, timeout);
    };

    /** After a set duration this cycles to the next demo mode
     *  unless a connection happened first */
    void on_duration_end()
    {
        print_performance();

        /* alloted time has elapsed, move to next demo mode */
        _event_queue.call(this, &GAPDevice::demo_mode_end);
    };

    /** Look at scan payload to find a peer device and connect to it */
    void on_scan(const Gap::AdvertisementCallbackParams_t *params)
    {
        /* keep track of scan events for performance reporting */
        _scan_count++;

        /* don't bother with analysing scan result if we're already connecting */
        if (_is_connecting) {
            return;
        }

        /* parse the advertising payload, looking for a discoverable device */
        for (uint8_t i = 0; i < params->advertisingDataLen; ++i) {
            /* The advertising payload is a collection of key/value records where
             * byte 0: length of the record excluding this byte
             * byte 1: The key, it is the type of the data
             * byte [2..N] The value. N is equal to byte0 - 1 */
            const uint8_t record_length = params->advertisingData[i];
            if (record_length == 0) {
                continue;
            }
            const uint8_t type = params->advertisingData[i + 1];
            const uint8_t *value = params->advertisingData + i + 2;

            /* connect to a discoverable device */
            if ((type == GapAdvertisingData::FLAGS)
                && (*value & GapAdvertisingData::LE_GENERAL_DISCOVERABLE)) {

                /* abort timeout as the mode will end on disconnection */
                _event_queue.cancel(_on_duration_end_id);

                printf("We found a connectable device\r\n");

                ble_error_t error = _ble.gap().connect(
                    params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC,
                    NULL, &connection_scan_params
                );

                if (error) {
                    printf("Error during Gap::connect\r\n");
                    /* since no connection will be attempted end the mode */
                    _event_queue.call(this, &GAPDevice::demo_mode_end);
                    return;
                }

                /* we may have already scan events waiting
                 * to be processed so we need to remember
                 * that we are already connecting and ignore them */
                _is_connecting = true;

                return;
            }

            i += record_length;
        }
    };

    /** This is called by Gap to notify the application we connected,
     *  in our case it immediately disconnects */
    void on_connect(const Gap::ConnectionCallbackParams_t *connection_event)
    {
        print_performance();

        printf("Connected in %dms\r\n", _demo_duration.read_ms());

        /* cancel the connect timeout since we connected */
        _event_queue.cancel(_on_duration_end_id);

        _event_queue.call_in(
            CONNECTION_DURATION, &_ble.gap(), &Gap::disconnect, Gap::REMOTE_USER_TERMINATED_CONNECTION
        );
    };

    /** This is called by Gap to notify the application we disconnected,
     *  in our case it calls demo_mode_end() to progress the demo */
    void on_disconnect(const Gap::DisconnectionCallbackParams_t *event)
    {
        printf("Disconnected\r\n");

        /* we have successfully disconnected ending the demo, move to next mode */
        _event_queue.call(this, &GAPDevice::demo_mode_end);
    };

    /**
     * Implementation of Gap::EventHandler::onReadPhy
     */
    virtual void onReadPhy(
        ble_error_t error,
        Gap::Handle_t connectionHandle,
        Gap::Phy_t txPhy,
        Gap::Phy_t rxPhy
    ) {
        if (error) {
            printf(
                "Phy read on connection %d failed with error code %s\r\n",
                connectionHandle,
                BLE::errorToString(error)
            );
        } else {
            printf(
                "Phy read on connection %d - Tx Phy: %s, Rx Phy: %s\r\n",
                connectionHandle,
                to_string(txPhy),
                to_string(rxPhy)
            );
        }
    }

    /**
     * Implementation of Gap::EventHandler::onPhyUpdateComplete
     */
    virtual void onPhyUpdateComplete(
        ble_error_t error,
        Gap::Handle_t connectionHandle,
        Gap::Phy_t txPhy,
        Gap::Phy_t rxPhy
    ) {
        if (error) {
            printf(
                "Phy update on connection: %d failed with error code %s\r\n",
                connectionHandle,
                BLE::errorToString(error)
            );
        } else {
            printf(
                "Phy update on connection %d - Tx Phy: %s, Rx Phy: %s\r\n",
                connectionHandle,
                to_string(txPhy),
                to_string(rxPhy)
            );
        }
    }

    /** called if timeout is reached during advertising, scanning
     *  or connection initiation */
    void on_timeout(const Gap::TimeoutSource_t source)
    {
        _demo_duration.stop();

        switch (source) {
            case Gap::TIMEOUT_SRC_ADVERTISING:
                printf("Stopped advertising early due to timeout parameter\r\n");
                break;
            case Gap::TIMEOUT_SRC_SCAN:
                printf("Stopped scanning early due to timeout parameter\r\n");
                break;
            case Gap::TIMEOUT_SRC_CONN:
                printf("Failed to connect after scanning %d advertisements\r\n", _scan_count);
                _event_queue.call(this, &GAPDevice::print_performance);
                _event_queue.call(this, &GAPDevice::demo_mode_end);
                break;
            default:
                printf("Unexpected timeout\r\n");
                break;
        }
    };

    /** clean up after last run, cycle to the next mode and launch it */
    void demo_mode_end()
    {
        /* reset the demo ready for the next mode */
        _scan_count = 0;
        _demo_duration.stop();
        _demo_duration.reset();

        /* cycle through all demo modes */
        _set_index++;

        /* switch between advertising and scanning when we go
         * through all the params in the array */
        if (_set_index >= (_is_in_scanning_mode? SCAN_PARAM_SET_MAX : ADV_PARAM_SET_MAX)) {
            _set_index = 0;
            _is_in_scanning_mode = !_is_in_scanning_mode;
        }

        _ble.shutdown();
        _event_queue.break_dispatch();
    };

    /** print some information about our radio activity */
    void print_performance()
    {
        /* measure time from mode start, may have been stopped by timeout */
        uint16_t duration = _demo_duration.read_ms();

        if (_is_in_scanning_mode) {
            /* convert ms into timeslots for accurate calculation as internally
             * all durations are in timeslots (0.625ms) */
            uint16_t interval_ts = GapScanningParams::MSEC_TO_SCAN_DURATION_UNITS(
                scanning_params[_set_index].interval
            );
            uint16_t window_ts = GapScanningParams::MSEC_TO_SCAN_DURATION_UNITS(
                scanning_params[_set_index].window
            );
            uint16_t duration_ts = GapScanningParams::MSEC_TO_SCAN_DURATION_UNITS(
                duration
            );
            /* this is how long we scanned for in timeslots */
            uint16_t rx_ts = (duration_ts / interval_ts) * window_ts;
            /* convert to milliseconds */
            uint16_t rx_ms = (rx_ts * GapScanningParams::UNIT_0_625_MS) / 1000;

            printf("We have scanned for %dms with an interval of %d"
                    " timeslot and a window of %d timeslots\r\n",
                    duration, interval_ts, window_ts);

            printf("We have been listening on the radio for at least %dms\r\n", rx_ms);

        } else /* advertising */ {

            /* convert ms into timeslots for accurate calculation as internally
             * all durations are in timeslots (0.625ms) */
            uint16_t interval_ts = GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(
                advertising_params[_set_index].interval
            );
            uint16_t duration_ts = GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(
                duration
            );
            /* this is how many times we advertised */
            uint16_t events = duration_ts / interval_ts;

            printf("We have advertised for %dms"
                   " with an interval of %d timeslots\r\n",
                   duration, interval_ts);

            /* non-scannable and non-connectable advertising
             * skips rx events saving on power consumption */
            if (advertising_params[_set_index].adv_type
                == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) {
                printf("We created at least %d tx events\r\n", events);
            } else {
                printf("We created at least %d tx and rx events\r\n", events);
            }
        }
    };

    /** Schedule processing of events from the BLE middleware in the event queue. */
    void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
    {
        _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents));
    };

    /** Blink LED to show we're running */
    void blink(void)
    {
        _led1 = !_led1;
    };

private:
    BLE                &_ble;
    events::EventQueue  _event_queue;
    DigitalOut          _led1;

    /* Keep track of our progress through demo modes */
    size_t              _set_index;
    bool                _is_in_scanning_mode;
    bool                _is_connecting;

    /* Remember the call id of the function on _event_queue
     * so we can cancel it if we need to end the mode early */
    int                 _on_duration_end_id;

    /* Measure performance of our advertising/scanning */
    Timer               _demo_duration;
    size_t              _scan_count;
};

int main()
{
    GAPDevice gap_device;

    while (1) {
        gap_device.run();
        wait_ms(TIME_BETWEEN_MODES_MS);
        printf("\r\nStarting next GAP demo mode\r\n");
    };

    return 0;
}

Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.