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