11. The BLE Framework

Figure 7 depicts the general architectural scheme used.

../_images/image05_01.png

Figure 7 BLE framework architecture

Using a top-down approach, the layers that build-up the BLE framework functionality can be identified as the following:

  1. The BLE service framework which is a library that provides implemented BLE services that the application can use “out-of-the-box”, using simple initialization functions and defining callbacks for the various BLE service events (like the change of an alert level attribute). The functionality of the BLE service framework is built on top of the Dialog BLE API library. The BLE service API header files can be found under <sdk_root_directory>/sdk/interfaces/ble_services/include. The BLE service framework is called in the context of the Application.
  2. The Dialog BLE API is a set of functions that can be used to initiate BLE operations or respond to BLE events. The API header files can be found under the path <sdk_root_directory>/sdk/interfaces/ble/include. The API functions constitute a library that can be used to send messages (commands or replies to events) to the BLE manager, using queues between the application task and the BLE manager task which makes the application thread-safe. The BLE API is called in the context of the Application.
  3. The BLE manager provides the interface to the BLE functionality of the chip. Application tasks that are based on BLE functionality use the Dialog BLE API to interface with the BLE manager. The BLE manager is a task that stands between the application and the BLE adapter. It uses the BLE adapter to interface with the BLE stack. The BLE manager uses a Generic Transport Layer (GTL) to communicate with the BLE adapter through a command and event queue.

The BLE Manager runs in its own task.

  1. The BLE adapter is the system task that provides the interface to the BLE stack which is in the ROM code. It runs the BLE stack internal scheduler, handles the BLE interrupts, receives the commands or the replies to events from the BLE manager, and passes BLE events to the BLE manager. BLE core functionality is implemented by the BLE adapter task.
  2. The BLE stack is the software stack that interfaces with the BLE IP and implements the Link Layer and the host stack, specifically the Logical Link Control and Adaptation Protocol (L2CAP), the Security Manager Protocol (SMP), the Attribute Protocol (ATT), the Generic Attribute Profile (GATT) and the Generic Access Profile (GAP). The BLE stack software is stored in the system’s ROM and its API header files can be found under <sdk_root_directory>/sdk/interfaces/ble/src/stack. The BLE stack default configuration can be modified by editing <sdk_root_directory>/sdk/interfaces/ble/src/stack/config/ble_stack_config.h. The BLE stack software is run under the BLE adapter’s task context, which instantiates and initializes the stack.

11.1. Developing BLE Applications

One of the main goals of the SmartSnippets™ DA1468x SDK is to simplify the development of Bluetooth low energy applications and achieve a fast time to market. The SmartSnippets™ DA1468x SDK separates the application logic from the BLE stack implementation and provide a clean and powerful API to interact with the Bluetooth low energy capabilities of the device. The BLE framework API gives easy access to configure the BLE manager, start air operations and set up an attribute database inside a GATT server. The BLE service API provides access to predefined Bluetooth SIG profiles with the definition of only a few call-back functions.

The Proximity (pxp_reporter) Reporter application described in Software Developer’s Guide [Ref_03] is the most typical of the BLE applications that are included in the SmartSnippets™ DA1468x SDK. It is a complete and solid example of a BLE application developed on top of the SmartSnippets™ DA1468x SDK. It uses both the Dialog BLE API and the BLE service framework to implement the functionality of a Bluetooth low energy profile.

However, it may not be the simplest example or the best starting point to become familiar with the development of a Bluetooth low energy application from scratch. Instead, there are Bluetooth low energy projects specifically created to serve as starting points for specific Bluetooth low energy applications such as beacons (ble_adv_demo) or for specific roles such as a generic peripheral (ble_peripheral) or central (ble_central) device .

This section aims to introduce the various options and examples that exist in the SmartSnippets™ DA1468x SDK which can be used as building blocks for many applications. After a short introduction on where the API header files can be found, each section describes the functionality they implement along with guidance on how they differ from each other. This information is essential when starting a Bluetooth low energy application from scratch.

11.2. The BLE API header files

11.2.1. Dialog BLE API

All demos and services API are found in the doxygen documentation. This can be found either at <sdk_root_directory>/docs/html/index.html or via the Open API Documentation button on the welcome page of SmartSnippets™ Studio.

In most projects these API header files are symbolically linked to files can be found under

<sdk_root_directory>/sdk/ble/include.

The API functions are declared across several header files depending on their functionality:

  • Common API (ble_common.h): Functions used for operations, not specific to a specific BLE host software component. For example:
Table 9 API Functions of the common BLE host software component
Function Description
ble_register_app() Register the application to the BLE framework so that it can receive BLE event notifications.
ble_enable() Enable the BLE framework.
ble_reset() Reset the BLE framework.
ble_central_start() Start the device as a BLE central. This is actually a helper function, since it uses API calls ble_enable() and ble_gap_role_set().
ble_peripheral_start() Start the device as a BLE peripheral. This is also a helper function that uses ble_enable() and ble_gap_role_set().
ble_get_event() Get a BLE event from the BLE manager’s event queue.
ble_has_event() Check if there is an event pending at the BLE manager’s event queue.
ble_handle_event_default() Used to define handling of events that are not handled by the added services or the application defined handlers.
  • GAP & L2CAP APIs (ble_gap.h/ble_l2cap.h): Covers a wide range of operations, like
    • Device parameters configuration: device role, MTU size, device name exposed in the GAP service attribute, etc.
    • Air operations: Advertise, scan, connect, respond to connection requests, initiate or respond to connection parameters update, etc.
    • Security operations: Initiate and respond to a pairing or bonding procedure, set the security level, unpair, etc.
Table 10 GAP and L2CAP API functions
Function Description
BLE device configuration
ble_gap_role_set() Set the GAP role.
ble_gap_mtu_size_get() Get the MTU size currently set.
ble_gap_mtu_size_set() Set the MTU size.
ble_gap_channel_map_get() Get the currently set channel map of the device (the device musthas to be configured as central).
ble_gap_channel_map_set() Set the channel map of the device (device must be configured as central).
ble_gap_address_get() Get the currently set BD address of the device.
ble_gap_address_set() Set the BD address of the device.
ble_gap_device_name_get() Get the device name used for the GAP service.
ble_gap_device_name_set() Set the device name used for the GAP service.
ble_gap_appearance_get() Get the appearance used for the GAP service.
ble_gap_appearance_set() Set the appearance used for the GAP service.
ble_gap_per_pref_conn_params_get() Get the peripheral preferred connection parameters used for the GAP service.
ble_gap_per_pref_conn_params_set() Set the peripheral preferred connection parameters used for the GAP service.
ble_gap_set_io_cap() Set the I/O capabilities of the device (combined with the peer’s I/O capabilities, this will determine which pairing algorithm will be used).
ble_gap_data_length_set() Set the data length to be used for TX on new connections.
   
Advertising
ble_gap_adv_start() Start advertising.
ble_gap_adv_stop() Stop advertising.
ble_gap_adv_data_set() Set the Advertising Data and Scan Response Data used.
ble_gap_adv_intv_set() Set the advertising intervals prior to advertising start.
ble_gap_adv_chnl_map_set() Set the advertising channel map prior to advertising start.
ble_gap_adv_mode_set() Set the discoverability mode used for advertising prior to advertising start.
ble_gap_adv_direct_address_set() Set the peer address used for directed advertising prior to advertising start.
   
