The Bluetooth specification defines 4 Generic Access Profile (GAP) roles for devices operating over a Low Energy physical transport [1]:
The Bluetooth Low Energy Host Stack implementation on the Kinetis KW40Z offers devices the possibility to change between any of the 4 roles at run time. This article will present the interaction with the Bluetooth Low Energy Host API needed to implement a GAP multiple role device.
Running the GAP roles requires the application to go through the following 3 steps:
The application needs to configure the stack parameters, e.g. advertising parameters, advertising data, scan parameters, callbacks. Note that configuration of the advertising parameters or scanning response and advertising data can be done only once if the values don’t change at runtime. The configuration is always made in the Link Layer Standby state.
The application needs to start advertising, scanning or initiate connection.
When changing between roles, the Link layer must always go through the Link Layer Standby state.
The GAP Broadcaster or Peripheral sends advertising events. Additionally, the GAP Peripheral will accept the establishment of a LE link. This is why the GAP Observer will only support the Non Connectable Advertising mode (gAdvNonConnectable_c).
Both roles requires configuration of advertising data, advertising parameters. The configuration (gAppAdvertisingData, gAppScanRspData and gAdvParams) usually resides in app_config.c. The confirmation events for setting these parameters is received in BleApp_GenericCallback. The confirmation event for the changing state of advertising is received in BleApp_AdvertisingCallback.
/* Setup Advertising and scanning data */
Gap_SetAdvertisingData(&gAppAdvertisingData, &gAppScanRspData);
/* Setting only for GAP Broadcaster role */
gAdvParams. advertisingType = gAdvNonConnectable_c;
/* Set advertising parameters*/
Gap_SetAdvertisingParameters(&gAdvParams);
App_StartAdvertising(BleApp_AdvertisingCallback, BleApp_ConnectionCallback);
Gap_StopAdvertising();
The GAP Observer receives advertising events. Unlike the GAP Peripheral or Broadcaster, it does not need to set scanning parameters separately. It passes the configuration with the start procedure. The configuration (gAppScanParams) usually resides in app_config.c. The confirmation event for the changing state of scanning is received in BleApp_ScanningCallback.
App_StartScanning(&gAppScanParams, BleApp_ScanningCallback);
Gap_StopScanning ();
The GAP Central initiates the establishment of the LE link. Like the GAP Observer, it passes the configuration with the start procedure. The configuration (gConnReqParams) usually resides in app_config.c. The confirmation event for the changing state of link is received in BleApp_ConnectionCallback.
Gap_Connect(&gConnReqParams, BleApp_ConnectionCallback);
Gap_Disconnect(deviceId);
An out-of-the box example for multiple role is attached. The application named blood_pressure_multi_role implements a Blood Pressure GATT client and server and can switch between the following GAP roles: Peripheral, Observer and Central. The contents of the archive needs to be copied to the following location:
<Installer Path>\KW40Z_Connectivity_Software_1.0.1\ConnSw\examples\bluetooth\
The application can be found at:
<Install Path specified>\KW40Z_Connectivity_Software_1.0.1\ConnSw\examples\bluetooth\blood_pressure_multi_role\frdmkw40z\bare_metal\build\iar\blood_pressure_multi_role.eww
Press SW4. LED1 will start flashing and the console will show that the Link Layer enters Advertising. If the Link Layer was in a previous state, it will go through Standby.
static void BleApp_Advertise(void)
{
/* Ensure Link Layer is in Standby */
BleApp_GoToStandby();
shell_write(" GAP Role: Peripheral\n\r");
mGapRole = gGapPeripheral_c;
/* Start GAP Peripheral */
App_StartAdvertising(BleApp_AdvertisingCallback, BleApp_ConnectionCallback);
}
Press SW3. A chasing LED pattern will start and the console will show that the Link Layer enters Scanning. If the Link Layer was in a previous state, it will go through Standby.
static void BleApp_Scan(void)
{
/* Ensure Link Layer is in Standby */
BleApp_GoToStandby();
shell_write(" GAP Role: Observer\n\r");
mGapRole = gGapObserver_c;
/* Start GAP Observer */
App_StartScanning(&gAppScanParams, BleApp_ScanningCallback);
}
If the Link Layer is in scanning and finds a Blood Pressure Sensor, it will go through Standby and initiate connection.
static void BleApp_Connect(void)
{
/* Ensure Link Layer is in Standby */
BleApp_GoToStandby();
shell_write(" GAP Role: Central\n\r");
mGapRole = gGapCentral_c;
/* Start GAP Central */
Gap_Connect(&gConnReqParams, BleApp_ConnectionCallback);
}
Pressing SW3 for more than 2 seconds, brings the Link Layer back in Standby.
static void BleApp_GoToStandby(void)
{
/* Check if connection is on */
if (mPeerInformation.deviceId != gInvalidDeviceId_c)
{
/* Stop GAP Central or Peripheral */
Gap_Disconnect(mPeerInformation.deviceId);
}
if (mAdvOn)
{
/* Stop GAP Peripheral or Bradcaster */
Gap_StopAdvertising();
}
if (mScanningOn)
{
/* Stop GAP Observer */
Gap_StopScanning();
}
}
[1] BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C], 2.2 PROFILE ROLES