xref: /btstack/src/hci_transport_h5.c (revision bd021c4e5b90cc8265c01b99957b7e253b9e8e9d)
1*bd021c4eSMatthias Ringwald /*
2*bd021c4eSMatthias Ringwald  * Copyright (C) 2016 BlueKitchen GmbH
3*bd021c4eSMatthias Ringwald  *
4*bd021c4eSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*bd021c4eSMatthias Ringwald  * modification, are permitted provided that the following conditions
6*bd021c4eSMatthias Ringwald  * are met:
7*bd021c4eSMatthias Ringwald  *
8*bd021c4eSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*bd021c4eSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*bd021c4eSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*bd021c4eSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*bd021c4eSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*bd021c4eSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*bd021c4eSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*bd021c4eSMatthias Ringwald  *    from this software without specific prior written permission.
16*bd021c4eSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*bd021c4eSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*bd021c4eSMatthias Ringwald  *    monetary gain.
19*bd021c4eSMatthias Ringwald  *
20*bd021c4eSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*bd021c4eSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*bd021c4eSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*bd021c4eSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*bd021c4eSMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*bd021c4eSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*bd021c4eSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*bd021c4eSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*bd021c4eSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*bd021c4eSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*bd021c4eSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*bd021c4eSMatthias Ringwald  * SUCH DAMAGE.
32*bd021c4eSMatthias Ringwald  *
33*bd021c4eSMatthias Ringwald  * Please inquire about commercial licensing options at
34*bd021c4eSMatthias Ringwald  * [email protected]
35*bd021c4eSMatthias Ringwald  *
36*bd021c4eSMatthias Ringwald  */
37*bd021c4eSMatthias Ringwald 
38*bd021c4eSMatthias Ringwald /*
39*bd021c4eSMatthias Ringwald  *  hci_transport_h5.c
40*bd021c4eSMatthias Ringwald  *
41*bd021c4eSMatthias Ringwald  *  HCI Transport API implementation for basic H5 protocol
42*bd021c4eSMatthias Ringwald  *
43*bd021c4eSMatthias Ringwald  *  Created by Matthias Ringwald on 4/29/09.
44*bd021c4eSMatthias Ringwald  */
45*bd021c4eSMatthias Ringwald 
46*bd021c4eSMatthias Ringwald #include "hci.h"
47*bd021c4eSMatthias Ringwald #include "btstack_slip.h"
48*bd021c4eSMatthias Ringwald #include "btstack_debug.h"
49*bd021c4eSMatthias Ringwald #include "hci_transport.h"
50*bd021c4eSMatthias Ringwald #include "btstack_uart_block.h"
51*bd021c4eSMatthias Ringwald 
52*bd021c4eSMatthias Ringwald #ifdef HAVE_EHCILL
53*bd021c4eSMatthias Ringwald #error "HCI Transport H5 does not support eHCILL. Please either use (H4 + HAVE_EHCILL) or H5 Transport"
54*bd021c4eSMatthias Ringwald #endif
55*bd021c4eSMatthias Ringwald 
56*bd021c4eSMatthias Ringwald /// newer
57*bd021c4eSMatthias Ringwald 
58*bd021c4eSMatthias Ringwald typedef enum {
59*bd021c4eSMatthias Ringwald     LINK_UNINITIALIZED,
60*bd021c4eSMatthias Ringwald     LINK_INITIALIZED,
61*bd021c4eSMatthias Ringwald     LINK_ACTIVE
62*bd021c4eSMatthias Ringwald } hci_transport_link_state_t;
63*bd021c4eSMatthias Ringwald 
64*bd021c4eSMatthias Ringwald typedef enum {
65*bd021c4eSMatthias Ringwald     HCI_TRANSPORT_LINK_SEND_SYNC            = 1 << 0,
66*bd021c4eSMatthias Ringwald     HCI_TRANSPORT_LINK_SEND_SYNC_RESPONSE   = 1 << 1,
67*bd021c4eSMatthias Ringwald     HCI_TRANSPORT_LINK_SEND_CONFIG          = 1 << 2,
68*bd021c4eSMatthias Ringwald     HCI_TRANSPORT_LINK_SEND_CONFIG_RESPONSE = 1 << 3,
69*bd021c4eSMatthias Ringwald     HCI_TRANSPORT_LINK_SEND_WOKEN           = 1 << 4,
70*bd021c4eSMatthias Ringwald     HCI_TRANSPORT_LINK_SEND_WAKEUP          = 1 << 5,
71*bd021c4eSMatthias Ringwald     HCI_TRANSPORT_LINK_SEND_QUEUED_PACKET   = 1 << 6,
72*bd021c4eSMatthias Ringwald     HCI_TRANSPORT_LINK_SEND_ACK_PACKET      = 1 << 7,
73*bd021c4eSMatthias Ringwald } hci_transport_link_actions_t;
74*bd021c4eSMatthias Ringwald 
75*bd021c4eSMatthias Ringwald // Configuration Field. No packet buffers -> sliding window = 1, no OOF flow control, no data integrity check
76*bd021c4eSMatthias Ringwald #define LINK_CONFIG_SLIDING_WINDOW_SIZE 1
77*bd021c4eSMatthias Ringwald #define LINK_CONFIG_OOF_FLOW_CONTROL 0
78*bd021c4eSMatthias Ringwald #define LINK_CONFIG_DATA_INTEGRITY_CHECK 0
79*bd021c4eSMatthias Ringwald #define LINK_CONFIG_VERSION_NR 0
80*bd021c4eSMatthias Ringwald #define LINK_CONFIG_FIELD (LINK_CONFIG_SLIDING_WINDOW_SIZE | (LINK_CONFIG_OOF_FLOW_CONTROL << 3) | (LINK_CONFIG_DATA_INTEGRITY_CHECK << 4) | (LINK_CONFIG_VERSION_NR << 5))
81*bd021c4eSMatthias Ringwald 
82*bd021c4eSMatthias Ringwald // periodic sending during link establishment
83*bd021c4eSMatthias Ringwald #define LINK_PERIOD_MS 250
84*bd021c4eSMatthias Ringwald 
85*bd021c4eSMatthias Ringwald // resend wakeup
86*bd021c4eSMatthias Ringwald #define LINK_WAKEUP_MS 50
87*bd021c4eSMatthias Ringwald 
88*bd021c4eSMatthias Ringwald // additional packet types
89*bd021c4eSMatthias Ringwald #define LINK_ACKNOWLEDGEMENT_TYPE 0x00
90*bd021c4eSMatthias Ringwald #define LINK_CONTROL_PACKET_TYPE 0x0f
91*bd021c4eSMatthias Ringwald 
92*bd021c4eSMatthias Ringwald // ---
93*bd021c4eSMatthias Ringwald static const uint8_t link_control_sync[] =   { 0x01, 0x7e};
94*bd021c4eSMatthias Ringwald static const uint8_t link_control_sync_response[] = { 0x02, 0x7d};
95*bd021c4eSMatthias Ringwald static const uint8_t link_control_config[] = { 0x03, 0xfc, LINK_CONFIG_FIELD};
96*bd021c4eSMatthias Ringwald static const uint8_t link_control_config_response[] = { 0x04, 0x7b, LINK_CONFIG_FIELD};
97*bd021c4eSMatthias Ringwald static const uint8_t link_control_config_response_prefix_len  = 2;
98*bd021c4eSMatthias Ringwald static const uint8_t link_control_wakeup[] = { 0x05, 0xfa};
99*bd021c4eSMatthias Ringwald static const uint8_t link_control_woken[] =  { 0x06, 0xf9};
100*bd021c4eSMatthias Ringwald static const uint8_t link_control_sleep[] =  { 0x07, 0x78};
101*bd021c4eSMatthias Ringwald 
102*bd021c4eSMatthias Ringwald // incoming pre-bufffer + 4 bytes H5 header + max(acl header + acl payload, event header + event data) + 2 bytes opt CRC
103*bd021c4eSMatthias Ringwald static uint8_t   hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + 6 + HCI_PACKET_BUFFER_SIZE];
104*bd021c4eSMatthias Ringwald 
105*bd021c4eSMatthias Ringwald // Non-optimized outgoing buffer (EOF, 4 bytes header, payload, EOF)
106*bd021c4eSMatthias Ringwald static uint8_t slip_outgoing_buffer[2 + 2 * (HCI_PACKET_BUFFER_SIZE + 4)];
107*bd021c4eSMatthias Ringwald 
108*bd021c4eSMatthias Ringwald // H5 Link State
109*bd021c4eSMatthias Ringwald static hci_transport_link_state_t link_state;
110*bd021c4eSMatthias Ringwald static btstack_timer_source_t link_timer;
111*bd021c4eSMatthias Ringwald static uint8_t  link_seq_nr;
112*bd021c4eSMatthias Ringwald static uint8_t  link_ack_nr;
113*bd021c4eSMatthias Ringwald static uint16_t link_resend_timeout_ms;
114*bd021c4eSMatthias Ringwald static uint8_t  link_peer_asleep;
115*bd021c4eSMatthias Ringwald 
116*bd021c4eSMatthias Ringwald // Outgoing packet
117*bd021c4eSMatthias Ringwald static uint8_t   hci_packet_type;
118*bd021c4eSMatthias Ringwald static uint16_t  hci_packet_size;
119*bd021c4eSMatthias Ringwald static uint8_t * hci_packet;
120*bd021c4eSMatthias Ringwald 
121*bd021c4eSMatthias Ringwald // hci packet handler
122*bd021c4eSMatthias Ringwald static  void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size);
123*bd021c4eSMatthias Ringwald 
124*bd021c4eSMatthias Ringwald static int hci_transport_link_actions;
125*bd021c4eSMatthias Ringwald 
126*bd021c4eSMatthias Ringwald // UART Driver + Config
127*bd021c4eSMatthias Ringwald static const btstack_uart_block_t * btstack_uart;
128*bd021c4eSMatthias Ringwald static btstack_uart_config_t uart_config;
129*bd021c4eSMatthias Ringwald 
130*bd021c4eSMatthias Ringwald static int uart_write_active;
131*bd021c4eSMatthias Ringwald 
132*bd021c4eSMatthias Ringwald // Prototypes
133*bd021c4eSMatthias Ringwald static void hci_transport_h5_process_frame(uint16_t frame_size);
134*bd021c4eSMatthias Ringwald static int  hci_transport_link_have_outgoing_packet(void);
135*bd021c4eSMatthias Ringwald static void hci_transport_link_send_queued_packet(void);
136*bd021c4eSMatthias Ringwald static void hci_transport_link_set_timer(uint16_t timeout_ms);
137*bd021c4eSMatthias Ringwald static void hci_transport_link_timeout_handler(btstack_timer_source_t * timer);
138*bd021c4eSMatthias Ringwald static void hci_transport_link_run(void);
139*bd021c4eSMatthias Ringwald static void hci_transport_slip_init(void);
140*bd021c4eSMatthias Ringwald 
141*bd021c4eSMatthias Ringwald // -----------------------------
142*bd021c4eSMatthias Ringwald 
143*bd021c4eSMatthias Ringwald 
144*bd021c4eSMatthias Ringwald // SLIP Outgoing
145*bd021c4eSMatthias Ringwald 
146*bd021c4eSMatthias Ringwald // format: 0xc0 HEADER PACKER 0xc0
147*bd021c4eSMatthias Ringwald // @param uint8_t header[4]
148*bd021c4eSMatthias Ringwald static void hci_transport_slip_send_frame(const uint8_t * header, const uint8_t * packet, uint16_t packet_size){
149*bd021c4eSMatthias Ringwald 
150*bd021c4eSMatthias Ringwald     int pos = 0;
151*bd021c4eSMatthias Ringwald 
152*bd021c4eSMatthias Ringwald     // Start of Frame
153*bd021c4eSMatthias Ringwald     slip_outgoing_buffer[pos++] = BTSTACK_SLIP_SOF;
154*bd021c4eSMatthias Ringwald 
155*bd021c4eSMatthias Ringwald     // Header
156*bd021c4eSMatthias Ringwald     btstack_slip_encoder_start(header, 4);
157*bd021c4eSMatthias Ringwald     while (btstack_slip_encoder_has_data()){
158*bd021c4eSMatthias Ringwald         slip_outgoing_buffer[pos++] = btstack_slip_encoder_get_byte();
159*bd021c4eSMatthias Ringwald     }
160*bd021c4eSMatthias Ringwald 
161*bd021c4eSMatthias Ringwald     // Packet
162*bd021c4eSMatthias Ringwald     btstack_slip_encoder_start(packet, packet_size);
163*bd021c4eSMatthias Ringwald     while (btstack_slip_encoder_has_data()){
164*bd021c4eSMatthias Ringwald         slip_outgoing_buffer[pos++] = btstack_slip_encoder_get_byte();
165*bd021c4eSMatthias Ringwald     }
166*bd021c4eSMatthias Ringwald 
167*bd021c4eSMatthias Ringwald     // Start of Frame
168*bd021c4eSMatthias Ringwald     slip_outgoing_buffer[pos++] = BTSTACK_SLIP_SOF;
169*bd021c4eSMatthias Ringwald 
170*bd021c4eSMatthias Ringwald     uart_write_active = 1;
171*bd021c4eSMatthias Ringwald     btstack_uart->send_block(slip_outgoing_buffer, pos);
172*bd021c4eSMatthias Ringwald }
173*bd021c4eSMatthias Ringwald 
174*bd021c4eSMatthias Ringwald // SLIP Incoming
175*bd021c4eSMatthias Ringwald 
176*bd021c4eSMatthias Ringwald static void hci_transport_slip_init(void){
177*bd021c4eSMatthias Ringwald     btstack_slip_decoder_init(&hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE], 6 + HCI_PACKET_BUFFER_SIZE);
178*bd021c4eSMatthias Ringwald }
179*bd021c4eSMatthias Ringwald 
180*bd021c4eSMatthias Ringwald // H5 Three-Wire Implementation
181*bd021c4eSMatthias Ringwald 
182*bd021c4eSMatthias Ringwald static void hci_transport_link_calc_header(uint8_t * header,
183*bd021c4eSMatthias Ringwald     uint8_t  sequence_nr,
184*bd021c4eSMatthias Ringwald     uint8_t  acknowledgement_nr,
185*bd021c4eSMatthias Ringwald     uint8_t  data_integrity_check_present,
186*bd021c4eSMatthias Ringwald     uint8_t  reliable_packet,
187*bd021c4eSMatthias Ringwald     uint8_t  packet_type,
188*bd021c4eSMatthias Ringwald     uint16_t payload_length){
189*bd021c4eSMatthias Ringwald 
190*bd021c4eSMatthias Ringwald     // reset data integrity flag
191*bd021c4eSMatthias Ringwald     if (data_integrity_check_present){
192*bd021c4eSMatthias Ringwald         log_error("hci_transport_link_calc_header: data integrity not supported, dropping flag");
193*bd021c4eSMatthias Ringwald         data_integrity_check_present = 0;
194*bd021c4eSMatthias Ringwald     }
195*bd021c4eSMatthias Ringwald 
196*bd021c4eSMatthias Ringwald     header[0] = sequence_nr | (acknowledgement_nr << 3) | (data_integrity_check_present << 6) | (reliable_packet << 7);
197*bd021c4eSMatthias Ringwald     header[1] = packet_type | ((payload_length & 0x0f) << 4);
198*bd021c4eSMatthias Ringwald     header[2] = payload_length >> 4;
199*bd021c4eSMatthias Ringwald     header[3] = 0xff - (header[0] + header[1] + header[2]);
200*bd021c4eSMatthias Ringwald }
201*bd021c4eSMatthias Ringwald 
202*bd021c4eSMatthias Ringwald static void hci_transport_link_send_control(const uint8_t * message, int message_len){
203*bd021c4eSMatthias Ringwald     uint8_t header[4];
204*bd021c4eSMatthias Ringwald     hci_transport_link_calc_header(header, 0, 0, 0, 0, LINK_CONTROL_PACKET_TYPE, message_len);
205*bd021c4eSMatthias Ringwald     hci_transport_slip_send_frame(header, message, message_len);
206*bd021c4eSMatthias Ringwald }
207*bd021c4eSMatthias Ringwald 
208*bd021c4eSMatthias Ringwald static void hci_transport_link_send_sync(void){
209*bd021c4eSMatthias Ringwald     log_info("link: send sync");
210*bd021c4eSMatthias Ringwald     hci_transport_link_send_control(link_control_sync, sizeof(link_control_sync));
211*bd021c4eSMatthias Ringwald }
212*bd021c4eSMatthias Ringwald 
213*bd021c4eSMatthias Ringwald static void hci_transport_link_send_sync_response(void){
214*bd021c4eSMatthias Ringwald     log_info("link: send sync response");
215*bd021c4eSMatthias Ringwald     hci_transport_link_send_control(link_control_sync_response, sizeof(link_control_sync_response));
216*bd021c4eSMatthias Ringwald }
217*bd021c4eSMatthias Ringwald 
218*bd021c4eSMatthias Ringwald static void hci_transport_link_send_config(void){
219*bd021c4eSMatthias Ringwald     log_info("link: send config");
220*bd021c4eSMatthias Ringwald     hci_transport_link_send_control(link_control_config, sizeof(link_control_config));
221*bd021c4eSMatthias Ringwald }
222*bd021c4eSMatthias Ringwald 
223*bd021c4eSMatthias Ringwald static void hci_transport_link_send_config_response(void){
224*bd021c4eSMatthias Ringwald     log_info("link: send config response");
225*bd021c4eSMatthias Ringwald     hci_transport_link_send_control(link_control_config_response, sizeof(link_control_config_response));
226*bd021c4eSMatthias Ringwald }
227*bd021c4eSMatthias Ringwald 
228*bd021c4eSMatthias Ringwald static void hci_transport_link_send_woken(void){
229*bd021c4eSMatthias Ringwald     log_info("link: send woken");
230*bd021c4eSMatthias Ringwald     hci_transport_link_send_control(link_control_woken, sizeof(link_control_woken));
231*bd021c4eSMatthias Ringwald }
232*bd021c4eSMatthias Ringwald 
233*bd021c4eSMatthias Ringwald static void hci_transport_link_send_wakeup(void){
234*bd021c4eSMatthias Ringwald     log_info("link: send wakeup");
235*bd021c4eSMatthias Ringwald     hci_transport_link_send_control(link_control_wakeup, sizeof(link_control_wakeup));
236*bd021c4eSMatthias Ringwald }
237*bd021c4eSMatthias Ringwald 
238*bd021c4eSMatthias Ringwald static void hci_transport_link_send_queued_packet(void){
239*bd021c4eSMatthias Ringwald     log_info("hci_transport_link_send_queued_packet: seq %u, ack %u, size %u", link_seq_nr, link_ack_nr, hci_packet_size);
240*bd021c4eSMatthias Ringwald     log_info_hexdump(hci_packet, hci_packet_size);
241*bd021c4eSMatthias Ringwald 
242*bd021c4eSMatthias Ringwald     uint8_t header[4];
243*bd021c4eSMatthias Ringwald     hci_transport_link_calc_header(header, link_seq_nr, link_ack_nr, 0, 1, hci_packet_type, hci_packet_size);
244*bd021c4eSMatthias Ringwald     hci_transport_slip_send_frame(header, hci_packet, hci_packet_size);
245*bd021c4eSMatthias Ringwald }
246*bd021c4eSMatthias Ringwald 
247*bd021c4eSMatthias Ringwald static void hci_transport_link_send_ack_packet(void){
248*bd021c4eSMatthias Ringwald     log_info("link: send ack %u", link_ack_nr);
249*bd021c4eSMatthias Ringwald     uint8_t header[4];
250*bd021c4eSMatthias Ringwald     hci_transport_link_calc_header(header, 0, link_ack_nr, 0, 0, LINK_ACKNOWLEDGEMENT_TYPE, 0);
251*bd021c4eSMatthias Ringwald     hci_transport_slip_send_frame(header, NULL, 0);
252*bd021c4eSMatthias Ringwald }
253*bd021c4eSMatthias Ringwald 
254*bd021c4eSMatthias Ringwald static void hci_transport_link_run(void){
255*bd021c4eSMatthias Ringwald     // exit if outgoing active
256*bd021c4eSMatthias Ringwald     if (uart_write_active) return;
257*bd021c4eSMatthias Ringwald 
258*bd021c4eSMatthias Ringwald     // process queued requests
259*bd021c4eSMatthias Ringwald     if (hci_transport_link_actions & HCI_TRANSPORT_LINK_SEND_SYNC){
260*bd021c4eSMatthias Ringwald         hci_transport_link_actions &= ~HCI_TRANSPORT_LINK_SEND_SYNC;
261*bd021c4eSMatthias Ringwald         hci_transport_link_send_sync();
262*bd021c4eSMatthias Ringwald         return;
263*bd021c4eSMatthias Ringwald     }
264*bd021c4eSMatthias Ringwald     if (hci_transport_link_actions & HCI_TRANSPORT_LINK_SEND_SYNC_RESPONSE){
265*bd021c4eSMatthias Ringwald         hci_transport_link_actions &= ~HCI_TRANSPORT_LINK_SEND_SYNC_RESPONSE;
266*bd021c4eSMatthias Ringwald         hci_transport_link_send_sync_response();
267*bd021c4eSMatthias Ringwald         return;
268*bd021c4eSMatthias Ringwald     }
269*bd021c4eSMatthias Ringwald     if (hci_transport_link_actions & HCI_TRANSPORT_LINK_SEND_CONFIG){
270*bd021c4eSMatthias Ringwald         hci_transport_link_actions &= ~HCI_TRANSPORT_LINK_SEND_CONFIG;
271*bd021c4eSMatthias Ringwald         hci_transport_link_send_config();
272*bd021c4eSMatthias Ringwald         return;
273*bd021c4eSMatthias Ringwald     }
274*bd021c4eSMatthias Ringwald     if (hci_transport_link_actions & HCI_TRANSPORT_LINK_SEND_CONFIG_RESPONSE){
275*bd021c4eSMatthias Ringwald         hci_transport_link_actions &= ~HCI_TRANSPORT_LINK_SEND_CONFIG_RESPONSE;
276*bd021c4eSMatthias Ringwald         hci_transport_link_send_config_response();
277*bd021c4eSMatthias Ringwald         return;
278*bd021c4eSMatthias Ringwald     }
279*bd021c4eSMatthias Ringwald     if (hci_transport_link_actions & HCI_TRANSPORT_LINK_SEND_WOKEN){
280*bd021c4eSMatthias Ringwald         hci_transport_link_actions &= ~HCI_TRANSPORT_LINK_SEND_WOKEN;
281*bd021c4eSMatthias Ringwald         hci_transport_link_send_woken();
282*bd021c4eSMatthias Ringwald         return;
283*bd021c4eSMatthias Ringwald     }
284*bd021c4eSMatthias Ringwald     if (hci_transport_link_actions & HCI_TRANSPORT_LINK_SEND_WAKEUP){
285*bd021c4eSMatthias Ringwald         hci_transport_link_actions &= ~HCI_TRANSPORT_LINK_SEND_WAKEUP;
286*bd021c4eSMatthias Ringwald         hci_transport_link_send_wakeup();
287*bd021c4eSMatthias Ringwald         return;
288*bd021c4eSMatthias Ringwald     }
289*bd021c4eSMatthias Ringwald     if (hci_transport_link_actions & HCI_TRANSPORT_LINK_SEND_QUEUED_PACKET){
290*bd021c4eSMatthias Ringwald         hci_transport_link_actions &= ~HCI_TRANSPORT_LINK_SEND_QUEUED_PACKET;
291*bd021c4eSMatthias Ringwald         // packet already contains ack, no need to send addtitional one
292*bd021c4eSMatthias Ringwald         hci_transport_link_actions &= ~HCI_TRANSPORT_LINK_SEND_ACK_PACKET;
293*bd021c4eSMatthias Ringwald         hci_transport_link_send_queued_packet();
294*bd021c4eSMatthias Ringwald         return;
295*bd021c4eSMatthias Ringwald     }
296*bd021c4eSMatthias Ringwald     if (hci_transport_link_actions & HCI_TRANSPORT_LINK_SEND_ACK_PACKET){
297*bd021c4eSMatthias Ringwald         hci_transport_link_actions &= ~HCI_TRANSPORT_LINK_SEND_ACK_PACKET;
298*bd021c4eSMatthias Ringwald         hci_transport_link_send_ack_packet();
299*bd021c4eSMatthias Ringwald         return;
300*bd021c4eSMatthias Ringwald     }
301*bd021c4eSMatthias Ringwald }
302*bd021c4eSMatthias Ringwald 
303*bd021c4eSMatthias Ringwald static void hci_transport_link_set_timer(uint16_t timeout_ms){
304*bd021c4eSMatthias Ringwald     btstack_run_loop_set_timer_handler(&link_timer, &hci_transport_link_timeout_handler);
305*bd021c4eSMatthias Ringwald     btstack_run_loop_set_timer(&link_timer, timeout_ms);
306*bd021c4eSMatthias Ringwald     btstack_run_loop_add_timer(&link_timer);
307*bd021c4eSMatthias Ringwald }
308*bd021c4eSMatthias Ringwald 
309*bd021c4eSMatthias Ringwald static void hci_transport_link_timeout_handler(btstack_timer_source_t * timer){
310*bd021c4eSMatthias Ringwald     switch (link_state){
311*bd021c4eSMatthias Ringwald         case LINK_UNINITIALIZED:
312*bd021c4eSMatthias Ringwald             hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_SYNC;
313*bd021c4eSMatthias Ringwald             hci_transport_link_set_timer(LINK_PERIOD_MS);
314*bd021c4eSMatthias Ringwald             break;
315*bd021c4eSMatthias Ringwald         case LINK_INITIALIZED:
316*bd021c4eSMatthias Ringwald             hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_CONFIG;
317*bd021c4eSMatthias Ringwald             hci_transport_link_set_timer(LINK_PERIOD_MS);
318*bd021c4eSMatthias Ringwald             break;
319*bd021c4eSMatthias Ringwald         case LINK_ACTIVE:
320*bd021c4eSMatthias Ringwald             if (!hci_transport_link_have_outgoing_packet()){
321*bd021c4eSMatthias Ringwald                 log_info("h5 timeout while active, but no outgoing packet");
322*bd021c4eSMatthias Ringwald                 return;
323*bd021c4eSMatthias Ringwald             }
324*bd021c4eSMatthias Ringwald             if (link_peer_asleep){
325*bd021c4eSMatthias Ringwald                 hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_WAKEUP;
326*bd021c4eSMatthias Ringwald                 hci_transport_link_set_timer(LINK_WAKEUP_MS);
327*bd021c4eSMatthias Ringwald                 return;
328*bd021c4eSMatthias Ringwald             }
329*bd021c4eSMatthias Ringwald             // resend packet
330*bd021c4eSMatthias Ringwald             hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_QUEUED_PACKET;
331*bd021c4eSMatthias Ringwald             hci_transport_link_set_timer(link_resend_timeout_ms);
332*bd021c4eSMatthias Ringwald             break;
333*bd021c4eSMatthias Ringwald         default:
334*bd021c4eSMatthias Ringwald             break;
335*bd021c4eSMatthias Ringwald     }
336*bd021c4eSMatthias Ringwald 
337*bd021c4eSMatthias Ringwald     hci_transport_link_run();
338*bd021c4eSMatthias Ringwald }
339*bd021c4eSMatthias Ringwald 
340*bd021c4eSMatthias Ringwald static void hci_transport_link_init(void){
341*bd021c4eSMatthias Ringwald     link_state = LINK_UNINITIALIZED;
342*bd021c4eSMatthias Ringwald     link_peer_asleep = 0;
343*bd021c4eSMatthias Ringwald 
344*bd021c4eSMatthias Ringwald     // get started
345*bd021c4eSMatthias Ringwald     hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_SYNC;
346*bd021c4eSMatthias Ringwald     hci_transport_link_set_timer(LINK_PERIOD_MS);
347*bd021c4eSMatthias Ringwald     hci_transport_link_run();
348*bd021c4eSMatthias Ringwald }
349*bd021c4eSMatthias Ringwald 
350*bd021c4eSMatthias Ringwald static int hci_transport_link_inc_seq_nr(int seq_nr){
351*bd021c4eSMatthias Ringwald     return (seq_nr + 1) & 0x07;
352*bd021c4eSMatthias Ringwald }
353*bd021c4eSMatthias Ringwald 
354*bd021c4eSMatthias Ringwald static int hci_transport_link_have_outgoing_packet(void){
355*bd021c4eSMatthias Ringwald     return hci_packet != 0;
356*bd021c4eSMatthias Ringwald }
357*bd021c4eSMatthias Ringwald 
358*bd021c4eSMatthias Ringwald static void hci_transport_link_clear_queue(void){
359*bd021c4eSMatthias Ringwald     btstack_run_loop_remove_timer(&link_timer);
360*bd021c4eSMatthias Ringwald     hci_packet = NULL;
361*bd021c4eSMatthias Ringwald }
362*bd021c4eSMatthias Ringwald 
363*bd021c4eSMatthias Ringwald static void hci_transport_h5_queue_packet(uint8_t packet_type, uint8_t *packet, int size){
364*bd021c4eSMatthias Ringwald     hci_packet = packet;
365*bd021c4eSMatthias Ringwald     hci_packet_type = packet_type;
366*bd021c4eSMatthias Ringwald     hci_packet_size = size;
367*bd021c4eSMatthias Ringwald }
368*bd021c4eSMatthias Ringwald 
369*bd021c4eSMatthias Ringwald static void hci_transport_h5_process_frame(uint16_t frame_size){
370*bd021c4eSMatthias Ringwald 
371*bd021c4eSMatthias Ringwald     if (frame_size < 4) return;
372*bd021c4eSMatthias Ringwald 
373*bd021c4eSMatthias Ringwald     uint8_t * slip_header  = &hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE];
374*bd021c4eSMatthias Ringwald     uint8_t * slip_payload = &hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + 4];
375*bd021c4eSMatthias Ringwald     int       frame_size_without_header = frame_size - 4;
376*bd021c4eSMatthias Ringwald 
377*bd021c4eSMatthias Ringwald     int      seq_nr =  slip_header[0] & 0x07;
378*bd021c4eSMatthias Ringwald     int      ack_nr = (slip_header[0] >> 3)    & 0x07;
379*bd021c4eSMatthias Ringwald     int      data_integrity_check_present = (slip_header[0] & 0x40) != 0;
380*bd021c4eSMatthias Ringwald     int      reliable_packet  = (slip_header[0] & 0x80) != 0;
381*bd021c4eSMatthias Ringwald     uint8_t  link_packet_type = slip_header[1] & 0x0f;
382*bd021c4eSMatthias Ringwald     uint16_t link_payload_len = (slip_header[1] >> 4) | (slip_header[2] << 4);
383*bd021c4eSMatthias Ringwald 
384*bd021c4eSMatthias Ringwald     log_info("hci_transport_h5_process_frame, reliable %u, packet type %u, seq_nr %u, ack_nr %u", reliable_packet, link_packet_type, seq_nr, ack_nr);
385*bd021c4eSMatthias Ringwald     log_info_hexdump(slip_header, 4);
386*bd021c4eSMatthias Ringwald     log_info_hexdump(slip_payload, frame_size_without_header);
387*bd021c4eSMatthias Ringwald 
388*bd021c4eSMatthias Ringwald     // CSR 8811 does not seem to auto-detect H5 mode and sends data with even parity.
389*bd021c4eSMatthias Ringwald     // if this byte sequence is detected, just enable even parity
390*bd021c4eSMatthias Ringwald     const uint8_t sync_response_bcsp[] = {0x01, 0x7a, 0x06, 0x10};
391*bd021c4eSMatthias Ringwald     if (memcmp(sync_response_bcsp, slip_header, 4) == 0){
392*bd021c4eSMatthias Ringwald         log_info("h5: detected BSCP SYNC sent with Even Parity -> discard frame and enable Even Parity");
393*bd021c4eSMatthias Ringwald         btstack_uart->set_parity(1);
394*bd021c4eSMatthias Ringwald         return;
395*bd021c4eSMatthias Ringwald     }
396*bd021c4eSMatthias Ringwald 
397*bd021c4eSMatthias Ringwald     // validate header checksum
398*bd021c4eSMatthias Ringwald     uint8_t header_checksum = slip_header[0] + slip_header[1] + slip_header[2] + slip_header[3];
399*bd021c4eSMatthias Ringwald     if (header_checksum != 0xff){
400*bd021c4eSMatthias Ringwald         log_info("h5: header checksum 0x%02x (instead of 0xff)", header_checksum);
401*bd021c4eSMatthias Ringwald         return;
402*bd021c4eSMatthias Ringwald     }
403*bd021c4eSMatthias Ringwald 
404*bd021c4eSMatthias Ringwald     // validate payload length
405*bd021c4eSMatthias Ringwald     int data_integrity_len = data_integrity_check_present ? 2 : 0;
406*bd021c4eSMatthias Ringwald     uint16_t received_payload_len = frame_size_without_header - data_integrity_len;
407*bd021c4eSMatthias Ringwald     if (link_payload_len != received_payload_len){
408*bd021c4eSMatthias Ringwald         log_info("h5: expected payload len %u but got %u", link_payload_len, received_payload_len);
409*bd021c4eSMatthias Ringwald         return;
410*bd021c4eSMatthias Ringwald     }
411*bd021c4eSMatthias Ringwald 
412*bd021c4eSMatthias Ringwald     // (TODO data integrity check)
413*bd021c4eSMatthias Ringwald 
414*bd021c4eSMatthias Ringwald     switch (link_state){
415*bd021c4eSMatthias Ringwald         case LINK_UNINITIALIZED:
416*bd021c4eSMatthias Ringwald             if (link_packet_type != LINK_CONTROL_PACKET_TYPE) break;
417*bd021c4eSMatthias Ringwald             if (memcmp(slip_payload, link_control_sync, sizeof(link_control_sync)) == 0){
418*bd021c4eSMatthias Ringwald                 log_info("link: received sync");
419*bd021c4eSMatthias Ringwald                 hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_SYNC_RESPONSE;
420*bd021c4eSMatthias Ringwald             }
421*bd021c4eSMatthias Ringwald             if (memcmp(slip_payload, link_control_sync_response, sizeof(link_control_sync_response)) == 0){
422*bd021c4eSMatthias Ringwald                 log_info("link: received sync response");
423*bd021c4eSMatthias Ringwald                 link_state = LINK_INITIALIZED;
424*bd021c4eSMatthias Ringwald                 btstack_run_loop_remove_timer(&link_timer);
425*bd021c4eSMatthias Ringwald                 log_info("link initialized");
426*bd021c4eSMatthias Ringwald                 //
427*bd021c4eSMatthias Ringwald                 hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_CONFIG;
428*bd021c4eSMatthias Ringwald                 hci_transport_link_set_timer(LINK_PERIOD_MS);
429*bd021c4eSMatthias Ringwald             }
430*bd021c4eSMatthias Ringwald             break;
431*bd021c4eSMatthias Ringwald         case LINK_INITIALIZED:
432*bd021c4eSMatthias Ringwald             if (link_packet_type != LINK_CONTROL_PACKET_TYPE) break;
433*bd021c4eSMatthias Ringwald             if (memcmp(slip_payload, link_control_sync, sizeof(link_control_sync)) == 0){
434*bd021c4eSMatthias Ringwald                 log_info("link: received sync");
435*bd021c4eSMatthias Ringwald                 hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_SYNC_RESPONSE;
436*bd021c4eSMatthias Ringwald             }
437*bd021c4eSMatthias Ringwald             if (memcmp(slip_payload, link_control_config, sizeof(link_control_config)) == 0){
438*bd021c4eSMatthias Ringwald                 log_info("link: received config");
439*bd021c4eSMatthias Ringwald                 hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_CONFIG_RESPONSE;
440*bd021c4eSMatthias Ringwald             }
441*bd021c4eSMatthias Ringwald             if (memcmp(slip_payload, link_control_config_response, link_control_config_response_prefix_len) == 0){
442*bd021c4eSMatthias Ringwald                 log_info("link: received config response");
443*bd021c4eSMatthias Ringwald                 link_state = LINK_ACTIVE;
444*bd021c4eSMatthias Ringwald                 btstack_run_loop_remove_timer(&link_timer);
445*bd021c4eSMatthias Ringwald                 log_info("link activated");
446*bd021c4eSMatthias Ringwald                 //
447*bd021c4eSMatthias Ringwald                 link_seq_nr = 0;
448*bd021c4eSMatthias Ringwald                 link_ack_nr = 0;
449*bd021c4eSMatthias Ringwald                 // notify upper stack that it can start
450*bd021c4eSMatthias Ringwald                 uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
451*bd021c4eSMatthias Ringwald                 packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
452*bd021c4eSMatthias Ringwald             }
453*bd021c4eSMatthias Ringwald             break;
454*bd021c4eSMatthias Ringwald         case LINK_ACTIVE:
455*bd021c4eSMatthias Ringwald 
456*bd021c4eSMatthias Ringwald             // validate packet sequence nr in reliable packets (check for out of sequence error)
457*bd021c4eSMatthias Ringwald             if (reliable_packet){
458*bd021c4eSMatthias Ringwald                 if (seq_nr != link_ack_nr){
459*bd021c4eSMatthias Ringwald                     log_info("expected seq nr %u, but received %u", link_ack_nr, seq_nr);
460*bd021c4eSMatthias Ringwald                     hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_ACK_PACKET;
461*bd021c4eSMatthias Ringwald                     break;
462*bd021c4eSMatthias Ringwald                 }
463*bd021c4eSMatthias Ringwald                 // ack packet right away
464*bd021c4eSMatthias Ringwald                 link_ack_nr = hci_transport_link_inc_seq_nr(link_ack_nr);
465*bd021c4eSMatthias Ringwald                 hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_ACK_PACKET;
466*bd021c4eSMatthias Ringwald             }
467*bd021c4eSMatthias Ringwald 
468*bd021c4eSMatthias Ringwald             // Process ACKs in reliable packet and explicit ack packets
469*bd021c4eSMatthias Ringwald             if (reliable_packet || link_packet_type == LINK_ACKNOWLEDGEMENT_TYPE){
470*bd021c4eSMatthias Ringwald                 // our packet is good if the remote expects our seq nr + 1
471*bd021c4eSMatthias Ringwald                 int next_seq_nr = hci_transport_link_inc_seq_nr(link_seq_nr);
472*bd021c4eSMatthias Ringwald                 if (hci_transport_link_have_outgoing_packet() && next_seq_nr == ack_nr){
473*bd021c4eSMatthias Ringwald                     log_info("h5: outoing packet with seq %u ack'ed", link_seq_nr);
474*bd021c4eSMatthias Ringwald                     link_seq_nr = next_seq_nr;
475*bd021c4eSMatthias Ringwald                     hci_transport_link_clear_queue();
476*bd021c4eSMatthias Ringwald 
477*bd021c4eSMatthias Ringwald                     // notify upper stack that it can send again
478*bd021c4eSMatthias Ringwald                     uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
479*bd021c4eSMatthias Ringwald                     packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
480*bd021c4eSMatthias Ringwald                 }
481*bd021c4eSMatthias Ringwald             }
482*bd021c4eSMatthias Ringwald 
483*bd021c4eSMatthias Ringwald             switch (link_packet_type){
484*bd021c4eSMatthias Ringwald                 case LINK_CONTROL_PACKET_TYPE:
485*bd021c4eSMatthias Ringwald                     if (memcmp(slip_payload, link_control_config, sizeof(link_control_config)) == 0){
486*bd021c4eSMatthias Ringwald                         log_info("link: received config");
487*bd021c4eSMatthias Ringwald                         hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_CONFIG_RESPONSE;
488*bd021c4eSMatthias Ringwald                         break;
489*bd021c4eSMatthias Ringwald                     }
490*bd021c4eSMatthias Ringwald                     if (memcmp(slip_payload, link_control_sync, sizeof(link_control_sync)) == 0){
491*bd021c4eSMatthias Ringwald                         log_info("link: received sync in ACTIVE STATE!");
492*bd021c4eSMatthias Ringwald                         // TODO sync during active indicates peer reset -> full upper layer reset necessary
493*bd021c4eSMatthias Ringwald                         break;
494*bd021c4eSMatthias Ringwald                     }
495*bd021c4eSMatthias Ringwald                     if (memcmp(slip_payload, link_control_sleep, sizeof(link_control_sleep)) == 0){
496*bd021c4eSMatthias Ringwald                         log_info("link: received sleep message");
497*bd021c4eSMatthias Ringwald                         link_peer_asleep = 1;
498*bd021c4eSMatthias Ringwald                         break;
499*bd021c4eSMatthias Ringwald                     }
500*bd021c4eSMatthias Ringwald                     if (memcmp(slip_payload, link_control_wakeup, sizeof(link_control_wakeup)) == 0){
501*bd021c4eSMatthias Ringwald                         log_info("link: received wakupe message -> send woken");
502*bd021c4eSMatthias Ringwald                         link_peer_asleep = 0;
503*bd021c4eSMatthias Ringwald                         hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_WOKEN;
504*bd021c4eSMatthias Ringwald                         break;
505*bd021c4eSMatthias Ringwald                     }
506*bd021c4eSMatthias Ringwald                     if (memcmp(slip_payload, link_control_woken, sizeof(link_control_woken)) == 0){
507*bd021c4eSMatthias Ringwald                         log_info("link: received woken message");
508*bd021c4eSMatthias Ringwald                         link_peer_asleep = 0;
509*bd021c4eSMatthias Ringwald                         // TODO: send packet if queued....
510*bd021c4eSMatthias Ringwald                         break;
511*bd021c4eSMatthias Ringwald                     }
512*bd021c4eSMatthias Ringwald                     break;
513*bd021c4eSMatthias Ringwald                 case HCI_EVENT_PACKET:
514*bd021c4eSMatthias Ringwald                 case HCI_ACL_DATA_PACKET:
515*bd021c4eSMatthias Ringwald                 case HCI_SCO_DATA_PACKET:
516*bd021c4eSMatthias Ringwald                     packet_handler(link_packet_type, slip_payload, link_payload_len);
517*bd021c4eSMatthias Ringwald                     break;
518*bd021c4eSMatthias Ringwald             }
519*bd021c4eSMatthias Ringwald 
520*bd021c4eSMatthias Ringwald             break;
521*bd021c4eSMatthias Ringwald         default:
522*bd021c4eSMatthias Ringwald             break;
523*bd021c4eSMatthias Ringwald     }
524*bd021c4eSMatthias Ringwald 
525*bd021c4eSMatthias Ringwald     hci_transport_link_run();
526*bd021c4eSMatthias Ringwald }
527*bd021c4eSMatthias Ringwald 
528*bd021c4eSMatthias Ringwald // recommendet time until resend: 3 * time of largest packet
529*bd021c4eSMatthias Ringwald static uint16_t hci_transport_link_calc_resend_timeout(uint32_t baudrate){
530*bd021c4eSMatthias Ringwald     uint32_t max_packet_size_in_bit = (HCI_PACKET_BUFFER_SIZE + 6) << 3;
531*bd021c4eSMatthias Ringwald     uint32_t t_max_x3_ms = max_packet_size_in_bit * 3000 / baudrate;
532*bd021c4eSMatthias Ringwald     log_info("resend timeout for %u baud: %u ms", baudrate, t_max_x3_ms);
533*bd021c4eSMatthias Ringwald     return t_max_x3_ms;
534*bd021c4eSMatthias Ringwald }
535*bd021c4eSMatthias Ringwald 
536*bd021c4eSMatthias Ringwald static void hci_transport_link_update_resend_timeout(uint32_t baudrate){
537*bd021c4eSMatthias Ringwald     link_resend_timeout_ms = hci_transport_link_calc_resend_timeout(baudrate);
538*bd021c4eSMatthias Ringwald }
539*bd021c4eSMatthias Ringwald 
540*bd021c4eSMatthias Ringwald /// H5 Interface
541*bd021c4eSMatthias Ringwald 
542*bd021c4eSMatthias Ringwald static uint8_t hci_transport_link_read_byte;
543*bd021c4eSMatthias Ringwald 
544*bd021c4eSMatthias Ringwald static void hci_transport_h5_read_next_byte(void){
545*bd021c4eSMatthias Ringwald     log_info("hci_transport_h5_read_next_byte");
546*bd021c4eSMatthias Ringwald     btstack_uart->receive_block(&hci_transport_link_read_byte, 1);
547*bd021c4eSMatthias Ringwald }
548*bd021c4eSMatthias Ringwald 
549*bd021c4eSMatthias Ringwald static void hci_transport_h5_block_received(){
550*bd021c4eSMatthias Ringwald     // log_info("slip: process 0x%02x", hci_transport_link_read_byte);
551*bd021c4eSMatthias Ringwald     btstack_slip_decoder_process(hci_transport_link_read_byte);
552*bd021c4eSMatthias Ringwald     uint16_t frame_size = btstack_slip_decoder_frame_size();
553*bd021c4eSMatthias Ringwald     if (frame_size) {
554*bd021c4eSMatthias Ringwald         hci_transport_h5_process_frame(frame_size);
555*bd021c4eSMatthias Ringwald         hci_transport_slip_init();
556*bd021c4eSMatthias Ringwald     }
557*bd021c4eSMatthias Ringwald     hci_transport_h5_read_next_byte();
558*bd021c4eSMatthias Ringwald }
559*bd021c4eSMatthias Ringwald 
560*bd021c4eSMatthias Ringwald static void hci_transport_h5_block_sent(void){
561*bd021c4eSMatthias Ringwald     uart_write_active = 0;
562*bd021c4eSMatthias Ringwald     hci_transport_link_run();
563*bd021c4eSMatthias Ringwald }
564*bd021c4eSMatthias Ringwald 
565*bd021c4eSMatthias Ringwald static void hci_transport_h5_init(const void * transport_config){
566*bd021c4eSMatthias Ringwald     // check for hci_transport_config_uart_t
567*bd021c4eSMatthias Ringwald     if (!transport_config) {
568*bd021c4eSMatthias Ringwald         log_error("hci_transport_h5: no config!");
569*bd021c4eSMatthias Ringwald         return;
570*bd021c4eSMatthias Ringwald     }
571*bd021c4eSMatthias Ringwald     if (((hci_transport_config_t*)transport_config)->type != HCI_TRANSPORT_CONFIG_UART) {
572*bd021c4eSMatthias Ringwald         log_error("hci_transport_h5: config not of type != HCI_TRANSPORT_CONFIG_UART!");
573*bd021c4eSMatthias Ringwald         return;
574*bd021c4eSMatthias Ringwald     }
575*bd021c4eSMatthias Ringwald 
576*bd021c4eSMatthias Ringwald     // extract UART config from transport config
577*bd021c4eSMatthias Ringwald     hci_transport_config_uart_t * hci_transport_config_uart = (hci_transport_config_uart_t*) transport_config;
578*bd021c4eSMatthias Ringwald     uart_config.baudrate    = hci_transport_config_uart->baudrate_init;
579*bd021c4eSMatthias Ringwald     uart_config.flowcontrol = hci_transport_config_uart->flowcontrol;
580*bd021c4eSMatthias Ringwald     uart_config.device_name = hci_transport_config_uart->device_name;
581*bd021c4eSMatthias Ringwald 
582*bd021c4eSMatthias Ringwald     // setup UART driver
583*bd021c4eSMatthias Ringwald     btstack_uart->init(&uart_config);
584*bd021c4eSMatthias Ringwald     btstack_uart->set_block_received(&hci_transport_h5_block_received);
585*bd021c4eSMatthias Ringwald     btstack_uart->set_block_sent(&hci_transport_h5_block_sent);
586*bd021c4eSMatthias Ringwald }
587*bd021c4eSMatthias Ringwald 
588*bd021c4eSMatthias Ringwald static int hci_transport_h5_open(void){
589*bd021c4eSMatthias Ringwald     int res = btstack_uart->open();
590*bd021c4eSMatthias Ringwald     if (res){
591*bd021c4eSMatthias Ringwald         return res;
592*bd021c4eSMatthias Ringwald     }
593*bd021c4eSMatthias Ringwald 
594*bd021c4eSMatthias Ringwald     // setup resend timeout
595*bd021c4eSMatthias Ringwald     hci_transport_link_update_resend_timeout(uart_config.baudrate);
596*bd021c4eSMatthias Ringwald 
597*bd021c4eSMatthias Ringwald     // init slip parser state machine
598*bd021c4eSMatthias Ringwald     hci_transport_slip_init();
599*bd021c4eSMatthias Ringwald 
600*bd021c4eSMatthias Ringwald     // init link management - already starts syncing
601*bd021c4eSMatthias Ringwald     hci_transport_link_init();
602*bd021c4eSMatthias Ringwald 
603*bd021c4eSMatthias Ringwald     // start receiving
604*bd021c4eSMatthias Ringwald     hci_transport_h5_read_next_byte();
605*bd021c4eSMatthias Ringwald 
606*bd021c4eSMatthias Ringwald     return 0;
607*bd021c4eSMatthias Ringwald }
608*bd021c4eSMatthias Ringwald 
609*bd021c4eSMatthias Ringwald static int hci_transport_h5_close(void){
610*bd021c4eSMatthias Ringwald     return btstack_uart->close();
611*bd021c4eSMatthias Ringwald     return 0;
612*bd021c4eSMatthias Ringwald }
613*bd021c4eSMatthias Ringwald 
614*bd021c4eSMatthias Ringwald static void hci_transport_h5_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
615*bd021c4eSMatthias Ringwald     packet_handler = handler;
616*bd021c4eSMatthias Ringwald }
617*bd021c4eSMatthias Ringwald 
618*bd021c4eSMatthias Ringwald static int hci_transport_h5_can_send_packet_now(uint8_t packet_type){
619*bd021c4eSMatthias Ringwald     if (hci_transport_link_have_outgoing_packet()) return 0;
620*bd021c4eSMatthias Ringwald     return link_state == LINK_ACTIVE;
621*bd021c4eSMatthias Ringwald }
622*bd021c4eSMatthias Ringwald 
623*bd021c4eSMatthias Ringwald static int hci_transport_h5_send_packet(uint8_t packet_type, uint8_t *packet, int size){
624*bd021c4eSMatthias Ringwald     if (!hci_transport_h5_can_send_packet_now(packet_type)){
625*bd021c4eSMatthias Ringwald         log_error("hci_transport_h5_send_packet called but in state %u", link_state);
626*bd021c4eSMatthias Ringwald         return -1;
627*bd021c4eSMatthias Ringwald     }
628*bd021c4eSMatthias Ringwald 
629*bd021c4eSMatthias Ringwald     // store request
630*bd021c4eSMatthias Ringwald     hci_transport_h5_queue_packet(packet_type, packet, size);
631*bd021c4eSMatthias Ringwald 
632*bd021c4eSMatthias Ringwald     // send wakeup first
633*bd021c4eSMatthias Ringwald     if (link_peer_asleep){
634*bd021c4eSMatthias Ringwald         hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_WAKEUP;
635*bd021c4eSMatthias Ringwald         hci_transport_link_set_timer(LINK_WAKEUP_MS);
636*bd021c4eSMatthias Ringwald     } else {
637*bd021c4eSMatthias Ringwald         hci_transport_link_actions |= HCI_TRANSPORT_LINK_SEND_QUEUED_PACKET;
638*bd021c4eSMatthias Ringwald         hci_transport_link_set_timer(link_resend_timeout_ms);
639*bd021c4eSMatthias Ringwald     }
640*bd021c4eSMatthias Ringwald     hci_transport_link_run();
641*bd021c4eSMatthias Ringwald     return 0;
642*bd021c4eSMatthias Ringwald }
643*bd021c4eSMatthias Ringwald 
644*bd021c4eSMatthias Ringwald static int hci_transport_h5_set_baudrate(uint32_t baudrate){
645*bd021c4eSMatthias Ringwald 
646*bd021c4eSMatthias Ringwald     log_info("hci_transport_h5_set_baudrate %u", baudrate);
647*bd021c4eSMatthias Ringwald     int res = btstack_uart->set_baudrate(baudrate);
648*bd021c4eSMatthias Ringwald 
649*bd021c4eSMatthias Ringwald     if (res) return res;
650*bd021c4eSMatthias Ringwald     hci_transport_link_update_resend_timeout(baudrate);
651*bd021c4eSMatthias Ringwald     return 0;
652*bd021c4eSMatthias Ringwald }
653*bd021c4eSMatthias Ringwald 
654*bd021c4eSMatthias Ringwald static void hci_transport_h5_reset_link(void){
655*bd021c4eSMatthias Ringwald 
656*bd021c4eSMatthias Ringwald     log_info("hci_transport_h5_reset_link");
657*bd021c4eSMatthias Ringwald 
658*bd021c4eSMatthias Ringwald     // clear outgoing queue
659*bd021c4eSMatthias Ringwald     hci_transport_link_clear_queue();
660*bd021c4eSMatthias Ringwald 
661*bd021c4eSMatthias Ringwald     // init slip parser state machine
662*bd021c4eSMatthias Ringwald     hci_transport_slip_init();
663*bd021c4eSMatthias Ringwald 
664*bd021c4eSMatthias Ringwald     // init link management - already starts syncing
665*bd021c4eSMatthias Ringwald     hci_transport_link_init();
666*bd021c4eSMatthias Ringwald }
667*bd021c4eSMatthias Ringwald 
668*bd021c4eSMatthias Ringwald static const hci_transport_t hci_transport_h5 = {
669*bd021c4eSMatthias Ringwald     /* const char * name; */                                        "H5",
670*bd021c4eSMatthias Ringwald     /* void   (*init) (const void *transport_config); */            &hci_transport_h5_init,
671*bd021c4eSMatthias Ringwald     /* int    (*open)(void); */                                     &hci_transport_h5_open,
672*bd021c4eSMatthias Ringwald     /* int    (*close)(void); */                                    &hci_transport_h5_close,
673*bd021c4eSMatthias Ringwald     /* void   (*register_packet_handler)(void (*handler)(...); */   &hci_transport_h5_register_packet_handler,
674*bd021c4eSMatthias Ringwald     /* int    (*can_send_packet_now)(uint8_t packet_type); */       &hci_transport_h5_can_send_packet_now,
675*bd021c4eSMatthias Ringwald     /* int    (*send_packet)(...); */                               &hci_transport_h5_send_packet,
676*bd021c4eSMatthias Ringwald     /* int    (*set_baudrate)(uint32_t baudrate); */                &hci_transport_h5_set_baudrate,
677*bd021c4eSMatthias Ringwald     /* void   (*reset_link)(void); */                               &hci_transport_h5_reset_link,
678*bd021c4eSMatthias Ringwald };
679*bd021c4eSMatthias Ringwald 
680*bd021c4eSMatthias Ringwald // configure and return h5 singleton
681*bd021c4eSMatthias Ringwald const hci_transport_t * hci_transport_h5_instance(const btstack_uart_block_t * uart_driver) {
682*bd021c4eSMatthias Ringwald     btstack_uart = uart_driver;
683*bd021c4eSMatthias Ringwald     return &hci_transport_h5;
684*bd021c4eSMatthias Ringwald }
685