Scanning
ble_gap_scan_start() Start scanning for devices.
ble_gap_scan_stop() Stop scanning for devices.
   
Connection management
ble_gap_scan_params_get() Get the scan parameters used for connections.
ble_gap_scan_params_set() Set the scan parameters used for connections.
ble_gap_connect() Initiate a direct connection to a device.
ble_gap_connect_ce() Initiate a direct connection with an app-defined minimum and maximum connection event length
ble_gap_connect_cancel() Cancel an initiated connection procedure.
ble_gap_disconnect() Initiate a disconnection procedure on an established link.
ble_gap_conn_rssi_get() Retrieve the RSSI of a connection.
ble_gap_conn_param_update() Initiate a connection parameter update.
ble_gap_conn_param_update_reply() Reply to a connection parameter update request.
ble_gap_data_length_set() Set the data length used for TX for a specified connection.
   
Security
ble_gap_pair() Start pairing.
ble_gap_pair_reply() Respond to a pairing request.
ble_gap_passkey_reply() Respond to a passkey request.
ble_gap_numeric_reply() Respond to a numeric comparison request (Secure Connections only).
ble_gap_get_sec_level() Get connection security level.
ble_gap_set_sec_level() Set connection security level.
ble_gap_unpair() Unpair device (will also remove bond data from BLE storage).
   
Helper functions
ble_gap_get_connected() Get list of connected devices.
ble_gap_get_bonded() Get list of bonded devices.
ble_gap_get_devices() Return list of known devices based on filter.
ble_gap_get_device_by_addr() Get the device object, given the device address.
ble_gap_get_device_by_conn_idx() Get device object, given the connection index.
ble_gap_is_bonded() Get bond state of device (by connection index).
ble_gap_is_addr_bonded() Get bond state of device (by address).
   
Expert functions
ble_gap_skip_latency() Temporarily ignore the connection latency.
  • GATT server API (ble_gatts.h): Set up the attribute database, set attribute values, notify/indicate characteristic values, initiate MTU exchanges, respond to write and read requests, etc.
Table 11 GATT server API
Function Description
ble_gatts_add_service() Add a new GATT service to the ATT database. Subsequent calls to ble_gatts_add_include(), ble_gatts_add_characteristic() and ble_gatts_add_descriptor() will add attributes to the service added by this call.
ble_gatts_add_include() Add an included service declaration to the service added by ble_gatts_add_service().
ble_gatts_add_characteristic() Add a characteristic declaration to the service added by ble_gatts_add_service().
ble_gatts_add_descriptor() Add a descriptor declaration to the service added by ble_gatts_add_service().
ble_gatts_register_service() Add to the ATT database all attributes previously added to the service.
ble_gatts_enable_service() Enable service in database.
ble_gatts_disable_service() Disable service in database.
ble_gatts_get_characteristic_prop() Read current characteristic properties and permissions.
ble_gatts_set_characteristic_prop() Set characteristic properties and permissions.
ble_gatts_get_value() Get attribute value.
ble_gatts_set_value() Set attribute value.
ble_gatts_read_cfm() Confirmation response to an attribute read request.
ble_gatts_write_cfm() Confirmation response to an attribute write request.
ble_gatts_prepare_write_cfm() Confirmation response to an attribute prepare write request.
ble_gatts_send_event() Send a characteristic value notification or indication.
ble_gatts_service_changed_ind() Send indication of the Service Changed Characteristic.
ble_gatts_get_num_attr() Calculate the number of attributes required for a service.
  • GATT client API (ble_gattc.h): Used by a device configured as a GATT client to discover the services, characteristics, etc. of a peer device, read or write its attributes, initiate MTU exchanges, confirm the reception of indications, etc.
Table 12 GATT client API
Function Description
ble_gattc_browse() Browse services on a remote GATT server.
ble_gattc_discover_svc() Discover services on a remote GATT server.
ble_gattc_discover_include() Discover included services on a remote GATT server.
ble_gattc_discover_char() Discover characteristics on a remote GATT server.
ble_gattc_discover_desc() Discover descriptors on a remote GATT server.
ble_gattc_read() Read a characteristic value or a characteristic descriptor from the remote GATT server, depending on the attribute handle.
ble_gattc_write() Write a characteristic value or a characteristic descriptor to the remote GATT server, depending on the attribute handle.
ble_gattc_write_no_resp() Write attribute to remote GATT server without response.
ble_gattc_write_prepare() Prepare long/reliable write to remote GATT server.
ble_gattc_write_execute() Execute long/reliable write to remote GATT server.
ble_gattc_indication_cfm() Send confirmation for received indication.
ble_gattc_get_mtu() Get current TX MTU of peer.
ble_gattc_exchange_mtu() Exchange MTU.

Note

Several GAP configuration functions must be called before the attribute database is created, because modifying the device’s configuration can clear the attribute database created up to that point. This is noted in the Doxygen headers of the configuration functions that can have this effect.

11.2.2. Dialog BLE service API

The BLE service API header files are in <sdk_root_directory>/sdk/interfaces/ble_services/include. In most projects the API header files are symbolically linked to <sdk_root_directory>/sdk/ble_services/include.

The services-specific API, call-back function prototypes and definitions are included in each service’s header file. The services implemented are the following:

Table 13 Header files for the BLE services
Header file Description
bas.h Battery Service.
bcs.h Body Composition Service.
ble_service Services handling routines API.
bms.h Bond Management Service.
cts.h Current Time Service.
dis.h Device Information Service.
dlg_debug Debug service API.
dlg_suota SUOTA service implementation API.
hids.h Human Interface Device Service.
hrs.h Heart Rate Service.
ias.h Immediate Alert Service.
lls.h Link Loss Service.
scps.h Scan Parameter Service.
sps.h Serial Port Service.
svc_defines Common definitions for all services.
svc_types Characteristics common types.
tps.h Tx Power Service.
uds.h User Data Service.
wss.h Weight Scale Service.

All services have an initialization function defined. This function is called with arguments that vary for different services.

The most common argument is a pointer to one or more call-back functions that should be called upon a service-specific event. For example, the prototype for the initialization function of the Immediate Alert Service (ias.h) is the following:

Code 6 Initialization code for Immediate Alert Service
ble_service_t *ias_init(ias_alert_level_cb_t alert_level_cb)

Function ias_init() has only one argument. It is a pointer to the call-back function that will be called when a peer device has modified the value of the Immediate Alert Level characteristic. This callback function is part of the user application code and should provide the application handling required for the change to the Immediate Alert Level.

The return value from all initialization functions is the created service’s handle which is used to reference the service in the application. So for example the handle will be used as an argument for function ble_service_add() to add the created service to the BLE service framework (in SDK release 1.0.10 and later this is seamlessly done by the service initialization function and there is no need to explicitly use ble_service_add()).

The application only needs to use the service handle. However, to understand how the service interacts with the BLE framework it is useful to know what the handle represents. The handle is a pointer to a generic structure (ble_service_t) that defines how the service should interact with the framework. Within each service there is an internal service definition (XXX_service_t) as shown in Figure 8. This contains the generic service structure plus a set of handles, one for each GATT characteristic that the service implements. This XXX_service_t structure is populated by XXX_init() for that service. The start_h and end_h handles will contain the start and end positions of the attributes for this service within the overall GATT table provided by the GATT server. So, when a GATT client requests a Service Discovery from the server these represent the start and end handles that the client would use to access service XXX.

../_images/image05_21.png

Figure 8 Structure of a service handle

