Introduction
Key points of the article:
- 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.
Figure 2. Smartphone App View
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
Thanks, it helped.
-Prakash
I think you can add your filter (RSSI) in the event - gecko_evt_le_gap_scan_response_id which carries the RSSI value.
Thanks,
Kevin
The app source code is here, https://github.com/fuzhen011/Android-Peripheral.git.
Note that there is no support on this. You can use it as a reference.
Thanks,
Kevin
Hi Kevin,
Is there a requirement on the smartphone/tablet hardware? My tablet supports bluetooth 4.0, but as soon as I launch the app, it said "Unfortunately, BLE Server has stopped.". Is there anything I need to set on the tablet?
Edit: I notice that it needs to run with Android 6.0 or newer. I try it Android 8.0, and it is working now.
Thanks,
Dennis
Hi Dennis,
Yes, the sample app was set to be compatible with Android version later than 6.0. If you want to make it to work with any former versions, you need to change the source code.
Thanks,
Kevin
Hi Kevin,
Thanks for the great example. If I want to extend this example such that when there is activity on UART's RX pin, I want to write back to smartphone app gatt server database. May I confirm if the following is the necessary changes?
1. Define UART port in app.c
#define UART_PORT (gpioPortA)
#define UART_RX_PIN (1)
#define RX_PRESS_SIGNAL (1U << 2)
2. In gpio_init(), configure PA0 as input and enable interrupt
GPIO_PinModeSet(UART_PORT, UART_RX_PIN, gpioModeInputPullFilter, 1);
GPIO_IntConfig(UART_PORT, UART_RX_PIN, false, true, true);
3. In GPIO_Common_IRQHandler, use the following to set the interrupt signal bit
if (flags & (1 << UART_RX_PIN)) {
//Send interupt event to the main loop
gecko_external_signal(RX_PRESS_SIGNAL);
}
4. In appMain, add the following to gecko_evt_system_external_signal_id case
if (evt->data.evt_system_external_signal.extsignals & RX_PRESS_SIGNAL) {
LOGV("PB0 Pressed.\n");
onPb0Press();
}
Hi Dennis Wang,
Yes, I can confirm the flow is correct, but I would expect it will raise too many events in practice. As your code set up the RX pin interrupt, if there is any activity related to the RX pin, let's say the baud rate is 115200, the RX pin will change very often. I think you could change the interrupt from GPIO to UART RX, whenever UART RX is available, the interrupt be served in the ISR, in which generate the external signal.
Thanks,
Kevin
Hi Kevin,
Thanks for the help. If I understand correctly, you are suggesting to handle UART RX interrupt directly instead of GPIO interrupt so that it can handle higher baud rate, right?
May I know how to set up UART RX interrupt?
Thanks,
Dennis