xref: /btstack/doc/manual/docs-template/porting.md (revision 503a627edab6ba8492c3d0cdd9ac598fe2b0f08a)
1#
2
3In this section, we highlight the BTstack components that need to be
4adjusted for different hardware platforms.
5
6
7## Time Abstraction Layer {#sec:timeAbstractionPorting}
8
9BTstack requires a way to learn about passing time.
10*btstack_run_loop_embedded.c* supports two different modes: system ticks or a
11system clock with millisecond resolution. BTstack’s timing requirements
12are quite low as only Bluetooth timeouts in the second range need to be
13handled.
14
15
16### Tick Hardware Abstraction {#sec:tickAbstractionPorting}
17
18
19If your platform doesn’t require a system clock or if you already have a
20system tick (as it is the default with CMSIS on ARM Cortex devices), you
21can use that to implement BTstack’s time abstraction in
22*include/btstack/hal_tick.h\>*.
23
24For this, you need to define *HAVE_EMBEDDED_TICK* in *btstack_config.h*:
25
26    #define HAVE_EMBEDDED_TICK
27
28Then, you need to implement the functions *hal_tick_init* and
29*hal_tick_set_handler*, which will be called during the
30initialization of the run loop.
31
32    void hal_tick_init(void);
33    void hal_tick_set_handler(void (*tick_handler)(void));
34    int  hal_tick_get_tick_period_in_ms(void);
35
36After BTstack calls *hal_tick_init()* and
37*hal_tick_set_handler(tick_handler)*, it expects that the
38*tick_handler* gets called every
39*hal_tick_get_tick_period_in_ms()* ms.
40
41
42### Time MS Hardware Abstraction {#sec:timeMSAbstractionPorting}
43
44
45If your platform already has a system clock or it is more convenient to
46provide such a clock, you can use the Time MS Hardware Abstraction in
47*include/btstack/hal_time_ms.h*.
48
49For this, you need to define *HAVE_EMBEDDED_TIME_MS* in *btstack_config.h*:
50
51    #define HAVE_EMBEDDED_TIME_MS
52
53Then, you need to implement the function *hal_time_ms()*, which will
54be called from BTstack’s run loop and when setting a timer for the
55future. It has to return the time in milliseconds.
56
57    uint32_t hal_time_ms(void);
58
59
60## Bluetooth Hardware Control API {#sec:btHWControlPorting}
61
62
63The Bluetooth hardware control API can provide the HCI layer with a
64custom initialization script, a vendor-specific baud rate change
65command, and system power notifications. It is also used to control the
66power mode of the Bluetooth module, i.e., turning it on/off and putting
67to sleep. In addition, it provides an error handler *hw_error* that is
68called when a Hardware Error is reported by the Bluetooth module. The
69callback allows for persistent logging or signaling of this failure.
70
71Overall, the struct *btstack_control_t* encapsulates common functionality
72that is not covered by the Bluetooth specification. As an example, the
73*btstack_chipset_cc256x_in-stance* function returns a pointer to a control
74struct suitable for the CC256x chipset.
75
76
77
78## HCI Transport Implementation {#sec:hciTransportPorting}
79
80
81On embedded systems, a Bluetooth module can be connected via USB or an
82UART port. BTstack implements three UART based protocols for carrying HCI
83commands, events and data between a host and a Bluetooth module: HCI
84UART Transport Layer (H4), H4 with eHCILL support, a lightweight
85low-power variant by Texas Instruments, and the Three-Wire UART Transport Layer (H5).
86
87
88### HCI UART Transport Layer (H4) {#sec:hciUARTPorting}
89
90
91Most embedded UART interfaces operate on the byte level and generate a
92processor interrupt when a byte was received. In the interrupt handler,
93common UART drivers then place the received data in a ring buffer and
94set a flag for further processing or notify the higher-level code, i.e.,
95in our case the Bluetooth stack.
96
97Bluetooth communication is packet-based and a single packet may contain
98up to 1021 bytes. Calling a data received handler of the Bluetooth stack
99for every byte creates an unnecessary overhead. To avoid that, a
100Bluetooth packet can be read as multiple blocks where the amount of
101bytes to read is known in advance. Even better would be the use of
102on-chip DMA modules for these block reads, if available.
103
104The BTstack UART Hardware Abstraction Layer API reflects this design
105approach and the underlying UART driver has to implement the following
106API:
107
108    void hal_uart_dma_init(void);
109    void hal_uart_dma_set_block_received(void (*block_handler)(void));
110    void hal_uart_dma_set_block_sent(void (*block_handler)(void));
111    int  hal_uart_dma_set_baud(uint32_t baud);
112    void hal_uart_dma_send_block(const uint8_t *buffer, uint16_t len);
113    void hal_uart_dma_receive_block(uint8_t *buffer, uint16_t len);
114
115
116The main HCI H4 implementations for embedded system is
117*hci_h4_transport-_dma* function. This function calls the following
118sequence: *hal_uart_dma_init*, *hal_uart_dma_set_block_received*
119and *hal_uart_dma_set_block_sent* functions. this sequence, the HCI
120layer will start packet processing by calling
121*hal_uart-_dma_receive_block* function. The HAL implementation is
122responsible for reading the requested amount of bytes, stopping incoming
123data via the RTS line when the requested amount of data was received and
124has to call the handler. By this, the HAL implementation can stay
125generic, while requiring only three callbacks per HCI packet.
126
127### H4 with eHCILL support
128
129With the standard H4 protocol interface, it is not possible for either
130the host nor the baseband controller to enter a sleep mode. Besides the
131official H5 protocol, various chip vendors came up with proprietary
132solutions to this. The eHCILL support by Texas Instruments allows both
133the host and the baseband controller to independently enter sleep mode
134without loosing their synchronization with the HCI H4 Transport Layer.
135In addition to the IRQ-driven block-wise RX and TX, eHCILL requires a
136callback for CTS interrupts.
137
138    void hal_uart_dma_set_cts_irq_handler(void(*cts_irq_handler)(void));
139    void hal_uart_dma_set_sleep(uint8_t sleep);
140
141
142### H5
143
144H5, makes use of the SLIP protocol to transmit a packet and can deal
145with packet loss and bit-errors by retransmission. Since it can recover
146from packet loss, it's also possible for either side to enter sleep
147mode without loosing synchronization.
148
149The use of hardware flow control in H5 is optional, however, since
150BTstack uses hardware flow control to avoid packet buffers, it's
151recommended to only use H5 with RTS/CTS as well.
152
153For porting, the implementation follows the regular H4 protocol described above.
154
155## Persistent Storage APIs {#sec:persistentStoragePorting}
156
157On embedded systems there is no generic way to persist data like link
158keys or remote device names, as every type of a device has its own
159capabilities, particularities and limitations. The persistent storage
160APIs provides an interface to implement concrete drivers for a particular
161system.
162
163### Link Key DB
164
165As an example and for testing purposes, BTstack provides the
166memory-only implementation *btstack_link_key_db_memory*. An
167implementation has to conform to the interface in Listing [below](#lst:persistentDB).
168
169~~~~ {#lst:persistentDB .c caption="{Persistent storage interface.}"}
170
171    typedef struct {
172        // management
173        void (*open)();
174        void (*close)();
175
176        // link key
177        int  (*get_link_key)(bd_addr_t bd_addr, link_key_t link_key);
178        void (*put_link_key)(bd_addr_t bd_addr, link_key_t key);
179        void (*delete_link_key)(bd_addr_t bd_addr);
180    } btstack_link_key_db_t;
181~~~~
182