Bluetooth protocol stack (seven, ported to other platforms)

In this section, we will focus on the BTstack components that need to be adjusted for different hardware platforms.

Time abstraction layer

BTstack needs a way to understand the delivery time. btstack_run_loop_embedded.c supports two different modes: system mark or system clock with millisecond resolution. The timing requirements of BTstack are very low because only Bluetooth timeouts in the second range need to be handled.

Tick ​​hardware abstraction

If your platform does not require a system clock or you already have a system clock (because it is the default setting for CMSIS on ARM Cortex devices), you can use it to implement the time abstraction of BTstack in include / btstack / hal_tick.h>.

For this, you need to define HAVE_EMBEDDED_TICK in btstack_config.h:

#define HAVE_EMBEDDED_TICK

Then you need to implement the hal_tick_init and hal_tick_set_handler functions, which will be called during the initialization of the run loop.

void hal_tick_init(void);

void hal_tick_set_handler(void (*tick_handler)(void));

int hal_tick_get_tick_period_in_ms(void);

After BTstack calls hal_tick_init () and hal_tick_set_handler (tick_handler), it is expected that tick_handler is called every hal_tick_get_tick_period_in_ms () milliseconds.

Time MS hardware abstraction

If your platform already has a system clock or it is more convenient to provide such a clock, you can use Time MS Hardware Abstraction in include / btstack / hal_time_ms.h.

For this, you need to define HAVE_EMBEDDED_TIME_MS in btstack_config.h:

#define HAVE_EMBEDDED_TIME_MS

Then you need to implement the function hal_time_ms (), which will be called from BTstack's running loop and when setting a timer for the future. It must return the time in milliseconds.

uint32_t hal_time_ms(void);

Bluetooth hardware control API

The Bluetooth hardware control API can provide custom initialization scripts for the HCI layer, vendor-specific baud rate change commands and system power notifications. It is also used to control the power mode of the Bluetooth module, that is, turn on / off and enter sleep mode. In addition, it also provides an error handler hw_error, which is called when the Bluetooth module reports a hardware error. Callbacks allow persistent recording or signaling of this failure.

In general, struct btstack_control_t encapsulates common functions not covered by the Bluetooth specification. For example, the btstack_chipset_cc256x_in-stance function returns a pointer to the control structure suitable for the CC256x chipset.

Human-computer interaction implementation

On embedded systems, the Bluetooth module can be connected via the USB or UART port. BTstack implements three UART-based protocols for transmitting HCI commands, events, and data between the host and the Bluetooth module: HCI UART transmission layer (H4), H4 supporting eHCILL, and lightweight low-power variable The body, and the three-wire UART transmission layer (H5).

HCI UART transmission layer (H4)

Most embedded UART interfaces operate at the byte level and generate a processor interrupt when a byte is received. In the interrupt handler, the public UART driver then puts the received data into a ring buffer and sets a flag for further processing or notifies higher-level code, which is the Bluetooth stack in our case.

Bluetooth communication is based on data packets, and a single data packet can contain up to 1021 bytes. Calling the data reception handler of the Bluetooth stack for each byte will generate unnecessary overhead. To avoid this, the Bluetooth data packet can be read as multiple blocks, where the amount of bytes to be read is known in advance. If possible, it is better to use an on-chip DMA module for these block reads.

The BTstack UART hardware abstraction layer API reflects this design method, and the underlying UART driver must implement the following APIs:

void hal_uart_dma_init(void);

void hal_uart_dma_set_block_received(void (*block_handler)(void));

void hal_uart_dma_set_block_sent(void (*block_handler)(void));

int hal_uart_dma_set_baud(uint32_t baud);

void hal_uart_dma_send_block(const uint8_t *buffer, uint16_t len);

void hal_uart_dma_receive_block(uint8_t *buffer, uint16_t len);

The main HCI H4 implementation of the embedded system is the hci_h4_transport-_dma function. This function calls the following sequence: hal_uart_dma_init, hal_uart_dma_set_block_received and hal_uart_dma_set_block_sent functions. In this sequence, the HCI layer will initiate packet processing by calling the hal_uart-_dma_receive_block function. The HAL implementation is responsible for reading the requested number of bytes, stopping incoming data via the RTS line when receiving the requested amount of data, and must call the handler. In this way, the HAL implementation can remain universal, and each HCI packet only requires three callbacks.

H4 supports eHCILL

Using the standard H4 protocol interface, neither the host nor the baseband controller can enter sleep mode. In addition to the official H5 protocol, various chip vendors have proposed proprietary solutions. Texas Instruments' (TI) eHCILL support allows the host and baseband controller to enter sleep mode independently without losing synchronization with the HCI H4 transport layer. In addition to IRQ-driven block RX and TX, eHCILL also needs to call back the CTS interrupt.

void hal_uart_dma_set_cts_irq_handler(void(*cts_irq_handler)(void));

void hal_uart_dma_set_sleep(uint8_t sleep);

H5

H5 uses the SLIP protocol to transmit data packets, and handles data packet loss and bit errors through retransmission. Because it can recover from packet loss, either party can enter sleep mode without losing synchronization.

Using hardware flow control in H5 is optional, however, since BTstack uses hardware flow control to avoid packet buffering, it is recommended to use H5 only with RTS / CTS.

For migration, the implementation follows the conventional H4 protocol described above.

Persistent storage API

On embedded systems, there is no universal method to save data such as link keys or remote device names, because each type of device has its own functions, features, and limitations. The persistent storage API provides an interface for implementing specific drivers for specific systems.

Link key DB

As an example and for testing purposes, BTstack provides a memory-only implementation btstack_link_key_db_memory. The implementation must conform to the interfaces in the following list .

typedef struct {

// management

void (*open)();

void (*close)();

 

// link key

int (*get_link_key)(bd_addr_t bd_addr, link_key_t link_key);

void (*put_link_key)(bd_addr_t bd_addr, link_key_t key);

void (*delete_link_key)(bd_addr_t bd_addr);

} btstack_link_key_db_t;

 

 

Published 105 original articles · Like 30 · Visits 160,000+

Guess you like

Origin blog.csdn.net/happygrilclh/article/details/100743632