The set of optional callbacks allow each service to specify if it wants to do some specific handling on a certain event received by the BLE framework. If the service wants to be informed when another Bluetooth low energy device has connected to this device then it can define its own handle_connected_evt() function and plug it into the connected_evt callback. Each service declares its handle_connected_evt() function as static in xxx.c and by convention in the SmartSnippets™ SDK they all share the same function names in each service.

As each service is initialized and thus added to the BLE services framework with ble_service_add(), its generic services structure is added to a structure of supported services as shown in Figure 9.

../_images/image05_22.png

Figure 9 Structure of supported services

Now that the main internal services structure has been explained, it is easier to follow how the service initialization defines how the service operates.

Within the BLE service framework the main event handler is ble_service_handle_event() which is shown below.

Code 7 Handle BLE events using BLE service framework
bool ble_service_handle_event(const ble_evt_hdr_t *evt)
{
     switch (evt->evt_code) {
     case BLE_EVT_GAP_CONNECTED:
             connected_evt((const ble_evt_gap_connected_t *) evt);
             return false; // make it "not handled" so app can handle
     case BLE_EVT_GAP_DISCONNECTED:
             disconnected_evt((const ble_evt_gap_disconnected_t *) evt);
             return false; // make it "not handled" so app can handle
     case BLE_EVT_GATTS_READ_REQ:
             return read_req((const ble_evt_gatts_read_req_t *) evt);
     case BLE_EVT_GATTS_WRITE_REQ:
             return write_req((const ble_evt_gatts_write_req_t *) evt);
     case BLE_EVT_GATTS_PREPARE_WRITE_REQ:
             return prepare_write_req((const ble_evt_gatts_prepare_write_req_t *) evt);
     case BLE_EVT_GATTS_EVENT_SENT:
             return event_sent((const ble_evt_gatts_event_sent_t *) evt);
     }

     return false;
}

Each of these sub-handlers inside ble_service_handle_event() search throughout the added services to find one that has defined a behavior for this event. There are two types of events that are handled differently.

11.2.3. Connection Orientated Events

The connection and disconnection events are potentially of interest to all registered services and so all services can be informed. The cleanup on shutdown is handled in the same way.

For example a connection event will call the BLE service’s statically defined connected_evt() function (sdk/ble_services/src/ble_service.c). This will loop through all the services registered in services array and if for each service a connected_evt callback has been registered during initialization the callback function will be called.

11.2.4. Attribute Orientated Events

These are events that are to do with a given attribute handle. As each attribute is related to a unique service the first step in one of these handlers is to identify which service the attribute belongs to. For example a write request on a specific attribute will call the BLE service’s statically defined write_req() function (sdk/ble_services/src/ble_service.c) as shown below. This will first identify which service owns that attribute with find_service_by_handle(). Then if it has a write_req callback defined it executes the callback.

Code 8 Example of code for the Write Request
static bool write_req(const ble_evt_gatts_write_req_t *evt)
{
        ble_service_t *svc = find_service_by_handle(evt->handle);

        if (!svc) {
                return false;
        }

        if (svc->write_req) {
                svc->write_req(svc, evt);
        }

        return true;
}

An example of this flow is the Write No Response procedure that can be applied to the Immediate Alert Level characteristic of the Immediate Alert Service. When a GATT client requests a write to that characteristic it will trigger the write_req() sub-handler under ble_service_handle_event().

The write_req() sub-handler will use find_service_by_handle() to see if any of the added services are registered for that characteristic. It will match it with the Immediate Alert Service (IAS) and as the IAS has registered a Write Request handler the IAS handle_write_req() will be called (<sdk_root_directory>\sdk\interfaces\ble_services\src\ias.c).

Code 9 Example of code that handle the Write Request and match it with the appropriate instance
static void handle_write_req(ble_service_t *svc, const ble_evt_gatts_write_req_t *evt)
{
        ia_service_t *ias = (ia_service_t *) svc;
        att_error_t err = ATT_ERROR_OK;

        if (evt->length == 1) {
                uint8_t level;

                /*
                * This is write-only characteristic so we don't need to store value written
                * anywhere, can just handle it here and reply.
                */

                level = get_u8(evt->value);

                if (level > 2) {
                        err = ATT_ERROR_APPLICATION_ERROR;
                } else if (ias->cb) {
                        ias->cb(evt->conn_idx, level);
                }
        }

        ble_gatts_write_cfm(evt->conn_idx, evt->handle, err);
}

By calling ias->cb() function, this handler also actually calls the application supplied call-back function passed as an argument when ias_init() was called by the application. Finally, it sends a Write Confirmation to update the value at the attribute database maintained in the BLE stack.

This is only an example of the way the BLE service framework translates BLE events to BLE service events. Different events in different services can have different levels of complexity, but most of the times this complexity is contained within the BLE service API. The aim is that the application only needs to call the service’s initialization function and define the appropriate call-back functions to handle all service’s events.

In addition, some services define additional service-specific API calls. For instance, the Heart Rate Service implementation defines an API to trigger notifications of the Heart Rate Measurement characteristic, using functions hrs_notify_measurement() and hrs_notify_measurement_all() (the first is used to notify the characteristic to a specified peer, while the second is used to notify the characteristic to all subscribed peers). Some services also define some internal helper functions that are used to manipulate characteristic values, and some services require attribute initial values as arguments of the initialization function.

The BLE service API adds another layer to the general BLE API. Together the BLE adapter, BLE manager, BLE API library and BLE service framework results in the BLE framework.

The BLE services API provides an off the shelf solution to implement an application using many of the common adopted Bluetooth low energy services. The underlying BLE API and GATT server API can be used to create other adopted services or even custom services using the BLE services as a template.

The following sections will provide an overview of a generic application and then will describe in detail several of the example Bluetooth low energy projects included in the SmartSnippets™ DA1468x SDK:

Table 14 BLE projects included in the SmartSnippets™ DA1468x SDK
BLE projects General description
ble_adv_demo The simplest BLE project available in the SmartSnippets DA1468x SDK, which does not use the BLE service framework and exposes only the GAP and GATT services.
ble_peripheral A project that can be used as a template for developing BLE peripheral applications. The project includes some of the services implemented under the BLE service framework.
ble_central A project that can be used as a template for developing BLE central applications. The project starts by scanning and trying to connect to a device with a pre-defined BD address, and then discovers all services and characteristics of it.
ble_multi_link_demo This project demonstrates the Bluetooth LE Topology feature, using a custom service that can be used to “force” a device to be master on one connection and slave on another at the same time.
ble_external_host This project exposes an HCI controller interface on a UART. The BLE framework is bypassed in this case as the external host provides the Bluetooth stack.
ble_suota_client This application is a SUOTA 1.2 client implementation and allows to update SUOTA-enabled devices over the air, using a simple serial console interface.
power_demo This project is a simple connectable advertising demo. It is designed to let the user configure several parameters such as the advertising interval and the connection parameters using either UART commands or the GPIOs. User can select the various preconfigured settings and examine the effect on the power consumption that these settings have.

11.2.5. Configuring the project

In each project the BLE framework and BSP are configured via a set of custom config files that set the defines and macros used in that project. These files are found in the config directory of each project.

In the case of the ble_adv_demo project this file is config/custom_config_qspi.h

Any defines set in this file will override the default SDK values which are found in the following files:

sdk/config/bsp_defaults.h

sdk/ble/config/ble_config.h

