mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-01-03 23:47:08 +00:00
167 lines
6.5 KiB
Markdown
167 lines
6.5 KiB
Markdown
In this section, we highlight the BTstack components that need to be
|
||
adjusted for different hardware platforms.
|
||
|
||
|
||
## Time Abstraction Layer {#sec:timeAbstractionPorting}
|
||
|
||
BTstack requires a way to learn about passing time.
|
||
*btstack_run_loop_embedded.c* supports two different modes: system ticks or a
|
||
system clock with millisecond resolution. BTstack’s timing requirements
|
||
are quite low as only Bluetooth timeouts in the second range need to be
|
||
handled.
|
||
|
||
|
||
### Tick Hardware Abstraction {#sec:tickAbstractionPorting}
|
||
|
||
|
||
If your platform doesn’t require a system clock or if you already have a
|
||
system tick (as it is the default with CMSIS on ARM Cortex devices), you
|
||
can use that to implement BTstack’s time abstraction 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 functions *hal_tick_init* and
|
||
*hal_tick_set_handler*, 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 expects that the
|
||
*tick_handler* gets called every
|
||
*hal_tick_get_tick_period_in_ms()* ms.
|
||
|
||
|
||
### Time MS Hardware Abstraction {#sec:timeMSAbstractionPorting}
|
||
|
||
|
||
If your platform already has a system clock or it is more convenient to
|
||
provide such a clock, you can use the 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 run loop and when setting a timer for the
|
||
future. It has to return the time in milliseconds.
|
||
|
||
uint32_t hal_time_ms(void);
|
||
|
||
|
||
## Bluetooth Hardware Control API {#sec:btHWControlPorting}
|
||
|
||
|
||
The Bluetooth hardware control API can provide the HCI layer with a
|
||
custom initialization script, a vendor-specific baud rate change
|
||
command, and system power notifications. It is also used to control the
|
||
power mode of the Bluetooth module, i.e., turning it on/off and putting
|
||
to sleep. In addition, it provides an error handler *hw_error* that is
|
||
called when a Hardware Error is reported by the Bluetooth module. The
|
||
callback allows for persistent logging or signaling of this failure.
|
||
|
||
Overall, the struct *btstack_control_t* encapsulates common functionality
|
||
that is not covered by the Bluetooth specification. As an example, the
|
||
*btstack_chipset_cc256x_in-stance* function returns a pointer to a control
|
||
struct suitable for the CC256x chipset.
|
||
|
||
|
||
|
||
## HCI Transport Implementation {#sec:hciTransportPorting}
|
||
|
||
|
||
On embedded systems, a Bluetooth module can be connected via USB or an
|
||
UART port. BTstack implements two UART based protocols for carrying HCI
|
||
commands, events and data between a host and a Bluetooth module: HCI
|
||
UART Transport Layer (H4) and H4 with eHCILL support, a lightweight
|
||
low-power variant by Texas Instruments.
|
||
|
||
|
||
### HCI UART Transport Layer (H4) {#sec:hciUARTPorting}
|
||
|
||
|
||
Most embedded UART interfaces operate on the byte level and generate a
|
||
processor interrupt when a byte was received. In the interrupt handler,
|
||
common UART drivers then place the received data in a ring buffer and
|
||
set a flag for further processing or notify the higher-level code, i.e.,
|
||
in our case the Bluetooth stack.
|
||
|
||
Bluetooth communication is packet-based and a single packet may contain
|
||
up to 1021 bytes. Calling a data received handler of the Bluetooth stack
|
||
for every byte creates an unnecessary overhead. To avoid that, a
|
||
Bluetooth packet can be read as multiple blocks where the amount of
|
||
bytes to read is known in advance. Even better would be the use of
|
||
on-chip DMA modules for these block reads, if available.
|
||
|
||
The BTstack UART Hardware Abstraction Layer API reflects this design
|
||
approach and the underlying UART driver has to implement the following
|
||
API:
|
||
|
||
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 implementations for embedded system is
|
||
*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. this sequence, the HCI
|
||
layer will start packet processing by calling
|
||
*hal_uart-_dma_receive_block* function. The HAL implementation is
|
||
responsible for reading the requested amount of bytes, stopping incoming
|
||
data via the RTS line when the requested amount of data was received and
|
||
has to call the handler. By this, the HAL implementation can stay
|
||
generic, while requiring only three callbacks per HCI packet.
|
||
|
||
### H4 with eHCILL support
|
||
|
||
With the standard H4 protocol interface, it is not possible for either
|
||
the host nor the baseband controller to enter a sleep mode. Besides the
|
||
official H5 protocol, various chip vendors came up with proprietary
|
||
solutions to this. The eHCILL support by Texas Instruments allows both
|
||
the host and the baseband controller to independently enter sleep mode
|
||
without loosing their synchronization with the HCI H4 Transport Layer.
|
||
In addition to the IRQ-driven block-wise RX and TX, eHCILL requires a
|
||
callback for CTS interrupts.
|
||
|
||
void hal_uart_dma_set_cts_irq_handler(void(*cts_irq_handler)(void));
|
||
void hal_uart_dma_set_sleep(uint8_t sleep);
|
||
|
||
|
||
## Persistent Storage APIs {#sec:persistentStoragePorting}
|
||
|
||
On embedded systems there is no generic way to persist data like link
|
||
keys or remote device names, as every type of a device has its own
|
||
capabilities, particularities and limitations. The persistent storage
|
||
APIs provides an interface to implement concrete drivers for a particular
|
||
system.
|
||
|
||
### Link Key DB
|
||
|
||
As an example and for testing purposes, BTstack provides the
|
||
memory-only implementation *btstack_link_key_db_memory*. An
|
||
implementation has to conform to the interface in Listing [below](#lst:persistentDB).
|
||
|
||
~~~~ {#lst:persistentDB .c caption="{Persistent storage interface.}"}
|
||
|
||
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;
|
||
~~~~
|