This example shows how to implement transparent serial data connection between two BGMxxx modules. Functionally the example is very close to the BGScript example that is described in following article:
There is no standard SPP service in Bluetooth Smart and therefore we need to implement this as a custom service. The service is exactly same as the one used in the BGScript example (see link above) and it can be described using the XML notation as follows:
<!-- Our custom accelerometer service is declared here --> <!-- UUID values generated with https://www.guidgenerator.com/ --> <service uuid="4880c12c-fdcb-4077-8920-a450d7f9b907" advertise="true"> <description>SPP Service</description> <characteristic uuid="fec26ec4-6d71-4442-9f81-55bc21d658d6" id="xgatt_spp_data"> <description>SPP Data</description> <properties write_no_response="true" notify="true" /> <value variable_length="true" length="20" type="hex"></value> </characteristic> </service>
The basic idea of the SPP service is explained in the BGScript article linked above and therefore it is not covered here.
The zip file attached at the end of this article includes source code for one single application that implements both the server and client roles. The role is selected dynamically at power-up using pushbuttons, details are found later in the section Running the demo.
This example has been tested with Bluetooth SDK 2.3.1 and GCC toolchain. The code should work without any changes at least with the following radio boards:
The zip file attached at the end of this article includes the source files for the C-based SPP example. It is not a complete project but a set of files that you can copy on top of a project created in Simplicity Studio. Follow these step-by-step instructions carefully:
Step 1: Create the SOC -Empty example project in Studio
After the project is created the BLE GATT Configurator is opened automatically and it shows the GATT database of the project. The project template includes a minimal GATT database that includes three services (Generic Access, Device Information and Silicon Labs OTA). Next you need to add the SPP service using the BLE GATT Configurator.
Step 2: add the SPP service
The details of the SPP service are:
Service UUID value 4880c12c-fdcb-4077-8920-a450d7f9b907
SPP data : UUID value fec26ec4-6d71-4442-9f81-55bc21d658d6
For the SPP data characteristic, define the ID as “gatt_spp_data”.
The length of the characteristic is set to 20 bytes and type is hex. variable length checkbox selected.
Add and enable following properties: write without response and notify.
The following screenshots show how the SPP service should look like in the BLE GATT Configurator.
After adding the service, save the *.isc file and press Generate button on the upper right corner of the GUI.
At this point, it is good to check that the project builds without any errors.
Step 3: add the C source files to the project
Unzip the attached zip file and add the included source files to the project.
Files can be added to the project simply by drag&drop. Studio will prompt you to either create a link to these files or create a copy. Select “copy” option. Note that the main.c that was created by Studio as part of the SOC – Empty example is overwritten.
Step 4: defined RETARGET_VCOM
Finally, in the project settings you need to define the precompiler directive RETARGET_VCOM so that the code uses the on-board USB-to-UART converter of the development kit.
Following screenshot shows how to set this in the GCC build options:
After building the project, flash the firmware to two development kits. The same application supports both SPP server and client roles. The following section explains how to select the mode.
Simplest way to run the demo is to use two similar development kits (for example two BGM121 kits). In this case you can use the same binary for both boards.
When the application boots, it checks the state of pushbuttons PB0, PB1. If buttons are not pressed the application starts in SPP server role.
By keeping either PB0 or PB1 pressed during reboot the application starts in SPP client mode.
In server mode, the device advertises the custom SPP service and waits for incoming connections.
In client mode, the device starts scanning and searches for the custom SPP UUID in the scan responses. If match is found, the client connects to the target, discovers the SPP service and characteristics and then enables notifications for the SPP_data characteristic. At this point, any data that is input in the client side is sent over the air to the server and printed on the remote UART. Similarly, any data input to the server UART is transmitted back to the client.
To connect to the kit using terminal program use the following UART settings: baud rate 115200 , 8N1, no flow control.
The example can be also tested between two different kits (e.g. BGM121 and BGM111). As the SPP service is the same that was used in the BGScript SPP example, it is also possible to connect BGScript-based SPP client to C-based SPP server, or vice versa.
Yet another option is to use BLED112 as the SPP client, see following article for more info:
USART peripheral is not accessible in EM2 sleep mode. For this reason, both the client and the server applications disable sleeping (EM2 mode) temporarily when the SPP mode is active. SPP mode in this context means that the client and server are connected and that the client has enabled notifications for the SPP_data characteristics.
When SPP mode is entered, the code calls SLEEP_SleepBlockBegin(sleepEM2) to temporarily disable sleeping. When connection is closed (or client disables notifications) then SLEEP_SleepBlockEnd(sleepEM2) is called to re-enable sleeping.
For more details on the power management details, see following article:
The sample code uses printf() for sending data to UART. For this reason, the example does not well with binary data transfer.
This example is a simple C-based SPP implementation for BGMxxx / EFR32BG products. It is not optimized for performance or low power. The code has been kept as simple as possible.
UART input/output is handled using stdio retarget functions (see following article for details:
This is not the most efficient way to handle UART input/output but the benefit is that it is portable and allows the sample code to be used easily on several radio boards without any modifications.