sdk/bsp/free_rtos/include/FreeRTOSconfig.h

11.2.6. BLE application structure

All the Bluetooth low energy application projects in the SmartSnippets™ DA1468x SDK have a similar structure. This involves several FreeRTOS tasks at different priority levels (illustrated in Figure 6) to ensure that the overall systems real time requirements are met.

The Bluetooth low energy application is implemented in a FreeRTOS task that is created by the system_init() function. system_init() runs at the highest priority at startup and is also responsible for starting the BLE manager and BLE adapter tasks that run the Bluetooth low energy stack.

The application task has the following flow:

  1. Device initialization and configuration: Start-up BLE, setting device role, device name, appearance and other device parameters.
  2. Attribute database creation (GATT server devices): Creation of services and attributes using the BLE service framework. This must be done after (1) to prevent deletion of the attribute database.
  3. Air operation configuration and initiation: Bluetooth low energy peripheral devices usually end-up advertising and Bluetooth low energy central devices end-up scanning and/or attempting to connect to another device. This is the last operation to be done only once as the task then drops into its infinite loop.
  4. The infinite for(;;) loop, which is the application’s event handling loop. The application has been set-up as desired and now it is waiting for Bluetooth low energy events to respond to, like connections or write requests.
    • The BLE adapter (ad_ble) must have a higher priority than the application task(s) because it runs the lower stack scheduler. It handles time critical tasks, like applying connection parameter and channel map updates, and replying to Packet Data Units (PDU) from the peer on time. If the BLE adapter does not run in time because another task has a higher priority, BLE events and even connections may be lost.
    • Most of the Bluetooth low energy applications use the FreeRTOS task notifications mechanism to block. ble_adv_demo is the simplest application and is the only project that does not use this mechanism. Instead, it just blocks on the BLE manager’s event queue.
    • In addition to the BLE-related functionality most projects also use other system modules, like software timers or sensors. In this case, the application usually defines call-back functions to be triggered on these system events or interrupts. These callback functions should use task notifications to unblock the application task which can then handle the event or interrupt in the context of the task’s for(;;) loop. The reason for this is that the BLE framework must be accessed by only one application task

Warning

Calling a BLE API function inside a call-back function triggered on a timer expiry will execute the BLE API function in the timer’s task context. Calling other functions in the callback functions also can have implications on real time performance or in corrupting the small stack used by the timer task.

11.3. Bluetooth low energy Security

The Bluetooth specification defines the security options for device authentication and link encryption. These aspects of security are handled seamlessly by the BLE Framework. The API in Table 15 is able to set-up security, initiate pairing, do a security request or set-up encryption using previously exchanged keys. Most details of the procedures will be handled internally by the BLE Framework and the application will be notified only if intervention is needed or when the procedure is completed. These options will be described in detail in sections 11.3.1 and 11.3.4.

The generation and storage of the security keys and other bonding information is also handled by the BLE Framework. Persistent storage can also be used to enable storage of the security keys and bonding data info in the flash. The BLE Framework can then retrieve this information after a power cycle and use it to restore connections with previously bonded devices. This is described in 11.3.5.

11.3.1. Functions

Table 15 summarizes the API functions that can be used by the application to set-up security features.

Table 15 BLE Security API functions
API call Description
ble_gap_pair() Initiate a pairing or bonding procedure with a connected peer. Depending on whether the device is master or slave on the connection, this call will result either in a pairing or a security request respectively.
ble_gap_pair_reply() Reply to a received BLE_EVT_GAP_PAIR_REQ event. This event will only be received by a peripheral device when the central peer has initiated a pairing procedure, so this function should only be called by a peripheral application and only after a BLE_EVT_GAP_PAIR_REQ event has been received.
ble_gap_passkey_reply() Reply to a received BLE_EVT_GAP_PASSKEY_REQUEST event. This event will be received if the combination of the devices’ input/output capabilities results in a passkey entry pairing algorithm. The application should use this function to submit the passkey for the pairing procedure to proceed.
ble_gap_numeric_reply() Reply to a received BLE_EVT_GAP_NUMERIC_REQUEST event. This event will be received if the combination of the devices’ input/output capabilities results in a numeric comparison pairing algorithm. The application should use this function to accept or reject the numeric key for the pairing procedure to proceed. This should be only used if LE Secure Connections are enabled.
ble_gap_set_sec_level() Set the security level for a connection. If the device is already bonded, the existing Long Term Key (LTK) will be used to set-up encryption. If the device is not bonded, a pairing or a security request will be triggered (depending on whether the device is master or slave on the connection) with the bond flag set to false.
ble_gap_get_sec_level() Get the security level currently established on a connection.
ble_gap_unpair() Unpair a previously paired or bonded device. This will also remove security keys and bonding data info currently present in BLE storage.

11.3.2. Events

Table 16 describes the BLE events related to security that may be received by the application and the proper API functions to respond to them.

Table 16 BLE Security API events
Event Argument Description
BLE_EVT_GAP_PAIR_REQ ble_evt_gap_pair_req_t Pairing request received by a connected peer. Member <bond> indicates if the peer has requested a bond (that is, exchange of long term security keys). The application should use ble_gap_pair_reply() to respond to this request.
BLE_EVT_GAP_PAIR_COMPLETED ble_evt_gap_pair_completed_t A previously requested pairing procedure has been completed. Member <status> indicates the completion status of the procedure, while members <bond> and <MITM> indicate if a bond was established with the peer and if MITM (Man In The Middle) protection has been enabled on the connected link.
BLE_EVT_GAP_SECURITY_REQUEST ble_evt_gap_security_request_t Security request received by a connected peripheral peer. Members <bond> and <MITM> indicate if a bond and MITM protection have been requested by the peer. The application may use ble_gap_pair() to initiate pairing with the peer.
BLE_EVT_GAP_PASSKEY_NOTIFY ble_evt_gap_passkey_notify_t A passkey has been generated during a pairing procedure. This event will be received if the application has display capability. Member <passkey> contains the passkey that should be displayed to the user and entered by the peer for the pairing procedure to continue.
BLE_EVT_GAP_PASSKEY_REQUEST ble_evt_gap_passkey_request_t A passkey has been requested during a pairing procedure. This event will be received if the application has keyboard capability. The application should use ble_gap_passkey_reply() to respond to this request using the passkey entered by the user.
BLE_EVT_GAP_NUMERIC_REQUEST ble_evt_gap_numeric_request_t A numeric comparison has been requested during a pairing procedure. This event will be received if the application has keyboard or Yes/No and display capability. The application should use ble_gap_numeric_reply() to respond to this request using the accept or reject input entered by the user.
BLE_EVT_GAP_SEC_LEVEL_CHANGED ble_evt_gap_sec_level_changed_t The security level has been changed on an established link. Member <level> contains the security level that has been reached. This will be received after a pairing or an encryption procedure has been successfully completed.
BLE_EVT_GAP_SET_SEC_LEVEL_FAILED ble_evt_gap_set_sec_level_failed_t Setting the security level on an established link using ble_gap_set_sec_level() has failed. Member <status> indicates the reason for the failure. This will be received after an initiated encryption procedure has been unsuccessful. This may indicate that pairing should be requested again for the connected peer (for example, the peer may have lost the previously exchanged security keys).

11.3.3. Macros

Table 17 contains the configuration macros related to BLE security.

