btstack/doc/manual/docs/porting.md
2016-04-01 16:51:17 +02:00

167 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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. BTstacks 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 doesnt 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 BTstacks 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 BTstacks 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;
~~~~