BTstack implements a set of Bluetooth protocols and profiles. To connect to other Bluetooth devices or to provide a Bluetooth services, BTstack has to be properly configured.
![]()
The configuration of BTstack is done both at compile time as well as at run time:
In the following, we provide an overview of the configurationthat is necessary to setup BTstack. From the point when the run loopis executed, the application runs as a finitestate machine, which processes events received from BTstack. BTstackgroups events logically and provides them via packet handlers.We provide their overview here. For the case that there is a need to inspect the data exchangedbetween BTstack and the Bluetooth chipset, we describe how to configurepacket logging mechanism. Finally, we provide an overview on power management in Bluetooth in general and how to save energy in BTstack.
OP, If you can find how to run a bluetooth serial monitor on an iphone, I promise to. I've tried both BTStack GPS and RoqyBT with my wifi iPad and numerous. The national debt, Boxer said to applause, 'Well, the biggest one is the wars. I have both my Wiimote + GPSPhone emulator already but I read that I need to download 'BTstack' from Cydia in order to make the wiimote work. I searched in Cydia and all I see are BTstack mouse, BTstack keyboard, and BTstack GPS. None of those appear to be the plain BTstack I need to play with.
Configuration in btstack_config.h
The file btstack_config.h contains three parts:
HAVE_* directives
System properties:
Embedded platform properties:
FreeRTOS platform properties:
POSIX platform properties:
ENABLE_* directives
BTstack properties:
HCI Controller to Host Flow Control
In general, BTstack relies on flow control of the HCI transport, either via Hardware CTS/RTS flow control for UART or regular USB flow control. If this is not possible, e.g on an SoC, BTstack can use HCI Controller to Host Flow Control by defining ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL. If enabled, the HCI Transport implementation must be able to buffer the specified packets. In addition, it also need to be able to buffer a few HCI Events. Using a low number of host buffers might result in less throughput.
Host buffer configuration for HCI Controller to Host Flow Control:
Memory configuration directives
The structs for services, active connections and remote devices can beallocated in two different manners:
For each HCI connection, a buffer of size HCI_ACL_PAYLOAD_SIZE is reserved. For fast data transfer, however, a large ACL buffer of 1021 bytes is recommend. The large ACL buffer is required for 3-DH5 packets to be used.
The memory is set up by calling btstack_memory_init function:
Here's the memory configuration for a basic SPP server.
Listing: Memory configuration for a basic SPP server. {#lst:memoryConfigurationSPP}
In this example, the size of ACL packets is limited to the minimum of 52 bytes, resulting in an L2CAP MTU of 48 bytes. Only a singleHCI connection can be established at any time. On it, two L2CAP services are provided, which can be active at the same time. Here, these two can be RFCOMM and SDP. Then, memory for one RFCOMM multiplexer is reserved over which one connection can be active. Finally, up to three link keys can be cached in RAM.
Non-volatile memory (NVM) directives
If implemented, bonding information is stored in Non-volatile memory. For Classic, a single link keys and its type is stored. For LE, the bonding information contains various values (long term key, random number, EDIV, signing counter, identity, ...)Often, this implemented using Flash memory. Then, the number of stored entries are limited by:
SEGGER Real Time Transfer (RTT) directives
SEGGER RTT replaces use of an UART for debugging with higher throughput and less overhead. In addition, it allows for direct logging in PacketLogger/BlueZ format via the provided JLinkRTTLogger tool.
When enabled with
ENABLE_SEGGER_RTT and hci_dump_open was called with either HCI_DUMP_BLUEZ or HCI_DUMP_PACKETLOGGER , the following directives are used to configure the up channel:
Source tree structure
The source tree has been organized to easily setup new projects.
The core of BTstack, including all protocol and profiles, is in src/.
Support for a particular platform is provided by the platform/ subfolder. For most embedded ports, platform/embedded/ provides btstack_run_loop_embedded and the hci_transport_h4_embedded implementation that require hal_cpu.h, hal_led.h, and hal_uart_dma.h plus hal_tick.h or hal_time_ms to be implemented by the user.
To accommodate a particular Bluetooth chipset, the chipset/ subfolders provide various btstack_chipset_ implementations.Please have a look at the existing ports in port/*.
Run loop configuration
To initialize BTstack you need to initialize the memoryand the run loop respectively, then setup HCI and all needed higherlevel protocols.
BTstack uses the concept of a run loop to handle incoming data and to schedule work.The run loop handles events from two different types of sources: datasources and timers. Data sources represent communication interfaces likean UART or an USB driver. Timers are used by BTstack to implementvarious Bluetooth-related timeouts. They can also be used to handleperiodic events.
![]()
Data sources and timers are represented by the btstack_data_source_t andbtstack_timer_source_t structs respectively. Each of these structs containat least a linked list node and a pointer to a callback function. All active timersand data sources are kept in link lists. While the list of data sourcesis unsorted, the timers are sorted by expiration timeout for efficientprocessing.
Timers are single shot: a timer will be removed from the timer listbefore its event handler callback is executed. If you need a periodictimer, you can re-register the same timer source in the callbackfunction, as shown in Listing [PeriodicTimerHandler]. Note that BTstackexpects to get called periodically to keep its time, see Sectionon time abstraction for more on thetick hardware abstraction.
BTstack provides different run loop implementations that implement the btstack_run_loop_t interface:
Depending on the platform, data sources are either polled (embedded, FreeRTOS), or the platform provides a wayto wait for a data source to become ready for read or write (POSIX, CoreFoundation, Windows), or,are not used as the HCI transport driver and the run loop is implemented in a different way (WICED).In any case, the callbacks must be to explicitly enabled with the btstack_run_loop_enable_data_source_callbacks(..) function.
In your code, you'll have to configure the run loop before you start itas shown in Listing [listing:btstackInit]. The application can registerdata sources as well as timers, e.g., for periodical sampling of sensors, orfor communication over the UART.
The run loop is set up by calling btstack_run_loop_init function and providingan instance of the actual run loop. E.g. for the embedded platform, it is:
The complete Run loop API is provided here.
Run loop embedded
In the embedded run loop implementation, data sources are constantly polled andthe system is put to sleep if no IRQ happens during the poll of all data sources.
The complete run loop cycle looks like this: first, the callbackfunction of all registered data sources are called in a round robin way.Then, the callback functions of timers that are ready are executed.Finally, it will be checked if another run loop iteration has beenrequested by an interrupt handler. If not, the run loop will put the MCUinto sleep mode.
Incoming data over the UART, USB, or timer ticks will generate aninterrupt and wake up the microcontroller. In order to avoid thesituation where a data source becomes ready just before the run loopenters sleep mode, an interrupt-driven data source has to call thebtstack_run_loop_embedded_trigger function. The call tobtstack_run_loop_embedded_trigger sets aninternal flag that is checked in the critical section just beforeentering sleep mode causing another run loop cycle.
To enable the use of timers, make sure that you defined HAVE_EMBEDDED_TICK or HAVE_EMBEDDED_TIME_MS in theconfig file.
Run loop FreeRTOS
The FreeRTOS run loop is used on a dedicated FreeRTOS thread and it uses a FreeRTOS queue to schedule callbacks on the run loop.In each iteration:
To trigger the run loop, btstack_run_loop_freertos_trigger and btstack_run_loop_freertos_trigger_from_isr can be called.This causes the data sources to get polled.
Alternatively. btstack_run_loop_freertos_execute_code_on_main_thread can be used to schedule a callback on the main loop.Please note that the queue is finite (see RUN_LOOP_QUEUE_LENGTH in btstack_run_loop_embedded).
Run loop POSIX
The data sources are standard File Descriptors. In the run loop execute implementation,select() call is used to wait for file descriptors to become ready to read or write,while waiting for the next timeout.
To enable the use of timers, make sure that you defined HAVE_POSIX_TIME in the config file.
Run loop CoreFoundation (OS X/iOS)
This run loop directly maps BTstack's data source and timer source with CoreFoundation objects.It supports ready to read and write similar to the POSIX implementation. The call tobtstack_run_loop_execute() then just calls CFRunLoopRun().
To enable the use of timers, make sure that you defined HAVE_POSIX_TIME in the config file.
![]() Run loop Windows
The data sources are Event objects. In the run loop implementation WaitForMultipleObjects() callis all is used to wait for the Event object to become ready while waiting for the next timeout.
Run loop WICED
WICED SDK API does not provide asynchronous read and write to the UART and no direct way to wait forone or more peripherals to become ready. Therefore, BTstack does not provide direct support for data sources.Instead, the run loop provides a message queue that allows to schedule functions calls on its thread viabtstack_run_loop_wiced_execute_code_on_main_thread().
The HCI transport H4 implementation then uses two lightweight threads to do theblocking read and write operations. When a read or write is complete onthe helper threads, a callback to BTstack is scheduled.
HCI Transport configuration
The HCI initialization has to adapt BTstack to the used platform. The firstcall is to hci_init() and requires information about the HCI Transport to use.The arguments are:
After these are ready, HCI is initialized like this:
In addition to these, most UART-based Bluetooth chipset require somespecial logic for correct initialization that is not covered by theBluetooth specification. In particular, this covers:
This is provided by the various btstack_chipset_t implementation in the chipset/ subfolders.As an example, the bstack_chipset_cc256x_instance function returns a pointer to a chipset structsuitable for the CC256x chipset.
In some setups, the hardware setup provides explicit control of Bluetooth power and sleep modes.In this case, a btstack_control_t struct can be set with hci_set_control.
Finally, the HCI implementation requires some form of persistent storage for link keys generatedduring either legacy pairing or the Secure Simple Pairing (SSP). This commonly requires platformspecific code to access the MCU’s EEPROM of Flash storage. For thefirst steps, BTstack provides a (non) persistent store in memory.For more see here.
The higher layers only rely on BTstack and are initialized by callingthe respective *_init function. These init functions registerthemselves with the underlying layer. In addition, the application canregister packet handlers to get events and data as explained in thefollowing section.
Services
One important construct of BTstack is service. A service represents aserver side component that handles incoming connections. So far, BTstackprovides L2CAP, BNEP, and RFCOMM services. An L2CAP service handles incomingconnections for an L2CAP channel and is registered with its protocolservice multiplexer ID (PSM). Similarly, an RFCOMM service handlesincoming RFCOMM connections and is registered with the RFCOMM channelID. Outgoing connections require no special registration, they arecreated by the application when needed.
Packet handlers configuration
After the hardware and BTstack are set up, the run loop is entered. Fromnow on everything is event driven. The application calls BTstackfunctions, which in turn may send commands to the Bluetooth module. Theresulting events are delivered back to the application. Instead ofwriting a single callback handler for each possible event (as it is donein some other Bluetooth stacks), BTstack groups events logically andprovides them over a single generic interface. AppendixEvents and Errorssummarizes the parameters and eventcodes of L2CAP and RFCOMM events, as well as possible errors and thecorresponding error codes.
Here is summarized list of packet handlers that an application mightuse:
These handlers are registered with the functions listed in Tablebelow.
Table: Functions for registering packet handlers.
HCI, GAP, and general BTstack events are delivered to the packet handlerspecified by hci_add_event_handler function. In L2CAP,BTstack discriminates incoming and outgoing connections, i.e., event anddata packets are delivered to different packet handlers. Outgoingconnections are used access remote services, incoming connections areused to provide services. For incoming connections, the packet handlerspecified by l2cap_register_service is used. For outgoingconnections, the handler provided by l2cap_create_channelis used. RFCOMM and BNEP are similar.
The application can register a single shared packet handler for allprotocols and services, or use separate packet handlers for eachprotocol layer and service. A shared packet handler is often used forstack initialization and connection management.
Separate packet handlers can be used for each L2CAP service and outgoingconnection. For example, to connect with a Bluetooth HID keyboard, yourapplication could use three packet handlers: one to handle HCI eventsduring discovery of a keyboard registered byl2cap_register_packet_handler; one that will be registered to anoutgoing L2CAP channel to connect to keyboard and to receive keyboarddata registered by l2cap_create_channel; after thatkeyboard can reconnect by itself. For this, you need to register L2CAPservices for the HID Control and HID Interrupt PSMs usingl2cap_register_service. In this call, you’ll also specifya packet handler to accept and receive keyboard data.
All events names have the form MODULE_EVENT_NAME now, e.g., gap_event_-advertising_report.To facilitate working withevents and get rid of manually calculating offsets into packets, BTstack providesauto-generated getters for all fields of all events in src/hci_event.h. Allfunctions are defined as static inline, so they are not wasting any program memoryif not used. If used, the memory footprint should be identical to accessing thefield directly via offsets into the packet. For example, to access fields address_typeand address from the gap_event_advertising_report event use following getters:
Bluetooth HCI Packet Logs
If things don't work as expected, having a look at the data exchangedbetween BTstack and the Bluetooth chipset often helps.
For this, BTstack provides a configurable packet logging mechanism via hci_dump.h:
On POSIX systems, you can call hci_dump_open with a path and HCI_DUMP_BLUEZor HCI_DUMP_PACKETLOGGER in the setup, i.e., before entering the run loop.The resulting file can be analyzed with Wiresharkor the Apple's PacketLogger tool.
On embedded systems without a file system, you still can call hci_dump_open(NULL, HCI_DUMP_STDOUT).It will log all HCI packets to the console via printf.If you capture the console output, incl. your own debug messages, you can usethe create_packet_log.py tool in the tools folder to convert a text output into aPacketLogger file.
In addition to the HCI packets, you can also enable BTstack's debug information by adding
to the btstack_config.h and recompiling your application.
Bluetooth Power Control
In most BTstack examples, the device is set to be discoverable and connectable. In this mode, even when there's no active connection, the Bluetooth Controller will periodically activate its receiver in order to listen for inquiries or connecting requests from another device.The ability to be discoverable requires more energy than the ability to be connected. Being discoverable also announces the device to anybody in the area. Therefore, it is a good idea to pause listening for inquiries when not needed. Other devices that have your Bluetooth address can still connect to your device.
To enable/disable discoverability, you can call:
If you don't need to become connected from other devices for a longer period of time, you can also disable the listening to connection requests.
To enable/disable connectability, you can call:
For Bluetooth Low Energy, the radio is periodically used to broadcast advertisements that are used for both discovery and connection establishment.
To enable/disable advertisements, you can call:
If a Bluetooth Controller is neither discoverable nor connectable, it does not need to periodically turn on its radio and it only needs to respond to commands from the Host. In this case, the Bluetooth Controller is free to enter some kind of deep sleep where the power consumption is minimal.
Finally, if that's not sufficient for your application, you could request BTstack to shutdown the Bluetooth Controller. For this, the 'on' and 'off' functions in the btstack_control_t struct must be implemented. To shutdown the Bluetooth Controller, you can call:
with mode set to HCI_POWER_OFF. When needed later, Bluetooth can be started again via by calling it with mode HCI_POWER_ON, as seen in all examples.
![]() Comments are closed.
|
AuthorWrite something about yourself. No need to be fancy, just an overview. Archives
December 2022
Categories |