Table 17 BLE Security API macros
Macro Default Description
dg_configBLE_SECURE_CONNECTIONS 1 Set to 1 to use LE Secure Connections pairing if the peer supports the feature or to 0 to always use LE Legacy Pairing.
dg_configBLE_PAIR_INIT_KEY_DIST GAP_KDIST_ENCKEY | GAP_KDIST_IDKEY | GAP_KDIST_SIGNKEY Set the security keys requested to be distributed by the pairing initiator during a pairing feature exchange procedure.
dg_configBLE_PAIR_RESP_KEY_DIST GAP_KDIST_ENCKEY | GAP_KDIST_IDKEY | GAP_KDIST_SIGNKEY Set the security keys requested to be distributed by the pairing responder during a pairing feature exchange procedure.

11.3.4. Message Sequence Charts (MSCs)

11.3.4.1. Central

../_images/image05_02.png

Figure 10 Central Pairing Just Works

../_images/image05_03.png

Figure 11 Central Bonding Just Works

../_images/image05_04.png

Figure 12 Central Bonding Passkey Entry (Central Display)

../_images/image05_05.png

Figure 13 Central Bonding Passkey Entry (Peripheral Display)

../_images/image05_06.png

Figure 14 Central Bonding Numeric Comparison (Secure Connections Only)

11.3.4.2. Peripheral

../_images/image05_07.png

Figure 15 Peripheral Pairing Just Works

../_images/image05_08.png

Figure 16 Peripheral Bonding Just Works

../_images/image05_09.png

Figure 17 Peripheral Bonding Passkey Entry (Peripheral Display)

../_images/image05_10.png

Figure 18 Peripheral Bonding Passkey Entry (Central Display)

../_images/image05_11.png

Figure 19 Peripheral Bonding Numeric Comparison (Secure Connections Only)

11.3.5. BLE Storage

BLE Storage is the BLE Framework module that implements storage functionality for information related to connected and bonded peers, like security keys, CCC descriptors configuration and application-defined values. BLE Storage can manage the list of connected and bonded devices both in RAM and in persistent storage (for example, in the flash). By default, devices are managed in RAM only and persistent storage must be explicitly enabled in the application’s configuration using macro CONFIG_BLE_STORAGE. Device data is then stored using Non-Volatile Memory Storage (NVMS) on the generic partition (see Section 16 for details).

Two kinds of data are stored:

  • Device pairing data (exchanged keys and related information).
  • Application-defined data managed using the BLE storage API (only the values with the ‘persistent’ flag set are stored in flash, for example CCC descriptor values).

Persistent storage can be enabled by the application by adding the following entries in the application’s custom configuration file:

Code 10 Enable BLE persistent storage
// enable BLE persistent storage
#define CONFIG_BLE_STORAGE

// enable Flash and NVMS adapters with VES (required by BLE persistent storage)
#define dg_configFLASH_ADAPTER                  1
#define dg_configNVMS_ADAPTER                   1
#define dg_configNVMS_VES                       1

The maximum number of bonded devices can be set using the defaultBLE_MAX_BONDED macro (defined to 8 by default). If the application attempts to bond more devices than its allowed, an error will be returned. This error should be handled by the application. It can then either unpair one of the currently bonded devices (using ble_gap_unpair() API function) or perform pairing without bonding.

Technical details on the BLE Storage implementation can be found in the following readme file:

<sdk_root_directory>/sdk/interfaces/ble/readme.md

11.3.6. LE Secure Connections

LE Secure Connections pairing is supported and enabled by default by the SDK using the API described in sections 11.3.1 LE Secure Connections pairing will be used if the connected peer supports the feature without the need for the application to specifically request it. If the combination of the devices’ capabilities result in a numeric comparison pairing algorithm (introduced for and used for the LE Secure Connections pairing), the application will be notified of a numeric comparison request during pairing by the reception of a BLE_EVT_GAP_NUMERIC_REQUEST event and should respond using ble_gap_numeric_reply() function.

If the application needs to use only LE Legacy Pairing and disable LE Secure Connections support in the SDK, it should define dg_configBLE_SECURE_CONNECTIONS macro to 0 in the application config file.

11.5. LE Data Packet Length Extension

For Bluetooth Core versions 4.0 and 4.1 the maximum Packet Data Unit (PDU) size was 27 octets. Bluetooth Core version 4.2 introduced an important enhancement, namely LE Data Packet Length Extension, which allows for the PDU size to be anywhere between 27 and 251 octets. This means that, for example, the L2CAP layer can now fill up to 245 octets of higher layer data packets in every L2CAP PDU compared to 21 octets with previous Bluetooth Core versions. This significant increase (more than 10 times) in the number of octets of user data sent per packet allows devices to transfer data up to 2.5 times faster than with previous versions. This will be of great benefit to applications that might require transferring large amounts of data such as Over-the-Air (OTA) firmware updates or downloading large data logs from sensors.

For the default PDU size to be extended on an established connection, the Data Length Update procedure must be performed. According to this control procedure, the LL_LENGTH_REQ and LL_LENGTH_RSP PDUs must be exchanged by the connected devices so that each is notified of its peer device’s capabilities. Each device uses these PDUs to report its maximum receive data channel and maximum transmit data channel PDU payload length and PDU time. After this update procedure, the PDU size for each direction of the connection’s data path is set by both controllers to the minimum of the values exchanged.

The DA1468x supports the LE Data Length Extension feature, so the values for the Receive and Transmit Data Length are set by default to the maximum allowed, which is 251 octets. The DA1468x controller when configured as a Bluetooth low energy central device will initiate a Data Length Update upon a new connection if the peer device’s controller supports this feature. The BLE Manager will use the values defined by dg_configBLE_DATA_LENGTH_RX_MAX and dg_configBLE_DATA_LENGTH_TX_MAX macros for this initial Data Length Update negotiation.

11.5.1. Functions

Table 21 LE Data Length Functions – ble_gap.h
Function Description
ble_gap_data_length_set() Set the maximum Transmit data length and time for an existing connection or the preferred Transmit data length for future connections (that is, the Transmit data length to be used in future data length update negotiations). Connection data length change will be signaled using BLE_EVT_GAP_DATA_LENGTH_CHANGED event.

11.5.2. Macros

Table 22 LE Data Length Definitions
Macro Default Description
dg_configBLE_DATA_LENGTH_RX_MAX 251 Set the maximum Receive Data Channel PDU Payload Length. Unless ble_gap_data_length_set() is used by the application, this will define the Receive data length present in the LE Data Length Update negotiations done by the device.
dg_configBLE_DATA_LENGTH_TX_MAX 251 Set the maximum Transmit Data Channel PDU Payload Length. Unless ble_gap_data_length_set() is used by the application, this will define the Transmit data length present in the LE Data Length Update negotiations done by the device.

11.5.3. Events

Table 23 LE Data Length Events – fetched using ble_get_event() - ble_gap.h
Event Argument Description
BLE_EVT_GAP_DATA_LENGTH_CHANGED ble_evt_gap_data_length_changed_t Data Length changed for specified connection. Members <rx_length>, <rx_time>, <tx_length> and <tx_time> specify the values obtained after an LE Data Length Update negotiation (each direction’s data length is typically set to the minimum of the values reported by the connected devices).
BLE_EVT_GAP_DATA_LENGTH_SET_FAILED ble_evt_gap_data_length_set_failed_t Data Length Set operation failed. Member <status> indicates the reason the set operation failed.

11.6. NVPARAM fields

Table 24 shows the Non-Volatile memory parameters which can be found in <sdk_root_directory>/sdk/adapters/include/platform_nvparam.h

