Bluenrg-1, Bluenrg-2 Ble Stack V2.X Programming Guidelines
Bluenrg-1, Bluenrg-2 Ble Stack V2.X Programming Guidelines
Bluenrg-1, Bluenrg-2 Ble Stack V2.X Programming Guidelines
Programming manual
Introduction
The main purpose of this document is to provide a developer with some reference programming guidelines about how to
develop a Bluetooth low energy (BLE) application using the BlueNRG-1, BlueNRG-2 BLE stack v2.x family APIs and related
event callbacks.
The document describes the BlueNRG-1, BlueNRG-2 Bluetooth low energy stack library framework, API interfaces and event
callbacks allowing the access to the Bluetooth low energy functions provided by the BlueNRG-1, BlueNRG-2 system-on-chip.
This programming manual also provides some fundamental concepts about the Bluetooth low energy (BLE) technology in order
to associate the BlueNRG-1, BlueNRG-2 BLE stack APIs, parameters, and related event callbacks with the BLE protocol stack
features. The user must have a basic knowledge about the BLE technology and its main features.
For more information about the BlueNRG-1, BlueNRG-2 devices and the Bluetooth low energy specifications, refer to
Section 5 References at the end of this document.
The BlueNRG-1 and BlueNRG-2 are very low power Bluetooth low energy (BLE) single-mode system-on-chips, compliant with
Bluetooth low energy specifications and supporting master or slave role; the BlueNRG-2 also supports the extended packet
length feature.
The manual is structured as follows:
• Fundamentals of the Bluetooth low energy (BLE) technology
• BlueNRG-1, BlueNRG-2 BLE stack v2.x library APIs and the event callback overview
• How to design an application using the BlueNRG-1, BlueNRG-2 stack v2.x library APIs and event callbacks
Note: The document content is valid for both BlueNRG-1 and BlueNRG-2 devices. Any reference to the BlueNRG-1
device is also valid for the BlueNRG-2 device. Any specific difference is highlighted whenever it is needed.
The Bluetooth low energy (BLE) wireless technology has been developed by the Bluetooth special interest group
(SIG) in order to achieve a very low power standard operating with a coin cell battery for several years.
Classic Bluetooth technology was developed as a wireless standard allowing cables to be replaced connecting
portable and/or fixed electronic devices, but it cannot achieve an extreme level of battery life because of its fast
hopping, connection-oriented behavior, and relatively complex connection procedures.
The Bluetooth low energy devices consume a fraction of the power of standard Bluetooth products only and
enable devices with coin cell batteries to be wireless connected to standard Bluetooth enabled devices.
Figure 1. Bluetooth low energy technology enabled coin cell battery devices
Bluetooth low energy technology is used on a broad range of sensor applications transmitting small amounts of
data.
• Automotive
• Sport and fitness
• Healthcare
• Entertainment
• Home automation
• Security and proximity
• Low-power
In particular, Bluetooth low energy technology has been created for the purpose of transmitting very small packets
of data at a time, while consuming significantly less power than basic rate/enhanced data rate/high speed
(BR/EDR/HS) devices.
The Bluetooth low energy technology is designed to address two alternative implementations:
• Smart device
• Smart ready device
Smart devices support the BLE standard only. It is used for applications in which low power consumption and coin
cell batteries are the key point (as sensors).
Smart ready devices support both BR/EDR/HS and BLE standards (typically a mobile or a laptop device).
The Bluetooth low energy stack consists of two components:
• Controller
• Host
The Controller includes the physical layer and the link layer.
Host includes the logical link control and adaptation protocol (L2CAP), the security manager (SM), the attribute
protocol (ATT), generic attribute profile (GATT) and the generic access profile (GAP). The interface between the
two components is called host controller interface (HCI).
In addition, Bluetooth specification v4.1, v4.2 and 5.0 have been released with new supported features.
For more information about these new features, refer to the related specification document.
GAMSEC201411251124
BLE is an adaptive frequency hopping (AFH) technology that can only use a subset of all the available
frequencies in order to avoid all frequencies used by other no-adaptive technologies. This allows moving from a
bad channel to a known good channel by using a specific frequency hopping algorithm, which determines next
good channel to be used.
Scanning
Connection
GAMSEC201411251131
Header
Length
Access Address Data CRC
The Bluetooth low energy BLE specification v4.2 defines the LE data packet length extension feature which
extends the link layer PDU of LE from 27 to 251 bytes of data payload.
8 32 8 8 0 to (8 * 255) 24 Bits
Preamble
Header
Length
The length field has a range of 0 to 255 bytes. When encryption is used, the message integrity code (MIC) at the
end of the packet is 4 bytes, so this leads to 251 bytes as actual maximum available payload size.
• Preamble: RF synchronization sequence
• Access address: 32 bits, advertising or data access addresses (it is used to identify the communication
packets on physical layer channel)
• Header: its content depends on the packet type (advertising or data packet)
• Advertiser packet header:
Connectable Used by an advertiser when it wants another device to connect to it. Device can
ADV_IND undirected be scanned by a scanning device, or go into a connection as a slave device on
advertising connection request reception.
Connectable Used by an advertiser when it wants a particular device to connect to it. The
ADV_DIRECT_IND directed ADV_DIRECT_IND packet contains only advertiser’s address and initiator
advertising address.
Used by an advertiser when it wants to provide some information to all the
Non-connectable devices, but it does not want other devices to ask it for more information or to
ADV_NONCONN_IND undirected connect to it.
advertising Device simply sends advertising packets on related channels, but it does not
want to be connectable or scanned by any other device.
Scannable Used by an advertiser which wants to allow a scanner to require more
ADV_SCAN_IND undirected information from it. The device cannot connect, but it is discoverable for
advertising advertising data and scan response data.
Used by a device in scanning state to request addition information to the
SCAN_REQ Scan request
advertiser.
SCAN_RSP Scan response Used by an advertiser device to provide additional information to a scan device.
Connection
CONNECT_REQ Sent by an initiating device to a device in connectable/discoverable mode.
request
Allowable response
Advertising event type
SCAN_REQ CONNECT_REQ
Link layer identifier Next sequence number Sequence number More data Reserved
The next sequence number (NESN) bit is used for performing packet acknowledgments. It informs the receiver
device about next sequence number that the transmitting device expects it to send. Packet is retransmitted until
the NESN is different from the sequence number (SN) value in the sent packet.
More data bits are used to signal to a device that the transmitting device has more data ready to be sent during
the current connection event.
For a detailed description of advertising and data header contents and types refer to the Bluetooth specification
[Vol 2], in Section 5 References.
• Length: number of bytes on data field
• Data or payload: it is the actual transmitted data (advertising data, scan response data, connection
establishment data, or application data sent during the connection)
• CRC (24 bits): it is used to protect data against bit errors. It is calculated over the header, length and data
fields
Preamble Advertising Advertising Payload Advertising Flags-LE TX Power Service Data 16 bit service CRC
Access Header Length Address General Level = 4 dBm “Temperature” UUIDs =
o
Address Discoverable = 20..5 C “Temperature
Flag service”
GAMSEC201411251139
– Process scan requests from all the devices but only connection requests in the white list
A white list is a list of stored device addresses used by the device controller to filter devices. The white list content
cannot be modified while it is being used. If the device is in advertising state and uses a white list to filter the
devices (scan requests or connection requests), it has to disable advertising mode to change its white list.
The transmit window starts after the end of the connection request packet plus the transmit window offset plus a
mandatory delay of 1.25 ms. When the transmit window starts, the slave device enters in receiver mode and waits
for a packet from the master device. If no packet is received within this time, the slave leaves receiver mode, and
it tries one connection interval again later. When a connection is established, a master has to transmit a packet to
the slave on every connection event to allow slave to send packets to the master. Optionally, a slave device can
skip a given number of connection events (slave latency).
A connection event is the time between the start of the last connection event and the beginning of the next
connection event.
A BLE slave device can only be connected to one BLE master device, but a BLE master device can be connected
to several BLE slave devices. On the Bluetooth SIG, there is no limit on the number of slaves a master can
connect to (this is limited by the specific used BLE technology or stack).
• “Temperature UUID” is defined by “Temperature characteristic” specification and it is a signed 16-bit integer.
A collection of attributes is called a database that is always contained in an attribute server.
Attribute protocol defines a set of method protocol to discover, read and write attributes on a peer device. It
implements the peer-to-peer client-server protocol between an attribute server and an attribute client as follows:
• Server role
– Contains all attributes (attribute database)
– Receives requests, executes, responds commands
– Indicates, notifies an attribute value when data change
• Client role
– Talks with server
– Sends requests, waits for response (it can access (read), update (write) the data)
– Confirms indications
Attributes exposed by a server can be discovered, read, and written by the client, and they can be indicated and
notified by the server as described in Table 9. Attribute protocol messages:
No output Display
LE legacy pairing
LE legacy pairing algorithm uses and generates 2 keys:
• Temporary key (TK): a 128-bit temporary key which is used to generate short-term key (STK)
• Short-term key (STK): a 128-bit temporary key used to encrypt a connection following pairing
Pairing procedure is a three-phase process.
Phase 1: pairing feature exchange
The two connected devices communicate their input/output capabilities by using the pairing request message.
This message also contains a bit stating if out-of-band data are available and the authentication requirements.
The information exchanged in phase 1 is used to select which pairing method is used for the STK generation in
phase 2.
Phase 2: short-term key (STK) generation
The pairing devices first define a temporary key (TK), by using one of the following key generation methods
1. The out-of-band (OOB) method, which uses out of band communication (e.g. NFC) for TK agreement. It
provides authentication (MITM protection). This method is selected only if the out-of-band bit is set on both
devices, otherwise the IO capabilities of the devices must be used to determine which other method could
be used (Passkey Entry or Just Works)
2. Passkey entry method: user passes six numeric digits as the TK between the devices. It provides
authentication (MITM protection)
3. Just works: this method does not provide authentication and protection against man-in-the-middle (MITM)
attacks
The selection between Passkey and Just Works method is done based on the IO capability as defined on the
following table.
Display only Display yes/no Keyboard only No input, no output Keyboard display
Display Only Just Works Just Works Passkey Entry Just Works Passkey Entry
Display Yes/No Just Works Just Works Passkey Entry Just Works Passkey Entry
Keyboard Only Passkey Entry Passkey Entry Passkey Entry Just Works Passkey Entry
No Input No Output Just Works Just Works Just Works Just Works Just Works
Keyboard Display Passkey Entry Passkey Entry Passkey Entry Just Works Passkey Entry
Phase 3: transport specific key distribution methods used to calculate the temporary key (TK)
Once the phase 2 is completed, up to three 128-bit keys can be distributed by messages encrypted with the STK
key:
1. Long-term key (LTK): it is used to generate the 128-bit key used for Link Layer encryption and authentication
2. Connection signature resolving key (CSRK): a 128-bit key used for the data signing and verification
performed at the ATT layer
3. Identity resolving key (IRK): a 128-bit key used to generate and resolve random addresses
LE secure connections
LE secure connection pairing methods use and generate one key:
• Long-term key (LTK): a 128-bit key used to encrypt the connection following pairing and subsequent
connections
Pairing procedure is a three-phase process:
Phase 1: pairing feature exchange
The two connected devices communicate their input/output capabilities by using the pairing request message.
This message also contains a bit stating if out-of-band data are available and the authentication requirements.
The information exchanged in phase 1 is used to select which pairing method is used on phase 2.
Phase 2: long-term key (LTK) generation
Pairing procedure is started by the initiating device which sends its public key to the receiving device. The
receiving device replies with its public key. The public key exchange phase is done for all the pairing methods
(except the OOB one). Each device generates its own elliptic curve Diffie-Hellman (ECDH) public-private key pair.
Each key pair contains a private (secret) key, and a public key. The key pair should be generated only once on
each device and may be computed before a pairing is performed.
The following pairing key generation methods are supported:
1. The out-of-band (OOB) method which uses out of band communication to set up the public key. This method
is selected if the out-of-band bit in the pairing request/response is set at least by one device, otherwise the
IO capabilities of the devices must be used to determine which other method could be used (Passkey entry,
Just Works or numeric comparison)
2. Just Works: this method is not authenticated, and it does not provide any protection against man-in-the-
middle (MITM) attacks
3. Passkey entry method: this method is authenticated. User passes six numeric digits. This six-digit value is
the base of the device authentication
4. Numeric comparison: this method is authenticated. Both devices have IO capabilities set to either display
Yes/No or keyboard display. The two devices compute a six-digit confirmation values that are displayed to
the user on both devices: user is requested to confirm if there is a match by entering yes or not. If yes is
selected on both devices, pairing is performed with success. This method allows confirmation to user that his
device is connected with the proper one, in a context where there are several devices, which could not have
different names
The selection among the possible methods is based on the following table.
Initiator/ No input no
Display only Display yes/no Keyboard only Keyboard display
responder output
Display only Just Works Just Works Passkey Entry Just Works Passkey Entry
Just Works
Passkey Entry (LE legacy)
(LE legacy)
Display yes/no Just Works Passkey Entry Just Works Numeric comparison (LE secure
Numeric comparison (LE secure connections)
connections)
Keyboard only Passkey Entry Passkey Entry Passkey Entry Just Works Passkey Entry
No input no output Just Works Just Works Just Works Just Works Just Works
Initiator/ No input no
Display only Display yes/no Keyboard only Keyboard display
responder output
Passkey Entry
Passkey Entry (LE legacy)
(LE legacy)
Keyboard display Passkey Entry Passkey Entry Just Works Numeric comparison (LE secure
Numeric comparison (LE secure connections)
connections)
Note: If the possible key generation method does not provide a key that matches the security properties (authenticated
- MITM protection or unauthenticated - no MITM protection), then the device sends the pairing failed command
with the error code “Authentication Requirements”.
Phase 3: transport specific key distribution
The following keys are exchanged between master and slave:
• Connection signature resolving key (CSRK) for authentication of unencrypted data
• Identity resolving key (IRK) for device identity and privacy
When the established encryption keys are stored in order to be used for future authentication, the devices are
bonded.
Data signing
It is also possible to transmit authenticated data over an unencrypted link layer connection by using the CSRK
key: a 12-byte signature is placed after the data payload at the ATT layer. The signature algorithm also uses a
counter which protects against replay attacks (an external device which can simply capture some packets and
send them later as they are, without any understanding of packet content: the receiver device simply checks the
packet counter and discards it since its frame counter is less than the latest received good packet).
1.8 Privacy
A device that always advertises with the same address (public or static random), can be tracked by scanners.
This can be avoided by enabling the privacy feature on the advertising device. On a privacy enabled device,
private addresses are used. There are two kinds of private addresses:
• Non-resolvable private address
• Resolvable private address
Non-resolvable private addresses are completely random (except for the two most significant bits) and cannot be
resolved. Hence, a device using a non-resolvable private address cannot be recognized by those devices which
have not been previously paired. The resolvable private address has a 24-bit random part and a hash part. The
hash is derived from the random number and from an IRK (identity resolving key). Hence, only a device that
knows this IRK can resolve the address and identify the device. The IRK is distributed during the pairing process.
Both types of addresses are frequently changed, enhancing the device identity confidentiality. The privacy feature
is not used during the GAP discovery modes and procedures but during GAP connection modes and procedures
only.
On Bluetooth low energy stacks up to v4.1, the private addresses are resolved and generated by the host. In
Bluetooth v4.2, the privacy feature has been updated from version 1.1 to version 1.2. On Bluetooth low energy
stack v4.2, private addresses can be resolved and generated by the controller, using the device identity
information provided by the host.
Peripheral
A privacy-enabled peripheral in non-connectable mode uses non-resolvable or resolvable private addresses.
To connect to a central, the undirected connectable mode only should be used if host privacy is used. If the
controller privacy is used, the device can also use the directed connectable mode. When in connectable mode,
the device uses a resolvable private address.
Whether non-resolvable or resolvable private addresses are used, they are automatically regenerated after each
interval of 15 minutes. The device does not send the device name to the advertising data.
Central
A privacy-enabled central, performing active scanning, uses non-resolvable or resolvable private addresses only.
To connect to a peripheral, the general connection establishment procedure should be used if host privacy is
enabled. With controller-based privacy, any connection procedure can be used. The central uses a resolvable
private address as the initiator’s device address. A new resolvable or non-resolvable private address is
regenerated after each interval of 15 minutes.
Broadcaster
A privacy-enabled broadcaster uses non-resolvable or resolvable private addresses. New addresses are
automatically generated after each interval of 15 minutes. A broadcaster should not send the name or unique data
to the advertising data.
Observer
A privacy-enabled observer uses non-resolvable or resolvable private addresses. New addresses are
automatically generated after each interval of 15 minutes.
Characteristic value
properties (read, broadcast,
write, write without response,
notify, indicate, …). Determine
0x2803 how characteristic value can Read only,
be used or how characteristic
0xNNNN (UUID for characteristic descriptor can be accessed no authentication, no
attribute type) authorization
Characteristic value attribute
handle
Characteristic value UUID (16
or 128 bits)
A characteristic declaration contains the value of the characteristic. This value is the first attribute after the
characteristic declaration:
Attribute
Attribute type Attribute value Attribute permissions
handle
Read only,
0x2800 – UUID for “Primary Service” or 0xuuuu – 16 bits or 128 bits for
0xNNNN no authentication,
0x2801 – UUID for “Secondary Service” service UUID
no authorization
A service contains a service declaration and may contain definitions and characteristic definitions. A service
includes declaration follows the service declaration and any other attributes of the server.
Attribute
Attribute type Attribute value Attribute permissions
handle
Read only,
0x2802 (UUID for Include service End group
0xNNNN Service UUID no authentication, no
include attribute type) attribute handle handle
authorization
“Include service attribute handle” is the attribute handle of the included secondary service and “end group handle”
is the handle of the last attribute within the included secondary service.
For a detailed description about the GATT procedures and related responses events refer to the Bluetooth
specifications in Section 5 References.
1. 1. M = Mandatory; O = Optional
Device only broadcasts data using the link layer Broadcasts data can be
Broadcast mode advertising channels and packets (it does not set detected by a device using the Broadcaster
any bit on Flags AD type) observation procedure
The following GAP procedures are defined in Table 25. GAP observer procedure:
For a detailed description of the GAP procedures, refer to the Bluetooth specifications.
Target
• When a device is close, very far, far away:
– Causes an alert
How it works
• If a device disconnects, it causes an alert
• Alert on link loss: «Link Loss» service
– If a device is too far away
– Causes an alert on path loss: «Immediate Alert» and «Tx Power» service
• «Link Loss» service
– «Alert Level» characteristic
– Behavior: on link loss, causes alert as enumerated
• «Immediate Alert» service
– «Alert Level» characteristic
– Behavior: when written, causes alert as enumerated
• «Tx Power» service
– «Tx Power» characteristic
– Behavior: when read, reports current Tx Power for connection
The BlueNRG-1, BlueNRG-2 devices are system-on-chip with a Bluetooth low energy (BLE) radio. A Bluetooth
low energy (BLE) stack standard C library, in binary format, provides a high-level interface to control BlueNRG-1,
BlueNRG-2 Bluetooth low energy functionalities.
The BLE binary library provides the following functionalities:
• Stack APIs for:
– BLE stack initialization
– BLE stack application command interface (HCI command prefixed with hci_, and vendor specific
command prefixed with aci_ )
– Sleep timer access
– BLE stack state machines handling
• Stack event callbacks
– Inform user application about BLE stack events
– Sleep timer events
• Provides interrupt handler for radio IP
In order to get access to the BLE stack functionalities, user application is just requested to:
• Call the related stack APIs
• Handle the expected events through the provided stack callbacks
Linking the BLE stack binary library to the user application, as described in Figure 9. BLE stack reference
application.
Note: 1. API is a C function defined by the BLE stack library and called by user application.
2. A callback is a C function called by the BLE stack library and defined by the user application.
3. Driver sources are a set of drivers (header and source files) which handles all the BlueNRG-1, BlueNRG-2
peripherals (ADC, I2C, SPI, timers, Watchdog, UART).
Note: BLE stack v2.1 or later provides the capability to enable/disable, at compile time, the following BLE stack
features based on user specific application scenario:
1. Enable/disable controller privacy
2. Enable/disable LE secure connections
3. Enable/disable master role
4. Enable/disable data length extension (valid only for BlueNRG-2 device)
This allows user to potentially exclude some features from the available BLE stack binary library and decrease the
overall Flash memory footprint.
Refer to the BLE stack preprocessor configuration options defined on file Library\Bluetooth_LE\inc\
stack_user_cfg.h, in order to identify which are the available and supported combinations.
Starting from the BLE stack v2.1, all the other BLE application layer header files have been moved to the Library
\BLE_Application\layers_inc folder.
Library
It includes the required BLE stack To be included on the user main
ble_const.h \BLE_Application
header files application
\layers_inc
Header file for BlueNRG-1 GAP layer It is included through ble_const.h
bluenrg1_gap.h “”
constants header file
It is included through ble_const.h
bluenrg1_gatt_server.h Header file for GATT server constants “”
header file
It is included through ble_const.h
bluenrg1_hal.h Header file with HAL for BlueNRG-1 “”
header file
Header file for BlueNRG-1 BLE stack To be included on the user main
bluenrg1_stack.h “”
initialization, tick and sleep timer APIs application
It is included through ble_const.h
hci_const.h It contains constants for HCI layer.
header file
Header file for BlueNRG-1's link layer It is included through ble_const.h
link_layer.h “”
constants header file
Header file for BlueNRG-1 security It is included through ble_const.h
sm.h “”
manager constants header file
Note: Starting from the BLE stack v2.1, the AES CMAC encryption functionality required by BLE stack is available on
new standalone binary library: Library\\cryptolib\\cryptolib.a. This library must also be included on user
application IDE project.
typedef struct {
uint8_t* bleStartFlashAddress;
uint32_t secDbSize ;
uint32_t serverDbSize ;
uint8_t* stored_device_id_data_p;
uint8_t* bleStartRamAddress;
uint32_t total_buffer_size;
uint16_t numAttrRecord;
uint16_t numAttrServ ;
uint16_t attrValueArrSize;
uint8_t numOfLinks;
uint8_t extended_packet_length_enable;
uint8_t prWriteListSize;
uint8_t mblockCount;
uint16_t attMtu;
hardware_config_table_t hardware_config;
} BlueNRG_Stack_Initialization_t;
typedef struct {
uint32_t *hot_ana_config_table;
uint32_t max_conn_event_length;
uint16_t slave_sca;
uint8_t master_sca;
uint8_t ls_source;
uint16_t hs_startup_time ;
} hardware_config_table_t;
Maximum number of
services that can be stored Total calculated value must be increased of 2 due to the
numAttrServ in the GATT database, for standard attribute profile and GAP services, automatically added
the specific user BLE when initializing GATT and GAP layers
application
Each characteristic contributes to the attrValueArrSize value as
follows:
Characteristic value length
Characteristic UUID is 16 bits: adding 5 bytes
Size of the storage area for Characteristic UUID is 128 bits: adding 19 bytes
attrValueArrSize
attribute values
Characteristic has server configuration descriptor: adding 2
bytes
Characteristic has client configuration descriptor: adding 2 bytes
for each simultaneous connection
Characteristic has extended properties: adding 2 bytes
Maximum number of
numOfLinks simultaneous connections Valid values are from 1 to 8
that the device can support
extended_packet_length_ena Unsupported feature
0
ble (reserved for future use)
Number of prepare write
requests needed for a long
The minimum required value is calculated using a specific macro
prWriteListSize(2) write procedure for a
provided on bluenrg1_stack.h file: PREP_WRITE_X_ATT()
characteristic with len > 20
bytes
Number of allocated
The minimum required value is calculated using a specific macro
mblockCount(2) memory blocks for the BLE
provided on bluenrg1_stack.h file: MBLOCKS_COUNT
stack
Maximum supported
attMtu(2) Supported values ranges is 23, 247 bytes
ATT_MTU size
Low level configuration
Configured with the required hot table configuration values (refer
hot_ana_config_table parameters table for the
to file system_bluenrg1.c)
radio subsystem.
Maximum duration of the
connection event when the
max_conn_event_length device is inslave mode in <= 4000 (ms)
units of 625/256 μs (~2.44
μs)
Sleep clock accuracy in
slave_sca ppm value
slave mode
Sleep clock accuracy in
master_sca 0 to 7 corresponding to 500, 250, 150, 100, 75, 50, 30, 20 ppm
master mode
1. These values cannot be changed. To be potentially optimized for making the BLE stack configuration more flexible.
2. New radio initialization parameter supported on BLE stack v2.x.
3. High speed and low speed crystal sources can be defined through some preprocessor options (refer to file
system_bluenrg1.c).
4. For information about how to define the proper hs_startup_time value refer to the Bringing up the BlueNRG-1, BlueNRG-2
devices application note (AN4818) in Section 5 References at the end of this document.
/* Configuration Table */
#define COLD_START_CONFIGURATION
{
NUMBER_CONFIG_BYTE, ATB0_ANA_ENG_REG, 0x00,
NUMBER_CONFIG_BYTE, ATB1_ANA_ENG_REG, 0x30,
NUMBER_CONFIG_BYTE, RM1_DIG_ENG_REG, SMPS_10uH_RM1,
NUMBER_CONFIG_BYTE, CLOCK_LOW_ENG_REG, SMPS_ON,
NUMBER_CONFIG_BYTE, CLOCK_HIGH_ENG_REG, HIGH_FREQ_16M,
NUMBER_CONFIG_BYTE, PMU_ANA_ENG_REG, SMPS_10uH_PMU,
NUMBER_CONFIG_BYTE, CLOCK_ANA_USER_REG, LOW_FREQ_XO,
NUMBER_CONFIG_BYTE, PMU_ANA_USER_REG,PMU_ANA_USER_RESET_VALUE, PMU_ANA_USER_RESET_VALUE,
END_CONFIG
}
Regarding the ATB0_ANA_ENG_REG, ATB1_ANA_ENG_REG registers settings, some test modes are also
available in order to address some test scenarios. User should set such registers as follows:
Please notice that the default user mode register setting must be restored for typical user application scenarios:
The selected application configuration is defined within the BLE device controller through the following
instructions executed on DeviceConfiguration() function called by SystemInit() API (system_bluenrg1.c file)
at device initialization (power on):
/* Device configuration*/
BLUE_CTRL->RADIO_CONFIG = 0x10000U | (uint16_t)((uint32_t)cold_start_config
& 0x0000FFFFU);
while ((BLUE_CTRL->RADIO_CONFIG & 0x10000) != 0);
Example: if a stack function may be called inside UART ISR the following code should be used:
NVIC_DisableIRQ(UART_IRQn);
BTLE_StackTick();
NVIC_EnableIRQ(UART_IRQn);
Note: Global interrupts disabling should be limited to few microseconds (µs) if radio activities are ongoing.
This section provides information and code examples about how to design and implement a Bluetooth low energy
application on a BlueNRG-1, BlueNRG-2 device using the BLE stack v2.x binary library.
User implementing a BLE application on a BlueNRG-1, BlueNRG-2 device has to go through some basic and
common steps:
1. Initialization phase and main application loop
2. BLE stack events callbacks setup
3. Services and characteristic configuration (on GATT server)
4. Create a connection: discoverable, connectable modes and procedures
5. Security (pairing and bonding)
6. Service and characteristic discovery
7. Characteristic notification/indications, write, read
8. Basic/typical error conditions description
Note: In the following sections, some user applications “defines” are used to simply identify the device Bluetooth low
energy role (central, peripheral, client and server).
Define Description
int main(void)
{
uint8_t ret;
/* System Init */
SystemInit();
if (ret != BLE_STATUS_SUCCESS) {
printf("Error in BlueNRG_Stack_Initialization() 0x%02x\r\n", ret);
while(1);
}
while(1)
{
/* BLE Stack Tick */
BTLE_StackTick();
} /* end main() */
Note: 1. BlueNRG_Stack_Init_params variable defines the BLE stack initialization parameters as described on
Section 2.2 BLE stack event callbacks
2. BTLE_StackTick() must be called in order to process BLE stack events.
3. APP_Tick() is just an application dependent function, which handles the user application state machine,
according to the application working scenario.
4. BlueNRG_Sleep(SLEEPMODE_WAKETIMER, 0, 0, 0) enables the BLE device HW Sleep low power
mode: CPU is stopped and all the peripherals are disabled (only the low speed oscillator and the external
wake-up source blocks run). It’s worth noticing that this API with the specified parameters
(SLEEPMODE_WAKETIMER, 0, 0, 0) must be called, on application main while loop, in order to allow
the BlueNRG-1, BlueNRG-2 devices to enter sleep mode with wake-up source on BLE stack advertising
and connection intervals. If not called, the BLE device always stays in running power save mode (BLE
stack is not autonomously entering sleep mode unless this specific API is called). The User application can
use the BlueNRG_Sleep() API to select one of the supported BLE device HW low power modes (CPU
halt, sleep, standby) and set the related wake-up sources and sleep timeout, when applicable. The
BlueNRG_Sleep() API combines the low power requests coming from the application with the radio
operating mode, choosing the best low power mode applicable in the current scenario. The negotiation
between the radio module and the application requests is done to avoid losing data exchanged over-the-
air.
5. For more information about the BlueNRG_Sleep() API and BLE device low power modes refer to the
related application note in Section 5 References at the end of this document.
6. When performing the aci_gatt_init() and aci_gap_init() APIs, BLE stack always adds two
standard services: attribute profile service (0x1801) with service changed characteristic and GAP service
(0x1800) with device name and appearance characteristics.
7. The last attribute handles reserved for the standard GAP service is 0x000B when no privacy or host-based
privacy is enabled on aci_gap_init() API, 0x000D when controller-based privacy is enabled on
aci_gap_init() API.
Char value
Default Attribute Char value
Characteristic Char property Char UUID length
services handle handle
(bytes)
Attribute
profile service
Service changed 0x0002 Indicate 0x0003 0x2A05 4
Generic
access profile
(GAP)
service
Read|write without response|
Device came 0x0006 write| authenticated signed 0x0007 0x2A00 8
writes
Read|write without response|
Appearance 0x0008 write| authenticated signed 0x0009 0x2A01 2
writes
Peripheral preferred
connection 0x000A Read| write 0x000B 0x2A04 8
parameters
Readable without
Central address authentication or
0x000C authorization. 0x000D 0x2AA6 1
resolution(1)
Not writable
0x01:Peripheral
0x02: Broadcaster The role parameter can be a bitwise OR of any of the
Role
0x04: Central supported values (multiple roles simultaneously support)
0x08: Observer
0x00 for disabling privacy;
enable_Privacy 0x01 for enabling privacy; Controller-based privacy is supported on BLE stack v2.x
0x02 for enabling controller-based privacy
For a complete description of this API and related parameters refer to the Bluetooth LE stack APIs and event
documentations, in Section 5 References.
MAC address needs to be stored in the specific Flash location associated to the MAC address during the product
manufacturing.
A user can write its application assuming that the MAC address is placed at a known specific MAC Flash location
of the BLE device. During manufacturing, the microcontroller can be programmed with the customer Flash image
via SWD.
A second step could involve generating the unique MAC address (i.e. reading it from a database) and storing of
the MAC address in the known MAC Flash location.
The BlueNRG-1, BlueNRG-2 devices do not have a valid preassigned MAC address, but a unique serial number
(read only for the user).The unique serial number is a six byte value stored at address 0x100007F4: it is stored as
two words (8 bytes) at address 0x100007F4 and 0x100007F8 with unique serial number padded with 0xAA55.
The static random address is generated and programmed at very 1st boot of the device on the dedicated Flash
area. The value on Flash is the actual value the device uses: each time the user resets the device the stack
checks if valid data are on the dedicated Flash area and it uses it (a special valid marker on FLASH is used to
identify if valid data are present). If the user performs mass erase, the stored values (including marker) are
removed so the stack generates a new random address and stores it on the dedicated flash.
Private addresses are used when privacy is enabled and according to the Bluetooth low energy specification. For
more information about private addresses, refer to Section 1.7 Security manager (SM).
aci_gatt_add_service(uint8_t Service_UUID_Type,
Service_UUID_t *Service_UUID,
uint8_t Service_Type,
uint8_t Max_Attribute_Records,
uint16_t *Service_Handle);
This command returns the pointer to the service handle (Service_Handle), which is used to identify the service
within the user application. A characteristic can be added to this service using the following command:
aci_gatt_add_char(uint16_t Service_Handle,
uint8_t Char_UUID_Type,
Char_UUID_t *Char_UUID,
uint8_t Char_Value_Length,
uint8_t Char_Properties,
uint8_t Security_Permissions,
uint8_t GATT_Evt_Mask,
uint8_t Enc_Key_Size,
uint8_t Is_Variable,
uint16_t *Char_Handle);
This command returns the pointer to the characteristic handle (Char_Handle), which is used to identify the
characteristic within the user application.
For a detailed description of the aci_gatt_add_service() and aci_gatt_add_char() function parameters
refer to the header file Library\Bluetooth_LE\inc\bluenrg1_events.h.
The following pseudocode example illustrates the steps to be followed to add a service and two associated
characteristic to a proprietary, non-standard profile.
tBleStatus Add_Server_Services_Characteristics(void)
{
tBleStatus ret = BLE_STATUS_SUCCESS;
/*
The following 128bits UUIDs have been generated from the random UUID
generator:
D973F2E0-B19E-11E2-9E96-0800200C9A66: Service 128bits UUID
D973F2E1-B19E-11E2-9E96-0800200C9A66: Characteristic_1 128bits UUID
D973F2E2-B19E-11E2-9E96-0800200C9A66: Characteristic_2 128bits UUID
*/
/*Service 128bits UUID */
const uint8_t uuid[16] =
{0x66,0x9a,0x0c,0x20,0x00,0x08,0x96,0x9e,0xe2,0x11,0x9e,0xb1,0xe0,0xf2,0x73,0xd9};
/*Characteristic_1 128bits UUID */
const uint8_t charUuid_1[16] =
{0x66,0x9a,0x0c,0x20,0x00,0x08,0x96,0x9e,0xe2,0x11,0x9e,0xb1,0xe1,0xf2,0x73,0xd9};
/*Characteristic_2 128bits UUID */
const uint8_t charUuid_2[16] =
{0x66,0x9a,0x0c,0x20,0x00,0x08,0x96,0x9e,0xe2,0x11,0x9e,0xb1,0xe2,0xf2,0x73,0xd9};
Osal_MemCpy(&service_uuid.Service_UUID_128, uuid, 16);
/* Add the service with service_uuid 128bits UUID to the GATT server
database. The service handle Service_Handle is returned.
*/
ret = aci_gatt_add_service(UUID_TYPE_128, &service_uuid, PRIMARY_SERVICE,
6, &Service_Handle);
if(ret != BLE_STATUS_SUCCESS) return(ret);
Osal_MemCpy(&char_uuid.Char_UUID_128, charUuid_1, 16);
0x00: connectable undirected advertising (default) Sets the device in general discoverable mode.
aci_gap_set_discoverable() 0x02: scannable undirected advertising The device is discoverable until the device issues
the aci_gap_set_non_discoverable()
0x03: non-connectable undirected advertising API.
0x00: connectable undirected advertising (default) Sets the device in limited discoverable mode. The
device is discoverable for a maximum period of
0x02: scannable undirected advertising TGAP (lim_adv_timeout) = 180 seconds. The
aci_gap_set_limited_discoverable()
advertising can be disabled at any time by calling
0x03: non-connectable undirected advertising aci_gap_set_non_discoverable()
API.
API Description
Starts the limited discovery procedure. The controller is commanded to start active
aci_gap_start_limited_discovery_proc() scanning. When this procedure is started, only the devices in limited discoverable
mode are returned to the upper layers.
Starts the general discovery procedure. The controller is commanded to start active
aci_gap_start_general_discovery_proc()
scanning.
API Description
3.3.1 Set discoverable mode and use direct connection establishment procedure
The following pseudocode example illustrates only the specific steps to be followed to let a GAP peripheral device
be in general discoverable mode, and for a GAP central device direct connect to it through a direct connection
establishment procedure.
Note: It is assumed that the device public address has been set during the initialization phase as follows:
void GAP_Peripheral_Make_Discoverable(void )
{
tBleStatus ret;
const charlocal_name[]=
{AD_TYPE_COMPLETE_LOCAL_NAME,'B','l','u','e','N','R','G','1','T','e','s',' t'};
void GAP_Central_Make_Connection(void)
{
/*Start the direct connection establishment procedure to the GAP
peripheral device in general discoverable mode using the
following connection parameters:
LE_Scan_Interval: 0x4000;
LE_Scan_Window: 0x4000;
Peer_Address_Type: PUBLIC_ADDR (GAP peripheral address type: public
address);
Peer_Address: {0xaa, 0x00, 0x00, 0xE1, 0x80, 0x02};
Own_Address_Type:
PUBLIC_ADDR (device address type);
Conn_Interval_Min: 40 (Minimum value for the connection event
interval);
Conn_Interval_Max: 40 (Maximum value for the connection event
interval);
Conn_Latency: 0 (Slave latency for the connection in a number of
connection events);
Supervision_Timeout: 60 (Supervision timeout for the LE Link);
Minimum_CE_Length: 2000 (Minimum length of connection needed for the
LE connection);
Maximum_CE_Length: 2000 (Maximum length of connection needed for the LE connection).
*/
Note: 1. If ret = BLE_STATUS_SUCCESS is returned, on termination of the GAP procedure, the event callback
hci_le_connection_complete_event() is called, to indicate that a connection has been established
with the GAP_Peripheral_address (same event is returned on the GAP peripheral device).
2. The connection procedure can be explicitly terminated by issuing the API
aci_gap_terminate_gap_proc().
3. The last two parameters Minimum_CE_Length and Maximum_CE_Length of the
aci_gap_create_connection() are the length of the connection event needed for the BLE
connection. These parameters allows user to specify the amount of time the master has to allocate for a
single slave so they must be wisely chosen. In particular, when a master connects to more slaves, the
connection interval for each slave must be equal or a multiple of the other connection intervals and user
must not overdo the connection event length for each slave. Refer to Section 4 BLE multiple connection
timing strategy for detailed information about the timing allocation policy.
3.3.2 Set discoverable mode and use general discovery procedure (active scan)
The following pseudocode example illustrates only the specific steps to be followed to let a GAP Peripheral device
be in general discoverable mode, and for a GAP central device start a general discovery procedure in order to
discover devices within its radio range.
Note: It is assumed that the device public address has been set during the initialization phase as follows:
hci_le_set_scan_response_data(18,ServiceUUID_Scan);
/* Put the GAP peripheral in general discoverable mode:
Advertising_Type: ADV_IND (undirected scannable and connectable); Advertising_Interval_Min
: 100;
Advertising_Interval_Max: 100;
Own_Address_Type: PUBLIC_ADDR (public address: 0x00); Advertising_Filter_Policy: NO_WHITE_
LIST_USE (no whit list is used);
Local_Name_Length: 8
Local_Name: BlueNRG;
Service_Uuid_Length: 0 (no service to be advertised); Service_Uuid_List: NULL;
Slave_Conn_Interval_Min: 0 (Slave connection internal minimum value); Slave_Conn_Interval_
Max: 0 (Slave connection internal maximum value).
*/
ret = aci_gap_set_discoverable(ADV_IND, 100, 100, PUBLIC_ADDR,
NO_WHITE_LIST_USE,sizeof(local_name),
local_name, 0, NULL, 0, 0);
if (ret != BLE_STATUS_SUCCESS) PRINTF("Failure.\n");
} /* end GAP_Peripheral_Make_Discoverable() */
/*GAP Central: start general discovery procedure to discover the GAP peripheral device in dis
coverable mode */
void GAP_Central_General_Discovery_Procedure(void)
{
tBleStatus ret;
The responses of the procedure are given through the event callback
hci_le_advertising_report_event().The end of the procedure is indicated by
aci_gap_proc_complete_event() event callback with Procedure_Code parameter equal to
GAP_GENERAL_DISCOVERY_PROC (0x2).
/* RSSI value */
uint8_t RSSI = Advertising_Report[0].RSSI;
} /* hci_le_advertising_report_event() */
In particular, in this specific context, the following events are raised on the GAP central
hci_le_advertising_report_event () , as a consequence of the GAP peripheral device in discoverable
mode with scan response enabled:
1. Advertising Report event with advertising packet type (evt_type =ADV_IND )
2. Advertising Report event with scan response packet type (evt_type =SCAN_RSP)
0x0280E1003 0x02,0x01,0x06,0x08,0x09,0x42
0x00
0x00 (public address) ,0x6C,0x75,0x65,0x4E,0x52,0x4 0xCE
(ADV_IND) 412 7,0x02,0x 0A,0xFE
The advertising data can be interpreted as follows (refer to Bluetooth specification version in
Section 5 References):
0x12,0x66,0x9A,0x0C,
0x20,0x00,0x08,0xA7,0
0x01 (random
0x04 (SCAN_RS P) 0x0280E1003412 xBA,0xE3,0x11,0x06,0x 0xDA
address)
85,0xC0,0xF7,0x97,0x8
A,0x06,0x11
The scan response data can be interpreted as follows (refer to Bluetooth specifications):
called by the BLE stack, while an API is a function defined by the stack and called by the user application. The
BlueNRG-1, BlueNRG-2 BLE stack event callback prototypes are defined on file bluenrg1_events.h. Weak
definitions are available for all the event callbacks in order to have a definition for each event callback. As
consequence, based on its own application scenario, user has to identify the required device event callbacks to
be called and the related application specific actions to be done.
When a BLE application is implemented, the most common and widely used BLE stack events are those related
to the discovery, connection and terminate procedures, services, characteristics, characteristics descriptors
discovery procedures and attribute notification/ indication events on a GATT client, attribute modified events on a
GATT server.
GAP
hci_disconnection_complete_event() A connection is terminated central/
peripheral
GAP
Indicates to both of the devices forming the connection that a
hci_le_connection_complete_event() central/
new connection has been established
peripheral
For a detailed description about the BLE events, and related formats refer to the BlueNRG-1, BlueNRG-2
Bluetooth LE stack APIs and events documentation, in Section 5 References.
The following pseudocode provides an example of events callbacks handling some of the described BLE stack
events (disconnection complete event, connection complete event, GATT attribute modified event , GATT
notification event):
{
/* Add user code for handling BLE connection complete event based on
application scenario.
NOTE: Refer to header file Library\Bluetooth_LE\inc\bluenrg1_events.h
for a complete description of the event callback parameters.
*/
#if GATT_SERVER
/* This event callback indicates that an attribute has been modified from a
peer device.
*/
void aci_gatt_attribute_modified_event(uint16_t Connection_Handle,
uint16_t Attr_Handle,
uint16_t Offset,
uint8_t Attr_Data_Length,
uint8_t Attr_Data[])
{
/* Add user code for handling attribute modification event based on
application scenario.
NOTE: Refer to header file Library\Bluetooth_LE\inc\bluenrg1_events.h
for a complete description of the event callback parameters.
*/
...
} /* end aci_gatt_attribute_modified_event() */
#endif /* GATT_SERVER */
#if GATT_CLIENT
0x00: 'IO_CAP_DISPLAY_ONLY'
0x01: 'IO_CAP_DISPLAY_YES_NO',
0x02: 'KEYBOARD_ONLY'
0x03: 'IO_CAP_NO_INPUT_NO_OUTPUT'
0x04: 'IO_CAP_KEYBOARD_DISPLAY’
/*Device_1:
*/ tBleStatus ret;\
ret= aci_gap_set_io_capability(IO_CAP_DISPLAY_ONLY);
if (ret != BLE_STATUS_SUCCESS) PRINTF("Failure.\n");
/*Device_2:
*/ tBleStatus ret;
ret= aci_gap_set_io_capability(IO_CAP_KEYBOARD_ONLY);
if (ret != BLE_STATUS_SUCCESS) PRINTF("Failure.\n");
ret=aci_gap_set_authentication_requirement(BONDING,/*bonding is
enabled */
MITM_PROTECTION_REQUIRED,
SC_IS_SUPPORTED,/*Secure connection
supported
but optional */
KEYPRESS_IS_NOT_SUPPORTED,
7, /* Min encryption key size */
16, /* Max encryption
key size */
0x01, /* fixed pin is not used*/
0x123456, /* fixed pin */
0x00 /* Public Identity address type */);
if (ret != BLE_STATUS_SUCCESS) PRINTF("Failure.\n");
Once the security IO capability and authentication requirements are defined, an application can initiate a pairing
procedure as follows:
1. By using aci_gap_slave_security_req() on a GAP peripheral (slave) device (it sends a slave security
request to the master):
tBleStatus ret;
ret= aci_gap_slave_security_req(conn_handle,
if (ret != BLE_STATUS_SUCCESS) PRINTF("Failure.\n");
Since the Device_1, I/O capability is set as “Display Only”, it should display the generated pin in the device
display. Since Device_2 , I/O capability is set as “Keyboard Only”, the user can provide the pin displayed on
Device_1 to the Device_2 though the same aci_gap_pass_key_resp() API, by a keyboard.
Alternatively, if the user wants to set the authentication requirements with a fixed pin 0x123456 (no pass key
event is required), the following pseudocode can be used:
tBleStatus ret;
Note: 1. When the pairing procedure is started by calling the described APIs (aci_gap_slave_security_req()
or aci_gap_send_pairing_req()) and the value ret= BLE_STATUS_SUCCESS is returned, on
termination of the procedure, a aci_gap_pairing_complete_event() event callback is called to
indicate the pairing status on the callback Status parameter:
– 0x00: pairing success
– 0x01: pairing timeout
– 0x02: pairing failed
The reason parameter provides the pairing failed reason code in case of failure (0 if status
parameter returns success or timeout).
2. When 2 devices get paired, the link is automatically encrypted during the first connection. If bonding is also
enabled (keys are stored for a future time), when the 2 devices get connected again, the link can be simply
encrypted (without no need to perform again the pairing procedure).User applications can simply use the
same APIs, which do not perform the paring process but just encrypt the link:
– aci_gap_slave_security_req ) on the GAP peripheral (slave) device or
– aci_gap_send_pairing_req() on the GAP central (master ) device.
3. If a slave has already bonded with a master, it can send a slave security request to the master to encrypt
the link. When receiving the slave security request, the master may encrypt the link, initiate the pairing
procedure, or reject the request. Typically, the master only encrypts the link, without performing the pairing
procedure. Instead, if the master starts the pairing procedure, it means that for some reasons, the master
lost its bond information, so it has to start the pairing procedure again. As a consequence, the slave device
calls the aci_gap_bond_lost_event()event callback to inform the user application that it is not
bonded anymore with the master it was previously bonded. Then, the slave application can decide to allow
the security manager to complete the pairing procedure and re-bond with the master by calling the
command aci_gap_allow_rebond(), or just close the connection and inform the user about the
security issue.
Table 47. BLE sensor profile demo services and characteristic handle
Characteristic
Service /
Characteristic client descriptor Characteristic
Service Characteristic characteristic
value handle configuration format handle
handle
handle
Acceleration
NA 0x000C NA NA NA
service
Free Fall
0x000D 0x000E 0x000F NA
characteristic
Acceleration
0x0010 0x0011 0x0012 NA
characteristic
Environmental
NA 0x0013 NA NA NA
service
Temperature
0x0014 0xx0015 NA 0x0016
characteristic
Pressure
0x0017 0xx0018 NA 0x0019
characteristic
For detailed information about the sensor profile demo, refer to the BlueNRG-1_2 DK User Manual and the
sensor demo source code available within the BlueNRG-1_2 DK software package (see Section 5 References).
Service discovery procedures and related GATT events.
A list of the service discovery APIs with related description as follows:
The responses of the procedure are given through the aci_att_read_by_group_type_resp_event() event
callback. The end of the procedure is indicated by aci_gatt_proc_complete_event() event callback() call.
uint8_t Data_Length,
uint8_t Att_Data_List[]);
{
/*
Conn_Handle: connection handle related to the response;
Attr_Data_Length: the size of each attribute data;
Data_Length: length of Attribute_Data_List in octets;
Att_Data_List: Attribute Data List as defined in Bluetooth Core
specifications. A sequence of attribute handle, end group handle,
attribute value tuples: [2 octets for Attribute Handle, 2
octets End Group Handle, (Attribute_Data_Length - 4 octets) for
Attribute Value].
*/
/* Add user code for decoding the Att_Data_List field and getting
the services attribute handle, end group handle and service uuid
*/
}/* aci_att_read_by_group_type_resp_event() */
In the context of the sensor profile demo, the GAP central application should get three read by group type
response events (through related aci_att_read_by_group_type_resp_event() event callback), with the
following callback parameters values.
First read by group type response event callback parameters:
Table 49. First read by group type response event callback parameters
Table 50. Second read by group type response event callback parameters
Table 51. Third read by group type response event callback parameters
In the context of the sensor profile demo, when the discovery all primary service procedure completes, the
aci_gatt_proc_complete_event() event callback is called on GAP central application, with the following
parameters
aci_gatt_disc_all_char_of_service () This API starts the GATT procedure to discover all the characteristics
of a given service
This API starts the GATT the procedure to discover all the
aci_gatt_disc_char_by_uuid ()
characteristics specified by a UUID
This API starts the procedure to discover all characteristic descriptors
aci_gatt_disc_all_char_desc ()
on the GATT server
In the context of the BLE sensor profile demo, follow a simple pseudocode illustrating how a GAP central
application can discover all the characteristics of the acceleration service (refer to Table 1 second read by group
type response event callback parameters):
/*
Connection_Handle: connection handle related to the response;
Handle_Value_Pair_Length: size of each attribute handle-value
Pair;
Data_Length: length of Handle_Value_Pair_Data in octets.
Handle_Value_Pair_Data: Attribute Data List as defined in
Bluetooth Core specifications. A sequence of handle-value pairs: [2
octets for Attribute Handle, (Handle_Value_Pair_Length - 2 octets)
}/* aci_att_read_by_type_resp_event() */
In the context of the BLE sensor profile demo, the GAP central application should get two read type response
events (through related aci_att_read_by_type_resp_event() event callback), with the following callback
parameter values.
First read by type response event callback parameters:
Free fall
characteristic
128-bit
0x000D 0x10 (notify) 0x000E 0xE23E78A0CF4A11E18FFC0002A5D5C51B
characteristic
proprietary
UUID
Characteristic Characteristic
Characteristic handle Characteristic UUID Note
properties value handle
Acceleration
0x12 (notify and characteristic 128-
0x0010 0x0011 0x340A1B80CF4B11E1AC360002A5D5C51B
read) bit characteristic
proprietary UUID
In the context of the sensor profile demo, when the discovery all primary service procedure completes, the
aci_gatt_proc_complete_event() event callback is called on GAP central application, with the following
parameters:
Similar steps can be followed in order to discover all the characteristics of the environment service (Table 47. BLE
sensor profile demo services and characteristic handle).
In the context of the sensor profile demo, the GAP central application should use a simple pseudo code in order
to configure the free fall and the acceleration characteristic client descriptors configuration for notification:
tBleStatus ret;
uint16_t handle_value = 0x000F;
/*Enable the free fall characteristic client descriptor configuration for
ret = aci_gatt_write_charac_desc(conn_handle,
handle_value /* handle for free fall
client descriptor
configuration */
0x02, /* attribute value length */
0x0001, /* attribute value: 1 for
notification */
);
if (ret != BLE_STATUS_SUCCESS) PRINTF("Failure.\n");
handle_value = 0x0012;
/*Enable the acceleration characteristic client descriptor configuration
for notification */
ret= aci_gatt_write_char_desc(conn_handle,
handle_value /* handle for acceleration
client descriptor
configuration *
0x02, /*attribute value
length */
0x0001, /* attribute value:
1 for notification */
);
if (ret != BLE_STATUS_SUCCESS) PRINTF("Failure.\n");
Once the characteristic notification has been enabled from the GAP central, the GAP peripheral can notify a new
value for the free fall and acceleration characteristics as follows:
tBleStatus ret;
uint8_t val = 0x01;
uint16_t service_handle = 0x000C;
uint16_t charac_handle = 0x000D;
tBleStatus ret;
uint8_t buff[6];
uint16_t charac_handle = 0x0010;
/*Set the mems acceleration values on three axis x,y,z on buff array */
....
/*GAP peripheral notifies acceleration characteristic to GAP Central*/
ret= aci_gatt_update_char_value_ext(connection_handle, /* connection
handle */
service_handle, /* acceleration
service handle */
charac_handle, /* acceleration
characteristic
handle*/
1, /* updated type */
1, /* Char Length */
0, /* characteristic value offset */
0x06, /* characteristic value length */
buff /* characteristic value */
);
if(ret != BLE_STATUS_SUCCESS) PRINTF("Failure.\n");
}/* aci_gatt_notification_event() */
BLE_STATUS_SUCCESS (0x00) is returned when the API is successfully executed. For a list of error conditions
associated to each ACI API refer to the BlueNRG-1, BlueNRG-2 Bluetooth LE stack APIs and event
documentation, in Section 5 References
Master (1)
Master&Slave(2)
Master&Slave Master&Slave
is a GAP central is a GAP central
(3)
Slave_A(3) Slave_B
Step 1. One BLE device (called Master&Slave) is configured as central and peripheral by setting role as
GAP_PERIPHERAL_ROLE |GAP_CENTRAL_ROLE on GAP_Init() API . Let’s also assume that this
device also defines a service with a characteristic.
Step 2. Two BLE devices (called Slave_A, Slave_B) are configured as peripheral by setting role as
GAP_PERIPHERAL_ROLE on GAP_Init() API. Both Slave_A and Slave_B define the same service
and characteristic as Master&Slave device.
Step 3. One BLE device (called Master) is configured as central by setting role as GAP_CENTRAL_ROLE on
GAP_Init()API.
Step 4. Both Slave_A and Slave_B devices enter discovery mode as follows:
ret =aci_gap_set_discoverable(Advertising_Type=0x00,
Advertising_Interval_Min=0x20,
Advertising_Interval_Max=0x100,
Own_Address_Type= 0x0;
Advertising_Filter_Policy= 0x00;
Local_Name_Length=0x05,
Local_Name=[0x08,0x74,0x65,0x73,0x74],
Service_Uuid_length = 0;
Service_Uuid_length = NULL;
Slave_Conn_Interval_Min = 0x0006,
Slave_Conn_Interval_Max = 0x0008);
Step 5. Master&Slave device performs a discovery procedure in order to discover the peripheral devices
Slave_A and Slave_B:
The two devices are discovered through the advertising report events notified with the
hci_le_advertising_report_event() event callback.
Step 6. Once the two devices are discovered, Master&Slave device starts two connection procedures (as
central) to connect, respectively, to Slave_A and Slave_B devices:
Step 7. Once connected, Master&Slave device enables the characteristics notification, on both of them, using
the aci_gatt_write_char_desc() API. Slave_A and Slave_B devices start the characteristic
notification by using the aci_gatt_upd_char_val() API.
Step 8. At this stage, Master&Slave device enters discovery mode (acting as peripheral):
Local_Name=[0x08,0x74,0x65,0x73,0x74],
Service_Uuid_length = 0;
Service_Uuid_List = NULL;
Slave_Conn_Interval_Min = 0x0006,
Slave_Conn_Interval_Max = 0x0008);
Since Master&Slave device also acts as a central device, it receives the notification event related to the
characteristic values notified from, respectively, Slave_A and Slave_B devices.
Step 9. Once Master&Slave device enters discovery mode, it also waits for the connection request coming
from the other BLE device (called Master) configured as GAP central. Master device starts discovery
procedure to discover the Master&Slave device:
ret = aci_gap_start_gen_disc_proc(LE_Scan_Interval=0x10,
LE_Scan_Window=0x10,
Own_Address_Type = 0x0,
Filter_Duplicates = 0x0);
Step 10. Once the Master&Slave device is discovered, Master device starts a connection procedure to connect
to it:
Master&Slave device is discovered through the advertising report events notified with the
hci_le_advertising_report_event() event callback.
Step 11. Once connected, Master device enables the characteristic notification on Master&Slave device using
the aci_gatt_write_char_desc() API.
Step 12. At this stage, Master&Slave device receives the characteristic notifications from both Slave_A, Slave_B
devices, since it is a GAP central and, as GAP peripheral, it is also able to notify these characteristic
values to the Master device.
Note: A set of test scripts allowing to exercise the described BLE simultaneously master, slave scenario are provided
within the BlueNRG GUI SW package (see Section Revision history). These scripts can be run using the
BlueNRG GUI and they can be taken as reference to implement a firmware application using the BlueNRG-1,
BlueNRG-2 simultaneously master and slave feature.
hci_le_direct_advertising_report_event() if it has been unmasked and the scanner filer policy is set
to 0x02 or 0x03.
Server_RX_MTU specifies the ATT_MTU value agreed between the server and client.
The supported TxOctets value is in the range [27-251] and the TxTime is provided as follows: (TxOctets +14)*8.
Once hci_le_set_data_length() API is performed on a BlueNRG-2 device after the device connection, if
the connected peer device supports LE data packet length extension feature, the following event is raised on both
devices:
hci_le_data_length_change_event(uint16_t Connection_Handle,
uint16_t MaxTxOctets,
uint16_t MaxTxTime,
uint16_t MaxRxOctets,
uint16_t MaxRxTime)
This event notifies the host of a change to either the maximum link layer payload length or the maximum time of
link layer data channel PDUs in either direction (TX and RX). The values reported (MaxTxOctets,
MaxTxTime, MaxRxOctets, MaxRxTime) are the maximum values that are actually used on the connection
following the change.
aci_gatt_update_char_value_ext(uint16_tConn_Handle_To_Notify,
uint16_t Service_Handle,
uint16_t Char_Handle,
uint8_t Update_Type,
uint16_t Char_Length,
uint16_t Value_Offset,
uint8_t Value_Length,
uint8_t Value[]);
Refer to the aci_gatt_update_char_value_ext() API description for detailed information about API usage
and its parameter values.
The FlashRoutine() performs the Flash write operation only if there is enough time for this operation before
next scheduled radio activity.
void FlashRoutine(void)
{
static uint32_t flash_counter = 0;
static uint32_t flash_pattern = 0xAAAAAAAA;
if (HAL_VTimerDiff_ms_sysT32(Next_Advertising_SysTime,
HAL_VTimerGetCurrentTime_sysT32()) > FLASH_WRITE_GUARD_TIME)
{
if(FLASH->IRQRAW_b.CMDDONE == SET)
{
FLASH_ProgramWord((TEST_PAGE_ADDRESS flash_counter*4),
flash_pattern);
flash_counter++;
}
}
}
This section provides an overview of the connection timing management strategy of the BlueNRG-1, BlueNRG-2
stack when multiple master and slave connections are active.
• slave latency (connSlaveLatency): allows a slave to use a reduced number of connection events. This
parameter defines the number of consecutive connection events that the slave device is not required to
listen to the master.
When the host wants to create a connection, it provides the controller with the maximum and minimum values of
the connection interval (Conn_Interval_Min, Conn_Interval_Max) and connection length (Minimum_CE_Length,
Maximum_CE_Length) thus giving the controller some flexibility in choosing the current parameters in order to
fulfill additional timing constraints e.g. in the case of multiple connections.
Parameter Description
Timing allocation concept allows a clean time to handle multiple connections but at the same time imposes some
constraints to the actual connection parameters that the controller can accept. An example of the time base
parameters and connection slot allocation is shown in the figure below
Slot #1 has offset 0 with respect to the anchor period, slot #2 has slot latency = 2, all slots are spaced by 1.25 ms
guard time.
In particular:
• The initial anchor period is chosen equal to the mean value between the maximum and minimum connection
period requested by the host
• The first connection slot is placed at the beginning of the anchor period
• The duration of the first connection slot is set equal to the maximum of the requested connection length
Clearly, the relative duration of such first connection slot compared to the anchor period limits the possibility to
allocate further connection slots for further master connections.
A) First connection
ConnIntMin = 100 ms Anchor Period = 200 ms, Connection Interval #1 = 200 ms
ConnIntMax = 300 ms Slot #1 offset = 0 ms
CE_len_min = 10 ms Slot #1 len = 20 ms
CE_len_max = 20 ms Slot #1 latency = 1
S S S
1 1 1
Anchor Period
t
B) Second connection
ConnIntMin = 250 ms Anchor Period = 200 ms, Connection Interval = 400 ms
ConnIntMax = 500 ms Slot #2 offset = 21.5 ms
CE_len_min = 10 ms Slot #2 len = 50 ms
CE_len_max = 50 ms Slot #2 latency = 2
S S S S S
1 2 1 1 2
Anchor Period
t
C) Third connection
ConnIntMin = 50 ms Anchor Period = 100 ms, Connection Interval = 100 ms
ConnIntMax = 150 ms Slot #3 offset = 73 ms
CE_len_min = 10 ms Slot #3 len = 25.5 ms
CE_len_max = 100 ms Slot #1 latency = 2, Slot #2 latency = 4, Slot #3 latency = 1
S S S S S S S S S S S
1 2 3 3 1 3 3 1 2 3 3
Anchor Period
Input
Description Allowed range Notes
parameter
Assumptions: the formula defines internally the number of packets, at maximum length, that can be exchanged to
each slave per connection interval.
5 References
Name Title/description
This section lists the standard acronyms and abbreviations used throughout the document.
Term Meaning
Revision history
Contents
1 Bluetooth low energy technology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1 BLE stack architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Physical layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Link layer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.1 BLE packets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.3.2 Set discoverable mode and use general discovery procedure (active scan) . . . . . . . . . . . 40
5 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .68
6 List of acronyms and abbreviations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .69
Revision history . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .70
List of tables
Table 1. BLE RF channel types and frequencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Table 2. Advertising data header content. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Table 3. Advertising packet types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Table 4. Advertising event type and allowable responses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Table 5. Data packet header content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Table 6. Packet length field and valid values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Table 7. Connection request timing intervals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Table 8. Attribute example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Table 9. Attribute protocol messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Table 10. Combination of input/output capabilities on a BLE device . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Table 11. Methods used to calculate the temporary key (TK) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Table 12. Mapping of IO capabilities to possible key generation methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Table 13. Characteristic declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Table 14. Characteristic value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Table 15. Service declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Table 16. Include declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Table 17. Discovery procedures and related response events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Table 18. Client-initiated procedures and related response events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Table 19. Server-initiated procedures and related response events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Table 20. GAP roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Table 21. GAP broadcaster mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Table 22. GAP discoverable modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Table 23. GAP connectable modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Table 24. GAP bondable modes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Table 25. GAP observer procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Table 26. GAP discovery procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Table 27. GAP connection procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Table 28. GAP bonding procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Table 29. BLE stack library framework interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Table 30. BLE application stack library framework interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Table 31. BlueNRG-1 BLE stack initialization parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Table 32. Application configuration preprocessor options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Table 33. Test mode configurations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Table 34. User mode configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Table 35. User application defines for BLE device roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Table 36. GATT, GAP default services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Table 37. GATT, GAP default characteristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Table 38. aci_gap_init() role parameter values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Table 39. GAP mode APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Table 40. GAP discovery procedure APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Table 41. Connection procedure APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Table 42. ADV_IND event type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Table 43. ADV_IND advertising data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Table 44. SCAN_RSP event type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Table 45. Scan response data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Table 46. BLE stack: main events callbacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Table 47. BLE sensor profile demo services and characteristic handle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Table 48. Service discovery procedures APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Table 49. First read by group type response event callback parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Table 50. Second read by group type response event callback parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Table 51. Third read by group type response event callback parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Table 52. Characteristics discovery procedures APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
List of figures
Figure 1. Bluetooth low energy technology enabled coin cell battery devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Figure 2. Bluetooth low energy stack architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Figure 3. Link Layer state machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Figure 4. Packet structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Figure 5. Packet structure with LE data packet length extension feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Figure 6. Advertising packet with AD type flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Figure 7. Example of characteristic definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Figure 8. Client and server profiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Figure 9. BLE stack reference application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Figure 10. BLE MAC address storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Figure 11. BLE simultaneous master and slave scenario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Figure 12. Advertising timings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Figure 13. Example of allocation of three connection slots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Figure 14. Example of timing allocation for three successive connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64