This article discusses changes to the Bluetooth SDK version 2.7.0.
Discussion
Starting in SDK version 2.7.x, the so-called legacy bootloader has been deprecated. This means that if you build and flash one of our sample applications you must now also build and flash a bootloader. The most reliable method is to build a bootloader for your device using the Appbuilder and flash the combined bootloader (*-combined.s37) using Simplicity Commander. This ensures that your device has both stages of the bootloader and will allow your application to run.
If your device does not have a bootloader, the symptoms you can expect include the application failing to start and the debugger showing the message "failed to read memory" in the disassembly window.
Please see UG266 for detailed information on the Gecko bootloader.
This KBA going to highlight the main differences between SDK 2.4.x and newer SDK versions and provides a guide about moving existing projects to the SDK 2.7.0.
SDK 2.4.2 vs SDK 2.6.0
SDK 2.6.0 changed the way of hardware initialization and configuration flow. Additionally, it changed the structure of projects. Let’s go through on these changes one by one.
No linked resources from SDK folders. Every .c and .h file copied to the folder of the project. The folder structure is the same as in gecko SDK suit except for emlib and emdrv configuration files are copied to project root.
The .hwconf file removed, so there is no graphical way to configure peripherals
As the .hwconf file removed the src\InitDevice.c and src\InitDevice.h also removed. These files use to contain peripheral initialization code. This initialization code was called in main.c before gecko_init().
Introduction of hal-config.h. This file collects the hardware related configuration options.
Introduction of init_mcu.c,init_board.c and init_app.c. These files contain MCU, board and application level initialization code. This initialization code now called in main.c before the gecko_init.
Board related initialization code, for example disabling the SPI flash on the radio board, moved from main.c to init_board.c.
SDK 2.6.0 vs SDK 2.7.0
SDK 2.7.0 introduced a new OTA mechanism called Application Loader. This mechanism only works with the latest Gecko Bootloader. Additionally, the stack now provided as a library and not as a binary blob. The list below highlights the most important effects of these changes.
In SDK 2.7 OTA relies on the application loader. If a project wants to use OTA the application loader object file must be added to the project. The file can be found here:
The file is added to the SoC examples example by default but NCP examples do not contain that as they typically updated by UART DFU.
Application loader expects gecko bootloader. The application loader is not supported by legacy bootloaders. In practice if OTA used, then the application loader is mandatory, therefore the gecko bootloader is mandatory too.
Since SDK 2.7.0 examples do not contain default bootloader. Therefore, the bootloader must be built and flashed separately using the Gecko Bootloader SDK or with downloading prebuilt demos.
Because Application Loader introduced and Bluetooth stack now provided as a library, memory layout also changed. This change affects the .ld (GCC) or .icf (IAR) linker script files too.
aat.h removed from main.c because Application Loader does not need that.
boards.h removed and its content moved to ble-configuration.h.
Porting Tips
Because these fundamental changes, migration to SDK 2.7.0 from SDK 2.4.2 or older is not a trivial task. Here we collect few tips which may make the process easier.
Start your project from soc-empty or ncp-empty example then add your application source and header files from the old project.
It is wise to merge the content of the old InitDevice.c to the new init_mcu.c.
Don’t use the old main.c because it includes different headers and calls different initialization functions. Copy only the event handling loop to the new main.
Don’t use linker script from your old project.
Import your old gatt.xml with the visual GATT editor in case you want to modify the GATT in the future. In case you don’t want to update it just copy gatt_db.c and gatt_db.h from the old project.
In case you modified the init_mcu.c,init_board.c or init_app.c make sure you don’t overwrite them in case of generating the GATT.
Again: Gecko bootloader is mandatory in case of OTA, you can read more about this here.
The following article discusses the special case when you want to upgrade your Gecko Bootloader via Bluetooth with an image that has different slot configuration than the previous Gecko Bootloader you used on your device.
To upgrade the bootloader with a new slot configuration is problematic, because the upgrade image is uploaded by the old bootloader to the old slot address, but after the bootloader upgrade the new bootloader tries to bootload the apploader image from the new address – this will definitely fail.
The following workaround can be used to solve this issue:
Suppose you want to upgrade from bootloader A, that has Slot0 address A, to bootloader B, that has Slot0 address B.
you have a bootloader with Slot0 address A in your device. This will upload the upgrade image to address A.
first you have to upgrade to a temporary multislot bootloader with Slot0 address B and Slot1 address A. This can bootload from address A but will upload the next upgrade image to address B.
finally you have to upgrade to the single slot bootloader with Slot0 address B, as originally intended. This can bootload from address B.
How to configure the temporary multislot bootloader:
create a new bootloader project. Use Bluetooth in-place OTA DFU Bootloader or Internal/External storage bootloader, as you normally do.
define the customer version string to N+1, where N is the version number of the original bootloader. You can do this by defining BOOTLOADER_VERSION_MAIN_CUSTOMER on the Other tab in the AppBuilder.
On the Storage tab define the slots. Define Slot0 to the new address (with the new slot size), and Slot1 to the old address (with the old slot size).
The multislot configuration needs a bootload info table that takes 8kB. It has to be defined somewhere outside of Slots and outside of the bootloader and apploader area. Go to Plugins page, select Common Storage, and define the Start address for bootload info to e.g. 8kB before the Slot with lower address. Make sure that the start address is aligned with the 2kB flash page size!
press Generate to generate your project
there is one more change needed. The bootload info table should be normally initialized by the app. This table tells which slots should be bootloaded in which order. Since there is no valid application image, however, after the bootloader upgrade, the bootloader code has to be modified:
-find storage-common/btl_storage.c in your project.
-right click on it and select „Copy Linked File into Project”. This will copy btl_storage.c and btl_storage.h into the project from the SDK.
-in storage-common_inc/btl_storage.h change to following line
The Bluetooth SDK supports two developing modes, System-On-Chip (SoC) and Network Co-Processor (NCP). For SoC mode, all the application will run on a single EFR32 device. For NCP mode, a EFR32 device acts as the coprocessor, working together with a host controller. AN1042: Using the Silicon Labs Bluetooth® Stack in Network Co-Processor Mode has detailed description of the NCP mode. It’s recommended to read this application note before reading this article, which can give you a better understanding of NCP mode.
Figure 1. SoC Mode
Figure 2. NCP Mode
BGLib and BGAPI
BGAPI is a custom binary protocol used to externally control our chipset and modules. BGAPI is a protocol specification only.
BGLib is an ANSI C reference implementation of the BGAPI binary protocol. BGLib only runs outside of our chipset and modules. BGLib assumes the host MCU is little-endian.
When using SoC mode, it allows you to run an application right on the chipset or module and call the BGAPI directly. However, if using the NCP mode, the application runs on an external device – typically a microcontroller, everything can communicate over UART between the NCP host and NCP target.
BGLIB_DEFINE
BGLib uses a set of global variables that are defined using macro BGLIB_DEFINE(), found in gecko_bglib.h. The host application that uses BGLib must include BGLIB_DEFINE() in global scope (i.e. it must be placed outside any function implementation).
BGLIB_DEFINE() is used to declare variables used for BGLib, it must be define globally.
_gecko_cmd_msg – The instance to store the command message.
_gecko_rsp_msg – The instance to store the response message.
gecko_cmd_msg – Pointer to _gecko_cmd_msg instance.
gecko_rsp_msg – Pointer to _gecko_rsp_msg instance.
gecko_queue[BGLIB_QUEUE_LEN] – FIFO buffer to store the messages received from the NCP target.
gecko_queue_w – FIFO buffer write index, working with gecko_queue_r to indicate if there is new message stored in the queue, it offsets by one if a new message is received.
gecko_queue_r – FIFO buffer read index, working with gecko_queue_w to indicate if there is new message stored in the queue, it offsets by one if a new message is read out from the queue.
bglib_output, bglib_input, bglib_peek – Function pointers to writing to / reading from / peek UART.
The symbol BGLIB_QUEUE_LEN defines the length of queue, it’s 30 by default and depends on the real use cases and allowed host memory usage.
Operation Modes
Blocking mode – If this mode is used, BGLib will get blocked in waiting events from NCP target if there is no data to send nor events to handle. To use this mode, use gecko_wait_event() to check events and call the function BGLIB_INITIALIZE(OFUNC, IFUNC) in your initialization code.
Nonblocking mode – If this mode is used, BGLib will not get blocked if there is no data to send nor data to receive. To use this mode, use gecko_peek_event() to check events and call the function BGLIB_INITIALIZE_NONBLOCK(OFUNC, IFUNC, PFUNC) in your initialization code.
It depends on the real use case which mode should be used. If there are many tasks not related to Bluetooth, nonblocking mode should be a better choice, because it will bypass the BGLib functions if there are no Bluetooth events to be handled and allows the MCU to process other tasks. The reason BGLib supports blocking mode is for symmetry purpose that the same code should work in both SoC and NCP modes, it’s recommended to use nonblocking mode because it gives the user better control of their application in most of the use cases.
Figure 3. Blocking vs Nonblocking
Function Mapping
Below functions are used to read from and write to UART. BGLib accesses UART through function pointers so that the code is platform independent. User must map the function pointers to platform-specific UART transmit / receive routines when initializing BGLIb. This is done using macro BGLIB_INITIALIZE() or BGLIB_INITIALIZE_NONBLOCK(), depending if blocking or non-blocking mode is used.
Add “BGLIB_DEFINE();” to the macro definition area in your project.
Add BGLIB_INITIALIZE(user_output, user_input) or BGLIB_INITIALIZE_NONBLOCK(user_output, user_input, user_peek) to the initialization code, after that, it’s recommended to call gecko_cmd_system_reset(0); function to reset the NCP target.
Add below template to the while loop to handle all the events received from NCP target.
static void appHandleEvents(struct gecko_cmd_packet *evt) {
if (NULL == evt) {
return;
}
/* Handle events */
switch (BGLIB_MSG_ID(evt->header)) {
case xxx:
break;
case xxx:
break;
…
default:
break;
}
}
While(1){
...
/* Check for stack event. */
evt = gecko_peek_event();
/* Run application and event handler. */
appHandleEvents(evt);
...
}
This example uses the nonblocking mode. You can import them to your Simplicity Studio, compile and download to your devices. The example is a very simple one, which only provides the skeleton showing the usage of both NCP host and NCP target. You can verify the example using a smartphone to scan and connect to it. It will advertise after boot or disconnected.
Memory Usage
GBGLib needs RAM for the variables defined in BGLIB_DEFINE(); as well as flash, below is the detailed RAM and flash usage of the example, the compiler is IAR with “High size” optimization.
Module ro code ro data rw data
------ ------- ------- -------
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\CMSIS\EFM32PG1B: [1]
startup_efm32pg1b.o 348
system_efm32pg1b.o 136 16 16
------------------------------------------------
Total: 484 16 16
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\emlib: [2]
em_cmu.o 756 4 4
em_gpio.o 156
em_system.o 52
em_usart.o 340
------------------------------------------------
Total: 1 304 4 4
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\src: [3]
app.o 400 20 8 348
gecko_bglib.o 336
main.o 116
------------------------------------------------
Total: 852 20 8 348
RAM
The RAM usage for the unit gecko_cmd_packet is 0x104. For 32-bit MCU, each point occupies 4-byte. The length of the queue is 30, so it takes 0x104 * 30 = 0x1e78.
The total flash of the example is 484+1304+852= 2640 bytes. They can be split by functionalities.
Basic part - It is required for any EFM32PG1 projects. startup_efm32pg1b.o, system_efm32pg1b.o and main.o and em_system.o, the flash occupation is 484+116+52 = 652 bytes. This part is platform-specific.
UART related part - Driver of UART. em_cmu.o, em_gpio.o and em_usart.o, the flash occupation is 756+156+340 = 1252 bytes. This part is platform-specific.
BGLib and application part – App.o has the basic skeleton of the Bluetooth event handler, which is the minimal requirement of application. The flash occupation is 400+336 = 736 bytes.
There are many new features introduced in Bluetooth 5.0 specification, including 2M PHY, LE coded PHY etc., but they are probably not supported by the devices which were already in the market before Bluetooth 5.0 specification was released. It becomes more important to know which features are supported by specified devices when designing peripherals connecting to them. Here is a description how to get such information from the Bluetooth SIG website.
Below is an example to get the listing information of Samsung Galaxy S8+, the model name is SM-G9550. You can search for any other listed devices following the steps below.
Type the model name into the search label, then click search. If the device is listed in Bluetooth SIG, the report including some major information (such as specification name) should be displayed.
Click the Declaration ID. Declaration details will show on the page.
Click “View ISC details”.
You will see below information on the page. The left part shows all the categories, and the right part shows all the items included in the selected category. Below picture is an example to search “LE 2M PHY” and “LE Coded PHY”, we can see that the LE 2M PHY is supported but the LE Coded PHY is not.
Besides of LE 2M PHY and LE Coded PHY, you can easily find other Bluetooth features on this page and see if they are supported or not.
· CCC descriptor – CCC descriptor has the UUID 0x2902, but Android doesn’t support 16-bit UUID, so it needs to be change to 128-bit UUID - 00002902-0000-1000-8000-00805f9b34fb. The API gecko_cmd_gatt_set_characteristic_notification will return error that it can’t find CCC descriptor with UUID 0x2902 in the characteristic. So, I write the next handle of NOTIFY_CHAR which is the location of CCC descriptor of this characteristic on the server side as workaround. This problem didn’t happen when I tested with Android 7.0 devices.
A working example implementing the BLE central role and GATT client.
A reference code of Android device as peripheral role and GATT server.
This article is for people who only have one Wireless Starter Kit (WSTK) and want to implement central role on it. If you have more than one WSTK and want to connect them, you could probably go through the SPP-over-BLE example which implements both the central and peripheral roles.
In case you only have one WSTK, we could use the smartphone as the peripheral and GATT server, then implement the central role and GATT client on the WSTK.
The typical work flow of the central device is shown as below:
Scan for nearby advertisements, you could add your own filter on the advertisements or scan responses to make decision to which device the central device should connect.
After filtered device is found, establish connection.
After connection established, discover services and characteristics.
Configure Client Characteristic Configuration(CCC) for characteristics if needed.
This is the typical behaviors central device does while connecting to a peripheral, but NOT all the processes are mandatory.
Features
To run this example, you need to have below devices.
An EFR32BG or EFR32MG based board – this example is developed for the EFR32BG or EFR32MG based board and modules. It works well on the WSTK and take the assumption that the 2 buttons on the WSTK are connected to GPIO PF6 and PF7, and modifications (Probably on buttons mapping) may be needed to run on any customized boards.
An Android smartphone – Make sure that this device supports BLE both on the hardware and software side. For hardware side, please check the device manual, and for the software side, Android has BLE software support from Android version 4.3.
GATT Server
A so-called “Demo service” is added to the server, and this service contains 2 characteristics “NOTIFY_CHAR” and “RW_CAHR”, this is done on the smartphone side.
Name
UUID
Properties
Demo Service
df6a8b89-32d1-486d-943a-1a1f6b0b52ed
---
NOTIFY_CHAR
0ced7930-b31f-457d-a6a2-b3db9b03e39a
Notify
RW_CHAR
0ced7930-b31f-457d-a6a2-b3db9b03e39a
Read and Write
Communication
This example demonstrates to use an EFR32 based board as a client and a smartphone as a server and send data back and forth between them. Below is a brief lists of features:
Smartphone to send advertisements and EFR32 baord scan for it and connects to the desired one.
EFR32 discover the gatt database on the smartphone.
EFR32 writes/reads data to/from smartphone to demonstrate sending data from EFR32 to smartphone.
Smartphone sends notification periodically to EFR32 to demonstrate sending data from smartphone to EFR32.
State Machine
There are 2 versions of the example code provided in the attachment, one is with a finite state machine implementation which gives more flexibility and expansibility, the other one is not, which is the lightest weight of the central role and GATT client implementation.
Import the example
To run this example, you will need to download Simplicity Studio and the attachment which includes 6 files, app.c, app.h, app_nofsm.c, fsm.c, fsm.h and the server.apk. Below is a brief guide on how to import them to your project.
Download the latest Bluetooth SDK via Simplicity Studio if you haven't done it.
Create a "soc-empty" project base on the board you are using as the starting point.
Drag the app.c(app_nofsm.c for no state machine version), app.h, fsm.c and fsm.h files to the project created just now, then compile and program to your board.
This is an optional step, include the Logging System to the project to get powerful logging like figure 1. By default, the code uses the simplest way to print data via VCOM.
Install the server.apk to your Android smartphone.
Run the example
After you have successfully import the example and done all the above steps, you can try below steps to verify the functionalities.
Open a serial terminal to connect to EFR32, which uses the USB-UART as the default interface.
Open the smartphone app, it will start advertising immediately. And EFR32 will also scan for it after it power up.
EFR32 device will autonomously connect to the smartphone if the advertisement payload matches.
Pressing PB0 on the WSTK will write 1 and 5 circularly to the RW_CHAR characteristic in the smartphone app gatt server database, pressing PB1 to read the current data back.
Smartphone will send notification with fixed payload "0x11 0x22" to the EFR32 device autonomously and periodically, the interval is determined by the value written in the RW_CHAR characteristic in last step in seconds.
Below are screenshots of the serial terminal and smartphone.
Figure 1. Terminal Output
Below is a brief description of the time point and the behaviors.
At 1, system boot.
From 1 to 2, EFR32 device is looking for the device which fit its filter and connects to it, then find services and characteristics, enable notification of the notify characteristic at last.
At 3, smartphone app starts sending notification periodically.
At 4, PB1 pressed to know what interval the smartphone is using to send notifications.
At 5. PB0 pressed to change the interval from 5 seconds to 1 second.
At 6, PB1 pressed again as point 4.
At 7, Smartphone app was terminated intendedly, EFR32 goes back to disconnected state and tries to find devices again.
The Out of Band (OOB) association model is primarily designed for scenarios where an Out of Band mechanism is used to both discover the devices as well as to exchange or transfer cryptographic numbers used in the pairing process. In order to be effective from a security point of view, the Out of Band channel should provide different properties in terms of security compared to the Bluetooth radio channel. The Out of Band channel should be resistant to MITM attacks. If it is not, security may be compromised during authentication.
The user's experience differs a bit depending on the Out of Band mechanism. As an example, with a Near Field Communication (NFC) solution, the user(s) will initially touch the two devices together, and is given the option to pair the first device with the other device. If "yes" is entered, the pairing is successful. This is a single touch experience where the exchanged information is used in both devices. The information exchanged includes discovery information (such as the Bluetooth Device Address) as well as cryptographic information. One of the devices will use a Bluetooth Device Address to establish a connection with the other device. The rest of the exchanged information is used during authentication.
The OOB mechanism may be implemented as either read only or read/write. If one side is read only, a one-way authentication is performed. If both sides are read/write, a two-way authentication is performed.
The OOB protocol is selected only when the pairing process has been activated by previous OOB exchange of information and one (or both) of the device(s) gives OOB as the IO capabilities. The protocol uses the information which has been exchanged and simply asks the user to confirm connection.
The OOB association model supports any OOB mechanism where cryptographic information and the Bluetooth Device Address can be exchanged. The OOB association model does not support a solution where the user has activated a Bluetooth connection and would like to use OOB for authentication only.
There are 2 OOB pairing modes, one is OOB with legacy pairing and the other is OOB with secure connection pairing. This example implements both modes for user’s reference.
There are 2 projects in the example, implementing the central and peripheral rolls.
Central
It’s the master roll of the connection
Implements the GATT client
It sends the write request to the server every 3 seconds and receives the notification from server side.
Peripheral
It’s the slave roll of the connection
Implements the GATT server, there are 1 service containing 2 characteristics
Notification characteristic – the property of this characteristic is “notify”, which doesn’t require authentication.
Write characteristic – the property of this characteristic is “Authenticated write”, which requires authenticated connection to write value to this characteristic.
It sends notification to the client every 3 seconds and receives write request from the client.
Due to the different property of these two characteristics, if the pairing and bonding procedure succeeds, the client will receive notifications and the server will receive write requests. Otherwise if pairing and bonding procedure fails, the client should not be able to write the characteristic value due to unauthenticated connection, but it should be able to receive notifications because it doesn’t require authentication.
Key points of the example
Pairing modes
In both projects, there is a symbol definition - PAIRING_MODE, it can either be LEGACY_PAIRING or SECURE_CONNECTION_PAIRING. This symbol determines which pairing mode will be used in the connection.
Central – It scans for the advertisement containing the service UUID “4880c12c-fdcb-4077-8920-a150d7f9b907”, and establish connection if found. After connection, go through the pairing and bonding procedure, discover services and characteristics. Send write request to the peer device every 3 seconds after the specified characteristic is found. Enable CCC of the specified characteristic the peer device to enable notifications.
Peripheral – It won’t start advertising after boot until it receives the OOB data from the serial terminal. For OOB with legacy pairing, the OOB data is 16-byte length, for OOB with secure connection pairing, the length is 32-byte, containing 16-byte OOB data and 16-byte confirm value. It will go through the pairing and bonding procedure after connection established with the central device, and send notifications to central every 3 seconds after CCC is enabled by the central device.
Test the example
As shown above, the example requires 2 devices (BRD4104a Rev A00) and serial terminal, VCOM has been enabled in the example, so the serial print information will go out from the USB cable.
Central device (#D1) – the device programmed with the project “KBA_oob_central”.
Peripheral device (#D2) - the device programmed with the project “KBA_oob_peripheral”.
Serial terminal (#S1) connected to central device.
Serial terminal (#S2) connected to peripheral device.
Test process
Power on both devices (#D1 and #D2) by the USB cable.
Open the serial terminals connected to both device, the port name should be “JLink CDC UART Port (COMxx)”.
Recognize which serial terminal connects to #D1 and which connects to #D2 by the print information after boot. Enter the right OOB data shown on #S1 to #S2. #D2 should start advertising if it receives enough length of data.
#D1 will connect and start pairing and bonding to #D2 automatically.
Below are 4 different test results
Figure 1 shows what happened if right OOB data was input while using the legacy pairing mode. Both sides can receive the GATT data from the remote peer device.
Figure 2 shows what happened if wrong OOB data was input while using the legacy pairing mode. Only the notification can be received, the write characteristic can’t be written because of unauthenticated connection.
Figure 3 shows what happened if right OOB data was input while using the secure connection pairing mode. Both sides can receive the GATT data from the remote peer device.
Figure 2 shows what happened if wrong OOB data was input while using the secure connection pairing mode. Only the notification can be received, the write characteristic can’t be written because of unauthenticated connection.
Figure 1. OOB with legacy pairing succeed
Figure 2. OOB with legacy pairing failed
Figure 3. OOB with Secure Connection pairing succeed
Figure 4. OOB with Secure Connection pairing failed
This article is about the differences among the types of a characteristic value. In the profile toolkit, there are 3 types of value can be used, hex, utf-8 and user. You can find detailed description in UG118, chapter 2.5.3.
Values: hex: Value type is hex utf-8: Value is a string user: When the characteristic type is marked as type="user" the application is responsible of initializing the characteristic value and also providing it for example when read operation occurs. The Bluetooth stack does not initialize the value, nor automatically provide the value when it's being read. When this is set the Bluetooth stack generates gatt_server_user_read_request or gatt_server_user_write_request which must be handled by the application. Default: utf-8
Introduction
The idea of this article is to give both examples of type "user" and "hex" to help users choosing the right property of a characteristic value.
The most significant difference between the type “user” and the other two types is where the data is stored.
Type – user
If you use "user" as the data type, the value of the characteristic is stored in the application layer. And you need to respond to write/read requests by sending write/read response back via API gecko_cmd_gatt_server_send_user_read_response(…) and gecko_cmd_gatt_server_send_user_write_response(…).
For example, there is a characteristic with length 20, you need to allocate a 20-byte buffer in the application layer to store its value.
When read request received, gecko_evt_gatt_server_user_read_request_id event is generated, you should respond the buffer value via gecko_cmd_gatt_server_send_user_read_response(…)
When write request received, gecko_evt_gatt_server_user_write_request_id event is generated, you should modify the local buffer with the data in write request and respond it via gecko_cmd_gatt_server_send_user_write_response(…)
Type – hex or utf-8
If you use the property other than "user", the stack will allocate and manage the buffer for the characteristic value automatically.
When read request received, the read response will be filled with the characteristic value and sent back to the peer device all by the stack.
When received write request, the stack will modify the characteristic value and generate a gecko_evt_gatt_server_attribute_value_id event to notify the user.
If you want to read or write the characteristic value locally, use these 2 APIs gecko_cmd_gatt_server_read_attribute_value(...) and gecko_cmd_gatt_server_write_attribute_value(...).
2 Notes:
DO NOT use the APIs gecko_cmd_gatt_server_read_attribute_value(...) and gecko_cmd_gatt_server_write_attribute_value(...) to read or write a characteristic value whose type is "user", because the data buffer is in your application code and stack never knows its value.
DO NOT forget to respond to the read and write requests if the characteristic value type is “user”, otherwise no other GATT operation can be issued until GATT timeout.
Create “SoC-Empty” example as the starting point and specify the project name and compiler (GCC or IAR).
Open the .isc file in the project, modify the GATT database. In this example, one service and two characteristics are added into the GATT database.
User type characteristic – the value type is “user”, its properties are “read” and “write”
Hex type characteristic – the value type is “hex”, its properties are “read” and “write”
Because the type “utf-8” has the same operation procedure as “hex”, there is no other characteristic with “utf-8” type.
Note: DO NOT FORGET TO CLICK “GENERATE” BUTTON AFTER YOU MODIFY THE FILE.
Copy and paste the main.c app.c and app.h files to your project root directory.
Test the example
The example code shows where to handle the read and write requests to the characteristic with user type, as well as the event generated by write request to the characteristic with hex/utf-8 type.
Follow below steps to test the example:
Build and program the project to the specified board
Use Blue Gecko app to connect
Try to read and write the 2 characteristics and think why the initial value of these 2 characteristics are different, where the initial value is set?
Conclusion
When to use "user" and when to use "hex"?
Type hex/utf-8
Advantage – Stack will handle the read and write request to the characteristics
Disadvantage – User has to use BlueGecko APIs to read and write the value locally
Type user
Advantage – The buffer storing the characteristic value is in the application layer, it’s easier to read and modify the value.
Disadvantage – User must respond to the read and write requests by calling BlueGecko APIs. If user doesn’t do it, no other GATT operation can be issued until GATT timeout.
Bluetooth Knowledge Base
KBA_BT_0601: Why Doesn't My Sample Application Run?
Introduction
This article discusses changes to the Bluetooth SDK version 2.7.0.
Discussion
Starting in SDK version 2.7.x, the so-called legacy bootloader has been deprecated. This means that if you build and flash one of our sample applications you must now also build and flash a bootloader. The most reliable method is to build a bootloader for your device using the Appbuilder and flash the combined bootloader (*-combined.s37) using Simplicity Commander. This ensures that your device has both stages of the bootloader and will allow your application to run.
If your device does not have a bootloader, the symptoms you can expect include the application failing to start and the debugger showing the message "failed to read memory" in the disassembly window.
Please see UG266 for detailed information on the Gecko bootloader.
KBA_BT_1405: Migration guide to Bluetooth SDK 2.7.x
Introduction
This KBA going to highlight the main differences between SDK 2.4.x and newer SDK versions and provides a guide about moving existing projects to the SDK 2.7.0.
SDK 2.4.2 vs SDK 2.6.0
SDK 2.6.0 changed the way of hardware initialization and configuration flow. Additionally, it changed the structure of projects. Let’s go through on these changes one by one.
SDK 2.6.0 vs SDK 2.7.0
SDK 2.7.0 introduced a new OTA mechanism called Application Loader. This mechanism only works with the latest Gecko Bootloader. Additionally, the stack now provided as a library and not as a binary blob. The list below highlights the most important effects of these changes.
<project -folder>\protocol\bluetooth_2.6\lib\<MCU_family>\EABI\binstack.o
to
<project -folder>\protocol\bluetooth_2.7\lib\<MCU_family>\<compiler>\libbluetooth.a
gecko_sdk_suite\v2.1\protocol\bluetooth_2.7\lib\<MCU_family>\<compiler>\binapploader.o
The file is added to the SoC examples example by default but NCP examples do not contain that as they typically updated by UART DFU.
Porting Tips
Because these fundamental changes, migration to SDK 2.7.0 from SDK 2.4.2 or older is not a trivial task. Here we collect few tips which may make the process easier.
KBA_BT_0606: Upgrading Gecko Bootloader with Slot address change
Gecko Bootloader can be upgraded either via UART or via Bluetooth as described here:
https://www.silabs.com/community/wireless/bluetooth/knowledge-base.entry.html/2017/04/26/upgrading_gecko_boot-IfFz
The following article discusses the special case when you want to upgrade your Gecko Bootloader via Bluetooth with an image that has different slot configuration than the previous Gecko Bootloader you used on your device.
To upgrade the bootloader with a new slot configuration is problematic, because the upgrade image is uploaded by the old bootloader to the old slot address, but after the bootloader upgrade the new bootloader tries to bootload the apploader image from the new address – this will definitely fail.
The following workaround can be used to solve this issue:
Suppose you want to upgrade from bootloader A, that has Slot0 address A, to bootloader B, that has Slot0 address B.
How to configure the temporary multislot bootloader:
to
to
This will ensure, that the bootloader will try to bootload from Slot0 and then from Slot1.
7. build your project, and upgrade to this bootloader as normally, before upgrading to the final bootloader.
The final bootloader can be configured as normally, but make sure that its version number is N+2.
KBA_BT_1602: NCP Host Implementation and Example
SoC Mode vs NCP Mode
The Bluetooth SDK supports two developing modes, System-On-Chip (SoC) and Network Co-Processor (NCP). For SoC mode, all the application will run on a single EFR32 device. For NCP mode, a EFR32 device acts as the coprocessor, working together with a host controller. AN1042: Using the Silicon Labs Bluetooth® Stack in Network Co-Processor Mode has detailed description of the NCP mode. It’s recommended to read this application note before reading this article, which can give you a better understanding of NCP mode.
Figure 1. SoC Mode
Figure 2. NCP Mode
BGLib and BGAPI
When using SoC mode, it allows you to run an application right on the chipset or module and call the BGAPI directly. However, if using the NCP mode, the application runs on an external device – typically a microcontroller, everything can communicate over UART between the NCP host and NCP target.
BGLIB_DEFINE
BGLib uses a set of global variables that are defined using macro BGLIB_DEFINE(), found in gecko_bglib.h. The host application that uses BGLib must include BGLIB_DEFINE() in global scope (i.e. it must be placed outside any function implementation).
BGLIB_DEFINE() is used to declare variables used for BGLib, it must be define globally.
The symbol BGLIB_QUEUE_LEN defines the length of queue, it’s 30 by default and depends on the real use cases and allowed host memory usage.
Operation Modes
It depends on the real use case which mode should be used. If there are many tasks not related to Bluetooth, nonblocking mode should be a better choice, because it will bypass the BGLib functions if there are no Bluetooth events to be handled and allows the MCU to process other tasks. The reason BGLib supports blocking mode is for symmetry purpose that the same code should work in both SoC and NCP modes, it’s recommended to use nonblocking mode because it gives the user better control of their application in most of the use cases.
Figure 3. Blocking vs Nonblocking
Function Mapping
Below functions are used to read from and write to UART. BGLib accesses UART through function pointers so that the code is platform independent. User must map the function pointers to platform-specific UART transmit / receive routines when initializing BGLIb. This is done using macro BGLIB_INITIALIZE() or BGLIB_INITIALIZE_NONBLOCK(), depending if blocking or non-blocking mode is used.
This is the callback function to send “len1” amount of data out via UART
This is the callback function to receive “len1” amount of data via UART
This is only required if using the nonblocking mode, this function is to peek the UART if there is any data valid.
How BGLib works?
Below 3 flowcharts show how BGLib works in details.
Figure 4. Flowchart of Nonblocking function calling
Figure 5. Flowchart of blocking function calling
Figure 6. Flowchart of API calling
Adding BGLib to Host MCU Project
Preparation
Below is the step by step guide to add BGLib to a host MCU project.
Example
Contents
Attachment is an example running on EFR32PG1 kit – BRD2500 Rev A01 (NCP host) and EFR32BG13 kit – BRD4104a Rev A00 (NCP target).
UART configuration
Connection between NCP host and NCP target is shown below, see figure 5.
NCP host expansion header NCP target expansion header
GND GND
PIN 9 (PD10) – UART TX PIN 14 (PA1) – UART RX
PIN 11 (PD11) – UART RX PIN 12 (PA0) – UART TX
Figure 7. Connection between NCP host and target
Verifying the example
This example uses the nonblocking mode. You can import them to your Simplicity Studio, compile and download to your devices. The example is a very simple one, which only provides the skeleton showing the usage of both NCP host and NCP target. You can verify the example using a smartphone to scan and connect to it. It will advertise after boot or disconnected.
Memory Usage
GBGLib needs RAM for the variables defined in BGLIB_DEFINE(); as well as flash, below is the detailed RAM and flash usage of the example, the compiler is IAR with “High size” optimization.
Module ro code ro data rw data
------ ------- ------- -------
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\CMSIS\EFM32PG1B: [1]
startup_efm32pg1b.o 348
system_efm32pg1b.o 136 16 16
------------------------------------------------
Total: 484 16 16
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\emlib: [2]
em_cmu.o 756 4 4
em_gpio.o 156
em_system.o 52
em_usart.o 340
------------------------------------------------
Total: 1 304 4 4
C:\Users\zhfu\SimplicityStudio\v4_mesh_mcu\KBA_ncp_host_pg\IAR ARM - Debug\src: [3]
app.o 400 20 8 348
gecko_bglib.o 336
main.o 116
------------------------------------------------
Total: 852 20 8 348
RAM
The RAM usage for the unit gecko_cmd_packet is 0x104. For 32-bit MCU, each point occupies 4-byte. The length of the queue is 30, so it takes 0x104 * 30 = 0x1e78.
Total = 0x104 * 2 + 0x4 * 7 + 0x1e78 = 0x209c = 8348 bytes
Flash
The total flash of the example is 484+1304+852= 2640 bytes. They can be split by functionalities.
[Deprecated] KBA_BT_1506: How to find the Bluetooth 5 feature status of a listed device such as a smartphone
Note: This KBA has been marked as deprecated. A more updated KBA can be found here:
Finding the Bluetooth features of smartphoneses
There are many new features introduced in Bluetooth 5.0 specification, including 2M PHY, LE coded PHY etc., but they are probably not supported by the devices which were already in the market before Bluetooth 5.0 specification was released. It becomes more important to know which features are supported by specified devices when designing peripherals connecting to them. Here is a description how to get such information from the Bluetooth SIG website.
Below is an example to get the listing information of Samsung Galaxy S8+, the model name is SM-G9550. You can search for any other listed devices following the steps below.
https://launchstudio.bluetooth.com/listings/search
Besides of LE 2M PHY and LE Coded PHY, you can easily find other Bluetooth features on this page and see if they are supported or not.
BLE主设备以及GATT客户端例程(连接安卓手机)
简介
这篇文章是针对只拥有一块开发板同时想实现BLE主设备的人群。如果你有两块或以上的开发板,你可以参考SPP-over-BLE例程,其实现了主从设备两个角色,下面是链接:
如果你只有一块WSTK,你可以使用智能手机作为BLE从设备,然后在WSTK端实现主设备以及GATT客户端相关功能。
典型的连接过程以及连接后GATT相关操作如下:
如上步骤和操作是连接以及连接后的典型动作,但并非所有都是必须的。
如何使用这个例程
你需要如下设备
我加入了一个叫做“Demo service”的服务到GATT服务器,其包含了2个特征值,分别叫“NOTIFY_CHAR”和“RW_CHAR”,具体信息如下:
UUID 属性
Demo Service df6a8b89-32d1-486d-943a-1a1f6b0b52ed
NOTIFY_CHAR 0ced7930-b31f-457d-a6a2-b3db9b03e39a 通知
RW_CAHR fb958909-f26e-43a9-927c-7e17d8fb2d8d 读、写
我将源代码附在了文件末尾,其基于BRD4104A Rev A00(EFR32BG12 radio board)和Bluetooth SDK 2.7.0开发的,同时安卓的APP安装文件也附上了。遵循如下步骤来让例程跑起来。
下面是手机以及串口工具的截图:
图1. 串口打印信息
图2. 手机app截屏
安卓APP
我的专长并不是安卓开发,所以写这个app仅仅是为了配合WSTK主设备例程来进行演示。我并没有花很多时间来测试这个app的稳定性以及兼容性等,如果你有任何APP相关疑问,你需要找安卓开发工程师来寻求帮助。
测试过的设备:
型号 安卓版本
三星 Galaxy Tab S3 7.0
魅族 MX_4 5.1
一个已知的问题:
· CCC descriptor – CCC descriptor has the UUID 0x2902, but Android doesn’t support 16-bit UUID, so it needs to be change to 128-bit UUID - 00002902-0000-1000-8000-00805f9b34fb. The API gecko_cmd_gatt_set_characteristic_notification will return error that it can’t find CCC descriptor with UUID 0x2902 in the characteristic. So, I write the next handle of NOTIFY_CHAR which is the location of CCC descriptor of this characteristic on the server side as workaround. This problem didn’t happen when I tested with Android 7.0 devices.
安卓APP的源代码可以在这里下载 - https://github.com/fuzhen011/Android-Peripheral
KBA_BT_0913: BLE Central and GATT client example - working with an Android app
Introduction
Key points of the article:
This article is for people who only have one Wireless Starter Kit (WSTK) and want to implement central role on it. If you have more than one WSTK and want to connect them, you could probably go through the SPP-over-BLE example which implements both the central and peripheral roles.
In case you only have one WSTK, we could use the smartphone as the peripheral and GATT server, then implement the central role and GATT client on the WSTK.
The typical work flow of the central device is shown as below:
This is the typical behaviors central device does while connecting to a peripheral, but NOT all the processes are mandatory.
Features
To run this example, you need to have below devices.
GATT Server
A so-called “Demo service” is added to the server, and this service contains 2 characteristics “NOTIFY_CHAR” and “RW_CAHR”, this is done on the smartphone side.
Communication
This example demonstrates to use an EFR32 based board as a client and a smartphone as a server and send data back and forth between them. Below is a brief lists of features:
State Machine
There are 2 versions of the example code provided in the attachment, one is with a finite state machine implementation which gives more flexibility and expansibility, the other one is not, which is the lightest weight of the central role and GATT client implementation.
Import the example
To run this example, you will need to download Simplicity Studio and the attachment which includes 6 files, app.c, app.h, app_nofsm.c, fsm.c, fsm.h and the server.apk. Below is a brief guide on how to import them to your project.
Run the example
After you have successfully import the example and done all the above steps, you can try below steps to verify the functionalities.
Below are screenshots of the serial terminal and smartphone.
Figure 1. Terminal Output
Below is a brief description of the time point and the behaviors.
Figure 2. Smartphone App View
[Deprecated] KBA_BT_1106: OOB introduction and example
Note: This KBA has been marked as deprecated. A more updated KBA can be found here:
OOB example
Introduction of OOB
Below is the description of Out of Band from BLUETOOTH SPECIFICATION Version 5.0 | Vol 1, Part A, 5.2.4.3
Environments
Purpose of the example
There are 2 OOB pairing modes, one is OOB with legacy pairing and the other is OOB with secure connection pairing. This example implements both modes for user’s reference.
There are 2 projects in the example, implementing the central and peripheral rolls.
Central
Peripheral
Due to the different property of these two characteristics, if the pairing and bonding procedure succeeds, the client will receive notifications and the server will receive write requests. Otherwise if pairing and bonding procedure fails, the client should not be able to write the characteristic value due to unauthenticated connection, but it should be able to receive notifications because it doesn’t require authentication.
Key points of the example
In both projects, there is a symbol definition - PAIRING_MODE, it can either be LEGACY_PAIRING or SECURE_CONNECTION_PAIRING. This symbol determines which pairing mode will be used in the connection.
Test the example
As shown above, the example requires 2 devices (BRD4104a Rev A00) and serial terminal, VCOM has been enabled in the example, so the serial print information will go out from the USB cable.
Central device (#D1) – the device programmed with the project “KBA_oob_central”.
Peripheral device (#D2) - the device programmed with the project “KBA_oob_peripheral”.
Serial terminal (#S1) connected to central device.
Serial terminal (#S2) connected to peripheral device.
Test process
Figure 1. OOB with legacy pairing succeed
Figure 2. OOB with legacy pairing failed
Figure 3. OOB with Secure Connection pairing succeed
Figure 4. OOB with Secure Connection pairing failed
[Deprecated] KBA_BT_0304: Different characteristic value types
Note: This KBA has been marked as deprecated. A more updated KBA and example can be found here:
Different Value Types of Characteristics
Different Value Types of Characteristics Example
This article is about the differences among the types of a characteristic value. In the profile toolkit, there are 3 types of value can be used, hex, utf-8 and user. You can find detailed description in UG118, chapter 2.5.3.
Values:
hex: Value type is hex
utf-8: Value is a string
user: When the characteristic type is marked as type="user" the application is responsible of initializing the characteristic value and also providing it for example when read operation occurs. The Bluetooth stack does not initialize the value, nor automatically provide the value when it's being read. When this is set the Bluetooth stack generates gatt_server_user_read_request or gatt_server_user_write_request which must be handled by the application.
Default: utf-8
Introduction
The idea of this article is to give both examples of type "user" and "hex" to help users choosing the right property of a characteristic value.
The most significant difference between the type “user” and the other two types is where the data is stored.
If you use "user" as the data type, the value of the characteristic is stored in the application layer. And you need to respond to write/read requests by sending write/read response back via API gecko_cmd_gatt_server_send_user_read_response(…) and gecko_cmd_gatt_server_send_user_write_response(…).
For example, there is a characteristic with length 20, you need to allocate a 20-byte buffer in the application layer to store its value.
If you use the property other than "user", the stack will allocate and manage the buffer for the characteristic value automatically.
2 Notes:
Example
IDE – Simplicity Studio 4
Software - Bluetooth SDK v2.7.0 or newer
Hardware – Bluetooth Compatiable Boards
Note: DO NOT FORGET TO CLICK “GENERATE” BUTTON AFTER YOU MODIFY THE FILE.
Test the example
The example code shows where to handle the read and write requests to the characteristic with user type, as well as the event generated by write request to the characteristic with hex/utf-8 type.
Follow below steps to test the example:
Conclusion
When to use "user" and when to use "hex"?
低功耗蓝牙安全性 - Simplicity Studio例程
这篇文章的英文原版可以从下面链接找到,因为其比较有用,所以我把它翻译成中文来方便中国客户阅读。感谢原作者Balazs Adamffy.
https://www.silabs.com/community/wireless/bluetooth/knowledge-base.entry.html/2016/06/13/bluetooth_smart_secu-BpM6
简介
这篇文章将会介绍在Simplicity Studio 4以及Bluetooth SDK v2.7.0下, 如何使用低功耗蓝牙(BLE)的安全相关特性,其包括配对、绑定、加密和授权。
首先,我们给出一些关于BLE安全性的一些基础信息,然后突出介绍附件的例程里的重要的代码片段。示例程序实现了一个加密传输,其特征值只能在配对和绑定完成才能被读出。
软硬件信息:
Bluetooth SDK版本 – 2.7.0
开发板 – EFR32BG13开发板,brd4104a Rev A00
BLE安全性特征
最常见的无线通讯的威胁如下:
BLE定义了5种安全特性来对抗上述威胁:
上述特征实现在BLE协议栈的不同层,参下图:
配对&绑定
配对
BLE使用Secure Simple Pairing(SSP)配对模型:
绑定
隐私
注意:随机地址尚未在Blue Gecko的协议中实现。
加密
注意:广播数据不支持加密
蓝牙4.2新加入的安全特性
示例程序
此示例程序的软硬件基础在上面已经提到,同时只需要做很少的改动,它便可以用于其他开发板,如BGM111/BGM113等。
示例程序实现了一个服务及一个特征值,其被另外设备读的前提是双方配对并绑定, 以下是完成这一任务的具体步骤:
1. 建立SoC-Empty工程,并指定其工程名称选择编译器(GCC或IAR)
2. 打开工程中的.isc文件,加入一个服务和一个特征值
Security的服务和一个叫My Secret的特征值。 因为authenticated_read属性被设为“true”,所以其只有在加密连接中才能被读出。
注意:不要忘记修改完之后,点击右上角的“Generate”按钮。
3. 使能VCOM获得串口打印
完成如上修改后,即可使用printf()函数来获得串口打印数据了。
4. 配置、使能配对和绑定
flag参数的bit 0:
flag参数的bit 1:
flag参数的bit 2:
flag参数的bit 3:
flag的4 - 7位保留,应设为0
capabilities 参数指示设备支持的输入输出类型,不同的capabilities 参数会导致不同的配对方法。
系统启动后,调用函数gecko_cmd_sm_configure
当使用sm_io_capability_displayonly或sm_io_capability_displayyesno作为io capabilities时,PIN码会显示在UART控制台,你需要在手机或平板端输入这个PIN码。
当使用sm_io_capability_keyboardonly或sm_io_capability_keyboarddisplay作为io capabilities时,PIN码会显示在手机或平板端,你需要在设备的UART控制台输入这个PIN码。
不要使用sm_io_capability_noinputnooutput,因为MITM保护不能在此模式下工作,配对和绑定将会失败。
5. 加入配对绑定相关的事件处理
代码如下
测试此例程
下载Blue Gecko app:
iOS用户可以通过App Store,安卓用户可以通过Google Play获得。同时可以通过Silicon Labs的官方网站获得。安卓用户点击此处,iOS用户点击此处。
完成如下步骤:
7.如果一切正常,你可以通过APP读取GATT的特征值,并在串口终端得到Bonding completed信息。删除手机端绑定再次 连接可以进行重复测试