Table 24 NVPARAM fields
Tag Offset Length
TAG_BLE_PLATFORM_BD_ADDRESS 0x0000 7
TAG_BLE_PLATFORM_LPCLK_DRIFT 0x0007 3
TAG_BLE_PLATFORM_EXT_WAKEUP_TIME 0x000A 3
TAG_BLE_PLATFORM_OSC_WAKEUP_TIME 0x000D 3
TAG_BLE_PLATFORM_RM_WAKEUP_TIME 0x0010 3
TAG_BLE_PLATFORM_SLEEP_ENABLE 0x0013 2
TAG_BLE_PLATFORM_EXT_WAKEUP_ENABLE 0x0015 2
TAG_BLE_PLATFORM_BLE_CA_TIMER_DUR 0x0017 3
TAG_BLE_PLATFORM_BLE_CRA_TIMER_DUR 0x001A 2
TAG_BLE_PLATFORM_BLE_CA_MIN_RSSI 0x001C 2
TAG_BLE_PLATFORM_BLE_CA_NB_PKT 0x001E 3
TAG_BLE_PLATFORM_BLE_CA_NB_BAD_PKT 0x0021 3
TAG_BLE_PLATFORM_IRK 0x0024 17

11.7. BLE Interrupt Generation

The BLE Core generates interrupts that are used to synchronize with the BLE Software. These interrupts are:

  • ble_cscnt_irq: 625μs (slot) base time reference clock interrupt. When sleep mode is used, this interrupt will also be used to program the next advertising, scanning or connection event if it fires before the finetgtim interrupt.
  • ble_rx_irq: Reception interrupt at the end of either each CS-RXTHR number of received packets or each received packet. CS-RXTHR can be configured at compile time using position 44 of rom_cfg_table_var[] (sdk\interfaces\ble\src\stack\plf\black_orca\src\arch\main\ble\jump_table.c).
  • ble_slp_irq: End of sleep mode events.
  • ble_event_irq: End of Advertising / Scanning / Connection event. Used to cleanup/re-initialize state and defer TX/RX handling operations.
  • ble_error_irq: Error interrupt generated on internal error.
  • ble_finetgtim_irq: Fine target interrupt. Used to program the next advertising, scanning or connection event. When sleep mode is not used, programming of events will be done by this interrupt’s service routine and not by the cscnt interrupt service routine.
  • ble_grossgtim_irq: Gross target timer interrupt. Used by BLE stack SW timers, e.g. supervision timeout, link layer timeout, etc.

Depending on the context, these interrupts are generated or not. The grayed ble_cscnt_irq interrupt pulses in the following figures can be masked or unmasked. The figures that follow assume the following:

  • Either extended or deep sleep mode is used.
  • CS-RXTHR is 1.

When a sleep mode is used, the event will be programmed in the cscnt_isr only if it fires before the finetgtim_irq after waking up. The original figures assumed a sleep mode was used, so the points where a finetgtim interrupt will fire instead of a cscnt interrupt are noted with red color in the same row.

Figure 21 shows an example of interrupt generation for an advertiser device during an advertising event. The first advertising event shows advertising packets only. The second advertising event shows a scanner that tried to exchange data with the advertiser device. The definitions of values such as T_advEvent and T_IFS can be found in Bluetooth Specification.

../_images/image05_13.png

Figure 21 Advertiser Device Interrupts Generation

Figure 22 shows an example of interrupts generation for a scanner device during a scanning event. The first scanning window shows a passive scan event onto channel 39. The second scanning window shows an active scan event with no scan response onto channel 37.

../_images/image05_14.png

Figure 22 Scanner Device Interrupts Generation

Figure 23 shows an example of interrupt generation for a master device during a Link Layer connection event without Deep Sleep in between anchor points. The first and third connection event show a two packet exchange, while the second connection event shows a four packets exchange.

Figure 24 shows an example of interrupt generation for a master device during a Link Layer connection event with Deep Sleep in between anchor points.

Figure 25 shows an example of interrupt generation for a slave device during a Link Layer connection event without Deep Sleep in between anchor points.

Figure 26 shows an example of interrupts generation for a slave device during a Link Layer connection event with Deep Sleep in between anchor points.

The CSCNT/FINE interrupt which each coming event is programmed in should be serviced with a maximum latency of 300us. If the CSCNT/FINE Interrupt Servicing Routine (ISR) that will program the event is not run 300us+ after the interrupt is asserted, this may result in losing the next connection event (i.e. no data transmission or reception in this connection event).

11.8. Considerations on BLE Task Priorities

The BLE Software in the SDK consists of three modules as shown previously in Figure 6 :

  1. BLE manager: Provides the interface to the Bluetooth low energy functionality of the chip. The application task uses the BLE API to interface with the BLE manager. The BLE manager is a task that stands between the application and the BLE adapter. It uses the BLE adapter to interface with the BLE stack.
  2. BLE adapter: The system task that provides the interface to the BLE stack, hence the BLE IP module. It runs the BLE stack internal scheduler, handles the BLE interrupts, receives the commands or the replies to events from the BLE manager, and passes BLE events to the BLE manager. BLE core functionality is implemented by the BLE adapter task.

3. 3. BLE stack: The software stack that interfaces with the BLE IP and implements the Link Layer and the host stack, specifically the Logical Link Control and Adaptation Protocol (L2CAP), the Security Manager Protocol (SMP), the Attribute Protocol (ATT), the Generic Attribute Profile (GATT) and the Generic Access Profile (GAP). The BLE stack software is stored in the system’s ROM and its API header files can be found in <sdk_root_directory>/sdk/interfaces/ble/src/stack. The BLE stack default configuration can be modified by editing ble_stack_config.h located in <sdk_root_directory>/sdk/interfaces/ble/src/stack/config. However, for an application specific change it is better to add the new configuration to the applications config/custom_config_qspi.h file which will override the stack defaults.

The BLE stack software is run under the BLE adapter’s task context, which instantiates and initializes the stack.

The two BLE system tasks have by default a higher priority than application tasks in the SDK.

Application developers should always make sure BLE adapter and BLE manager tasks always have a higher priority than application tasks.

The BLE adapter instantiates the BLE stack scheduler, which dispatches all the messages between the BLE stack’s different layers and calls the appropriate handlers. For example, when an application uses API ble_gatts_send_event() to send a GATT notification, this will result in a propagation of messages between the BLE manager, the BLE adapter and several BLE stack’s internal layers until it reaches a transmission buffer and, eventually, the air. BLE stack’s reception handlers are also run in the context of the BLE adapter’s task, so it is crucial that the BLE adapter is always run after a BLE interrupt to handle received data, check if the data programmed for transmission were transmitted and/or acknowledged by the peer device, etc.

11.9. BLE tasks timing requirements

When the application is not making any BLE API calls, the BLE adapter will typically run for a short period of time following every BLE interrupt. For example, in the scenario where a GATT server application sends a notification at every connection event, the BLE adapter will only need to run for about 18us following the ble_cscnt/finetgtim_irq interrupt that programs the connection event and about 68us following the ble_event_irq (rough average times when 96MHz clock is used and no control packet is received or sent during that connection event but only the notification data). In this scenario, the BLE adapter only needs to run between two consecutive events when the application uses ble_gatts_send_event() to send a new notification. In this case it needs roughly 190us for the data to be put in a TX buffer and to be programmed for the next connection event. Figure 27 shows two connection events and the period between them.

