BLE Hands on Getting Started Basic Structure of a Bluetooth Application - joe-possum/IoT-Developer-Boot-Camp GitHub Wiki
In this exercise we examine the general structure of a Bluetooth application and introduce the debugger.
Returning to the Simplicity IDE perspective, locate the file "app.c" (1) in the Project Explorer. Double click on "app.c", this will open the file in the editor. Scrolling down, locate the "app_init()" (2) function. This function is called once after system initilaization of the device is complete.
The next function of interest is "app-process_action() (3)." This function is called each time the device is awake. A simple application will generally be driven by events, but in situations where, for example, you may want to send large amounts of data using notifications, this would be useful. (general method would be to attempt to send notifications until the stack indicates no more memory is available. This is due to the queue of pending messages getting filled. After returning from this function the device can sleep until the next connection event. When the next connection event occurs, many of the notificatons can be sent freeing space allowing more notification to be queued.)
Since "app_init()" is an interesting location, we can add a break point here. Right click on the line number to the left of the "app_log_info()" call and select "Toggle Breakpoint" from the context menu.
The breakpoint will be indicated by a blue filled circle to the left of the line number. This does not modify the firmware in anyway, just shares information with the debugger.
The function "sl_bt_on_event()" (4) is called each time the stack needs pass an event to the application. The first event delivered is the system-boot event, indicating that the stack is ready to receive commands. We can set a breakpoint to capture this event, again right clicking on the line number to the left of the "app_log_info()" call (line 108 shown below).
A quick walk through of the event handling in this example. Three events are explicitly handled in the switch statement (the links lead to documentation, recooment opening in a new tab):
- sl_bt_evt_system_boot
- sl_bt_evt_connection_opened - called when a connection is established.
- sl_bt_evt_connection_closed - called when a connection is closed for any reason. There are other events which are handled by the Health Thermometer module. This module interacts with the callback functions later in app.c.
The handler for the system-boot event sets the device system ID based upon the device's mac address, creates an advertising set and begins advertising.
Other than logging, the connection-opened handler does not do anything. It is not required to halt advertising, an advertisement is terminated by connection.
The connection-closed event restarts advertising.
Bluetooth - SoC Thermometer sends logs to the USART connected to VCOM. We can observe the logs by connecting a terminal emulator to the omp port / device reported in the Using Commander exercise. In this case I am using Tera Term. After resetting the device using the button, I see
We can run the application under the control of the debugger. The default behavior is for the application to be rebuilt before entering the debugger. While this does guarantee the source files match the firmware image, that can be workflows where this is inconvenient, I will note how to skip the build step in the notes at the end of this exercise. To debug the application, select the SoC Themometer project root and click on the debug icon (5).
After building the firmware, if the SE firmware ion the device does not match the SDK, you may get a dialog pop up warning about this. At this stage it is not critical, so you can click "Yes".
The firmware is flashed to the device and the debugged will halt execution at the first statement in "main()". Here we can see how "app_init()" and "app_process_action()" are called. Events generated would be dispatched from behind "sl_system_process_action()". We can resume execution by clicking the resume icon (6).
As expected execution should halt at "app_init()."
Resuming once again, we should break in the system-boot handler.
Since sl_bt_on_event is passed a pointer to the event data, it would be interesting to examine the event. In the panel at the right, the Variable tab will list local variables. Expand evt and evt->data and evt->data.evt-system_boot.
We can also try placing a breakpoint to examine the event data passed when a connection is opened. Scroll down to the connection-opened case and place a breakpoint by right-clicking the line number to the left of "app_log_info(). (line 167 below)"
Resume execution. The application should run uninterrupted until a connection is made. Use EFR Connect as before. When the device is connected the breakpoint should activate. Note the behavior of EFR Connect. Since execution is suspended, Bluetooth connections can not be sustained. This is on of the challenges of debugging Bluetooth applications.
While the connection no longer exists, we can still examine the event data. Expanding evt->data.evt_connection_opened we can see the mac address and other info about the potential connection