../_images/image05_19.png

Figure 27 Two connection events

In some scenarios the BLE manager and the BLE adapter will communicate with messages without notifying the application. As an example, upon connection with a peer that uses a resolvable private address the BLE manager will attempt to resolve using known devices IRKs. In this case the BLE manager and BLE adapter will have more running slots. These periods will also be placed right after the ble_event_irq.

There are also other cases when the BLE framework will require a reply from the application when, for example, a pair request or a write request is received from the peer. Again, in these cases the BLE adapter and BLE manager will have to run more times in a period between two connection events.

11.10. Attribute operations

As the Attribute protocol is strict (section 8.8.3) when an attribute request such as a read or a write request is received, the BLE stack’s GATT layer will switch to a busy state for as long as the request is not completed/handled. In the case of a write request or a read request of an attribute whose value is to be provided by the application, then the application will have to confirm these operations using ble_gatts_read_cfm() or ble_gatts_write_cfm() respectively (after receiving BLE_EVT_GATTS_READ_REQ or BLE_EVT_GATTS_WRITE_REQ). In this case, other GATT operations, such as notification sending, will be queued until this request is confirmed. See an example of this in Figure 28.

../_images/image05_20.png

Figure 28 Attribute operations example

This plot shows the period after a connection event during which a write request was received from the peer. In this case this request is confirmed by a task different than the one making the ble_gatts_send_event() call. In this case the BLE adapter runs for an additional slot of about 180us. BLE manager also needs to be run in between since it implements the BLE framework functionality on top of the BLE adapter/stack. BLE manager will need in general smaller time slots to run, unless it reads/writes data from/to the flash.

11.11. Bluetooth low energy Application Examples

11.11.1. Advertising Application

The simplest Bluetooth low energy project in the SmartSnippetsTM DA1468x SDK is ble_adv_demo which is found in the folder <sdk_root_directory>/projects/dk_apps/demos/ble_adv. The application starts the device as a peripheral, sets the device name and advertising data and starts advertising. Code 11 is an extract from main.c.

Code 11 Set BLE device
// Start BLE module as a peripheral device
ble_peripheral_start();

// Set device name
ble_gap_device_name_set("Dialog ADV Demo", ATT_PERM_READ);

// Set advertising data
ble_gap_adv_data_set(sizeof(adv_data), adv_data, 0, NULL);

// Start advertising
ble_gap_adv_start(GAP_CONN_MODE_UNDIRECTED);

No BLE service is added, and the ones exposed are just GAP and GATT services. The infinite loop that implements the lifetime behavior of the application uses just ble_get_event(true) to block indefinitely on the BLE manager’s event queue. As soon as an event is posted there, the task unblocks and handles it using a switch case. Code 12 is located in main.c.

Code 12 Example of event handle
for (;;) {
             ble_evt_hdr_t *hdr;

             /* notify watchdog on each loop */
             sys_watchdog_notify(wdog_id);

             /* suspend watchdog while blocking on ble_get_event() */
             sys_watchdog_suspend(wdog_id);

             /*
              * Wait for a BLE event - this task will block
              * indefinitely until something is received.
              */
             hdr = ble_get_event(true);

             /* resume watchdog */
             sys_watchdog_notify_and_resume(wdog_id);

             if (!hdr) {
                     continue;
             }

             switch (hdr->evt_code) {
             case BLE_EVT_GAP_CONNECTED:
                     handle_evt_gap_connected((ble_evt_gap_connected_t *) hdr);
                     break;
             case BLE_EVT_GAP_DISCONNECTED:
                     handle_evt_gap_disconnected((ble_evt_gap_disconnected_t *) hdr);
                     break;
             case BLE_EVT_GAP_PAIR_REQ:
             {
                     ble_evt_gap_pair_req_t *evt = (ble_evt_gap_pair_req_t *) hdr;
                     ble_gap_pair_reply(evt->conn_idx, true, evt->bond);
                     break;
             }
             default:
                     ble_handle_event_default(hdr);
                     break;
             }

             // Free event buffer
             OS_FREE(hdr);
     }

Since the BLE service framework is not used, the only events handled by the application are the three events handled by the switch case: connection, disconnection and pair request. This makes sense for this application as its only purpose is to start a connectable advertising, restart it in case of a disconnection and respond to pair requests from devices that require pairing/bonding upon connection.

Running this project will result in an advertising Bluetooth low energy peripheral device exposing GAP and GATT services. GAP service attributes can be read using any standard Bluetooth low energy central device. An example is described in Section 4.1.5 of the Software Developers Guide [Ref_03].

The ble_peripheral project is a good starting point for developing Bluetooth low energy peripheral applications. It is found in folder <sdk_root_directory>/projects/dk_apps/demos/ble_peripheral. Unlike other example projects, it does not implement a specific profile, but instead exposes several BLE services via a GATT server.

The application’s initialization is similar to other projects that implement Bluetooth low energy peripheral applications. It uses the BLE service framework to instantiate several Bluetooth low energy services:

  • Battery Service (multiple instance)
  • Current Time Service
  • Device Information Service
  • Scan Parameter Service
  • Dialog Debug Service
  • Custom User Service

In addition to Bluetooth SIG-adopted services, ble_peripheral project instantiates two more services, Dialog Debug Service and a custom user service.

The Dialog Debug Service can be used to interact with the services that the application exposes using a Control Point characteristic to write commands and receive notifications from. A detailed description of the ways to interact with the Dialog Debug Service is included in the readme.md file inside the project’s folder.

The custom user service does not define any specific functionality other than using 128-bit UUIDs for services, characteristics and descriptors. This custom service, referred to as myservice in the project source code, is an example of implementing a custom service using BLE API calls to create its attribute database. No specific functionality is defined when one of these attributes is read or written. More details on how to create and use custom services will be given in section 7.14.

After the attribute database is created, the device will end-up advertising and it will wait for a connection event.

The ble_peripheral project uses the BLE service framework to handle service events, the application also defines handlers for connection, advertising completion and pair request events. The ble_peripheral project stands in terms of its completeness somewhere between the ble_adv_demo and a full profile like the pxp_reporter.

The services the project will expose can be configured using the file config/ble_peripheral_config.h.

11.11.2. Central Application

The ble_central project is found in folder <sdk_root_directory>/projects/dk_apps/ble_central. It is the recommended starting point for creating a Bluetooth low energy central application. The application initialization is similar to the previously described projects. The difference is that the device is configured as a Bluetooth low energy central device and no attribute database is created as the device implements a GATT client. Code 13 is extracted from ble_central_task.c.

Code 13 Configure device as a BLE central
ble_central_start();
ble_register_app();

After configuring the Bluetooth low energy parameters, the device attempts to connect to another device. To work with this demo the other device must expose the specific Bluetooth Device (BD) address defined in the addr structure:

Code 14 Connection to another device
ble_gap_connect(&addr, &cp);

The project is configured to connect by default to another DA1468x device, preferably one that exposes a couple of services such as ble_peripheral. A good experiment would be to run the ble_central project after having programmed another DA1468x board with ble_peripheral. Of course, addr must be modified to force the ble_central device to connect to a device with a different BD address. The default BD address of a project can be changed via the project’s config/custom_config_qspi.h by adding the following override.

Code 15 Default BD address override
#define defaultBLE_STATIC_ADDRESS      {0x02,0x00,0x80,0xCA,0xEA,0x80}

Upon connection, the handle_evt_gap_connected() handler uses BLE API call ble_gattc_browse() (or ble_gattc_discover_svc(), ble_gattc_discover_char() and ble_gattc_discover_desc(), if CFG_USE_BROWSE_API macro is set to 0) to discover all services, characteristics and descriptors of the peer device. The project uses the serial interface to print information of the discovered attribute database.

The options of the project can be configured using the file config/ble_central_config.h.

11.11.4. External Host Application

The Bluetooth low energy external host project is found in folder <sdk_root_directory>/projects/dk_apps/demos/ble_external_host. It is the only project that does not use the BLE framework and the Dialog BLE API. Instead, its application task is a custom adapter created to send and receive HCI and BLE stack proprietary messages over the serial interface, allowing the development of the host on a separate processor.

After building the project, the user should make sure that the RTS/CTS pins are connected on the Development Kit. Then, a host can send HCI messages over the serial interface and receive the controller’s responses.

11.12. BLE profile projects

In addition to the projects described in the previous sections, there are several application projects that implement Bluetooth low energy profiles. These projects are more complex and provide a full implementation of Bluetooth low energy applications. As such they provide a good reference on how to combine the Bluetooth low energy functionality with several OS mechanisms, GPIO handling and interfacing with external sensors.

The profiles implemented are the following:

  • HID over GATT Profile (HOGP) – Device role (hogp_device) located under <sdk_root_directory>/projects/dk_apps/ble_profiles
  • HID over GATT Profile (HOGP) – Host role (hogp_host) located under <sdk_root_directory>/projects/dk_apps/ble_profiles
  • Heart Rate Profile – Sensor role (hrp_sensor) located under <sdk_root_directory>/projects/dk_apps/ble_profiles
  • Proximity Profile – Reporter role (pxp_reporter) located under <sdk_root_directory>/projects/dk_apps/demos
  • Weight Scale Profile – Weight Scale role (wsp_weightscale) located under <sdk_root_directory>/projects/dk_apps/ble_profiles
  • Apple Notification Center Service (ANCS) - Notification Consumer (NC) role (ancs) located under <sdk_root_directory>/projects/dk_apps/ble_profiles
  • Blood Pressure Profile (BLP) – Blood Pressure Sensor role (blp_sensor) located under <sdk_root_directory>/projects/dk_apps/ble_profiles
  • Bond Management Service (BMS) - located under <sdk_root_directory>/projects/dk_apps/ble_profiles
  • Cycling Speed And Cadence collector (CSCP) - located under <sdk_root_directory>/projects/dk_apps/ble_profiles
  • Health Thermometer Profile – Thermometer role (htp_thermometer) located under <sdk_root_directory>/projects/dk_apps/ble_profiles

11.13. Using adopted Bluetooth low energy services

Table 25 summarizes the API header files of the Bluetooth low energy services implemented by the SmartSnippets™ DA1468x SDK. These files can be found under <sdk_root_directory>/sdk/interfaces/ble_services/include. The developer can use these APIs to add these services to another project.

Table 25 BLE service API header files
File name Description
ble_service.h

BLE service framework API:

  • Add service to framework
  • Handle event using BLE service framework
  • Elevate permission
  • Get number of attributes in a service
  • Add included services
bas.h Battery Service – BAS
bcs.h Body Composition Service – BCS
bms.h Bond Management Service – BMS
cts.h Current Time Service – CTS
dis.h Device Information Service – DIS
dlg_debug.h Dialog Debug Service
dlg_suota.h Dialog SUOTA Service
hids.h Human Interface Device Service – HID
hrs.h Heart Rate Service – HRS
ias.h Immediate Alert Service – IAS
lls.h Link Loss Service – LLS
scps.h Scan Parameters Service – ScPS
sps.h Serial Port Service – SPS
tps.h Tx Power Service – TPS
uds.h User Data Service – UDS
wss.h Weight Scale Service – WSS

11.14. Adding a custom service

The following code segments provide an overview of the initialization required to create a new custom service called XXX. It requires the files xxx.c and xxx.h to be created. A good example to base these on is the dlj_mls service in the Multi-Link demo. This provides a single write only characteristic in the service.

Each service needs a structure containing both the generic ble_service_t structure and any callbacks and characteristic handles required by the service. In the example below for service XXX there is one callback and one characteristic defined.

Code 16 Structure definition for XXX service
typedef struct {
     ble_service_t svc;          // Core BLE service structure
     xxx_cb_t cb;                // Callback provided by app to xxx
                                 // service to process an event
     uint16_t xxx_char1_val_h;   // Declare handle for each characteristic
                                 // that can be read or written
} xxx_service_t;

The requirements of the initialization function xxx_init() are illustrated below. They key information here is the comments which are explaining what each line is doing.

Code 17 Initialization function for XXX service
xxx_service_t* xxx_init(callback1){
// Allocate and initialise xxx_service_t structure
// Define any callback functions required by the service, write only in this case
xxx->svc.write_req = <this services write request handler>
// Create primary service UUID with either 16 or 128 bit value
uuid=ble_uuid_from_string() or uuid=ble_uuid_create16()
// add PRIMARY service with X attributes
num_attrs=X
ble_gatts_add_service(&uuid, GATT_SERVICE_PRIMARY, num_attrs)
// Create characteristic 1 for this service and allocate handle for it in GATT table
ble_gatts_add_characteristic(&uuid, GATT property, ATT permissions, size,0, NULL, &xxx->xxx_char1_h)
// Set start_h and pass in null terminated variable length list of all characteristic handles in the service
ble_gatts_register_service(&xxx->svc.start_h, &xxx->xxx_char1_h,0);
// Calculate end handle for service based on number of attributes in service
xxx->svc.end_h= xxx->svc.start_h + num_attrs;
// add the passed in callback function to service structure
xxx->xxx_cb1=callback1;
// add newly created service to ble framework
ble_service_add(&xxx->svc);
// and return handle for the service to the application
return &xxx->svc
}

11.15. Extending Bluetooth low energy functionality

The Dialog BLE API can be used to create any Bluetooth low energy application. These API header files are in folder <sdk_root_directory>/sdk/interfaces/ble/include. They come with additional Doxygen documentation and are summarized in Table 26.

Table 26 Dialog BLE API header files
File name Description
ble_att.h Attribute Protocol API: Mostly definitions.
ble_attribdb Helper to manage complex attributes database.
ble_bufops Helpers to put and get data from BLE buffers.
ble_common.h Common API: Functions used for operations not specific to a certain BLE host software component
ble_gap.h

GAP API:

  • Device parameters configuration: device role, MTU size, device name exposed in the GAP service attribute, etc.
  • Air operations: Advertise, scan, connect, respond to connection requests, initiate or respond to connection parameters update, etc.
  • Security operations: Initiate and respond to a pairing or bonding procedure, set the security level, unpair, etc.
ble_gatt Common definitions for GATT API
ble_gattc.h

GATT client API:

  • Discover services, characteristics, etc. of a peer device
  • Read or write a peer device’s attributes
  • Initiate MTU exchanges
  • Confirm the reception of indications
ble_gatts.h

GATT server API:

  • Set up the attribute database
  • Set attribute values
  • Notify/indicate characteristic values
  • Initiate MTU exchanges
  • Respond to write and read requests
ble_l2cap BLE L2CAP API.
ble_storage.h BLE persistent storage API.
ble_uuid.h BLE UUID declarations and helper functions.