xref: /btstack/src/hci_transport_em9304_spi.c (revision 2fca4dad957cd7b88f4657ed51e89c12615dda72)
1161a5569SMatthias Ringwald /*
2161a5569SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3161a5569SMatthias Ringwald  *
4161a5569SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5161a5569SMatthias Ringwald  * modification, are permitted provided that the following conditions
6161a5569SMatthias Ringwald  * are met:
7161a5569SMatthias Ringwald  *
8161a5569SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9161a5569SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10161a5569SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11161a5569SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12161a5569SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13161a5569SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14161a5569SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15161a5569SMatthias Ringwald  *    from this software without specific prior written permission.
16161a5569SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17161a5569SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18161a5569SMatthias Ringwald  *    monetary gain.
19161a5569SMatthias Ringwald  *
20161a5569SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21161a5569SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22161a5569SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*2fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24*2fca4dadSMilanka Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25161a5569SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26161a5569SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27161a5569SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28161a5569SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29161a5569SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30161a5569SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31161a5569SMatthias Ringwald  * SUCH DAMAGE.
32161a5569SMatthias Ringwald  *
33161a5569SMatthias Ringwald  * Please inquire about commercial licensing options at
34161a5569SMatthias Ringwald  * [email protected]
35161a5569SMatthias Ringwald  *
36161a5569SMatthias Ringwald  */
37161a5569SMatthias Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "hci_transport_em9304_spi.c"
39161a5569SMatthias Ringwald 
40161a5569SMatthias Ringwald #include "btstack_config.h"
41c8dfe071SMatthias Ringwald #include "hci_transport_em9304_spi.h"
42c8dfe071SMatthias Ringwald 
43c8dfe071SMatthias Ringwald #include "hci_transport.h"
44161a5569SMatthias Ringwald 
45161a5569SMatthias Ringwald // EM9304 SPI Driver
46161a5569SMatthias Ringwald static const btstack_em9304_spi_t * btstack_em9304_spi;
47161a5569SMatthias Ringwald 
48161a5569SMatthias Ringwald /////////////////////////
49161a5569SMatthias Ringwald // em9304 engine
50161a5569SMatthias Ringwald #include "btstack_ring_buffer.h"
51161a5569SMatthias Ringwald #include "btstack_debug.h"
52161a5569SMatthias Ringwald #include "btstack_util.h"
53161a5569SMatthias Ringwald #include "hci.h"
54161a5569SMatthias Ringwald #include "hci_transport.h"
55161a5569SMatthias Ringwald 
56fc46bba0SMatthias Ringwald static void em9304_spi_engine_run(void);
57161a5569SMatthias Ringwald 
58161a5569SMatthias Ringwald #define STS_SLAVE_READY 0xc0
59161a5569SMatthias Ringwald 
60161a5569SMatthias Ringwald #define EM9304_SPI_HEADER_TX        0x42
61161a5569SMatthias Ringwald #define EM9304_SPI_HEADER_RX        0x81
62161a5569SMatthias Ringwald 
6324b2b71bSMatthias Ringwald #define SPI_EM9304_BUFFER_SIZE        64
64161a5569SMatthias Ringwald #define SPI_EM9304_RING_BUFFER_SIZE  128
65161a5569SMatthias Ringwald 
66161a5569SMatthias Ringwald // state
67161a5569SMatthias Ringwald static volatile enum {
68c682b8ecSMatthias Ringwald     SPI_EM9304_OFF,
69fc46bba0SMatthias Ringwald     SPI_EM9304_READY_FOR_TX,
70fc46bba0SMatthias Ringwald     SPI_EM9304_READY_FOR_TX_AND_RX,
71161a5569SMatthias Ringwald     SPI_EM9304_RX_W4_READ_COMMAND_SENT,
72161a5569SMatthias Ringwald     SPI_EM9304_RX_READ_COMMAND_SENT,
73161a5569SMatthias Ringwald     SPI_EM9304_RX_W4_STS2_RECEIVED,
74161a5569SMatthias Ringwald     SPI_EM9304_RX_STS2_RECEIVED,
75161a5569SMatthias Ringwald     SPI_EM9304_RX_W4_DATA_RECEIVED,
76161a5569SMatthias Ringwald     SPI_EM9304_RX_DATA_RECEIVED,
77161a5569SMatthias Ringwald     SPI_EM9304_TX_W4_RDY,
78161a5569SMatthias Ringwald     SPI_EM9304_TX_W4_WRITE_COMMAND_SENT,
79161a5569SMatthias Ringwald     SPI_EM9304_TX_WRITE_COMMAND_SENT,
80161a5569SMatthias Ringwald     SPI_EM9304_TX_W4_STS2_RECEIVED,
81161a5569SMatthias Ringwald     SPI_EM9304_TX_STS2_RECEIVED,
82161a5569SMatthias Ringwald     SPI_EM9304_TX_W4_DATA_SENT,
83161a5569SMatthias Ringwald     SPI_EM9304_TX_DATA_SENT,
84fc46bba0SMatthias Ringwald     SPI_EM9304_DONE,
85161a5569SMatthias Ringwald } em9304_spi_engine_state;
86161a5569SMatthias Ringwald 
87161a5569SMatthias Ringwald static uint16_t em9304_spi_engine_rx_request_len;
88161a5569SMatthias Ringwald static uint16_t em9304_spi_engine_tx_request_len;
89161a5569SMatthias Ringwald 
90161a5569SMatthias Ringwald static btstack_ring_buffer_t em9304_spi_engine_rx_ring_buffer;
9124b2b71bSMatthias Ringwald 
92161a5569SMatthias Ringwald static uint8_t em9304_spi_engine_rx_ring_buffer_storage[SPI_EM9304_RING_BUFFER_SIZE];
93161a5569SMatthias Ringwald 
94161a5569SMatthias Ringwald static const uint8_t  * em9304_spi_engine_tx_data;
95161a5569SMatthias Ringwald static uint16_t         em9304_spi_engine_tx_size;
96161a5569SMatthias Ringwald 
97161a5569SMatthias Ringwald // handlers
98f2e99339SMatthias Ringwald static void (*em9304_spi_engine_rx_available_handler)(void);
99161a5569SMatthias Ringwald static void (*em9304_spi_engine_tx_done_handler)(void);
100161a5569SMatthias Ringwald 
101161a5569SMatthias Ringwald // TODO: get rid of alignment requirement
102161a5569SMatthias Ringwald union {
103161a5569SMatthias Ringwald     uint32_t words[1];
104161a5569SMatthias Ringwald     uint8_t  bytes[1];
105161a5569SMatthias Ringwald } sCommand;
106161a5569SMatthias Ringwald 
107161a5569SMatthias Ringwald union {
108161a5569SMatthias Ringwald     uint32_t words[1];
109161a5569SMatthias Ringwald     uint8_t  bytes[1];
110161a5569SMatthias Ringwald } sStas;
111161a5569SMatthias Ringwald 
112161a5569SMatthias Ringwald union {
11324b2b71bSMatthias Ringwald     uint32_t words[SPI_EM9304_BUFFER_SIZE/4];
11424b2b71bSMatthias Ringwald     uint8_t  bytes[SPI_EM9304_BUFFER_SIZE];
11524b2b71bSMatthias Ringwald } em9304_spi_engine_spi_buffer;
116161a5569SMatthias Ringwald 
em9304_spi_engine_ready_callback(void)117161a5569SMatthias Ringwald static void em9304_spi_engine_ready_callback(void){
118fc46bba0SMatthias Ringwald     // TODO: collect states
119fc46bba0SMatthias Ringwald     em9304_spi_engine_run();
120161a5569SMatthias Ringwald }
121161a5569SMatthias Ringwald 
em9304_spi_engine_transfer_done(void)122161a5569SMatthias Ringwald static void em9304_spi_engine_transfer_done(void){
123161a5569SMatthias Ringwald     switch (em9304_spi_engine_state){
124161a5569SMatthias Ringwald         case SPI_EM9304_RX_W4_READ_COMMAND_SENT:
125161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_RX_READ_COMMAND_SENT;
126161a5569SMatthias Ringwald             break;
127161a5569SMatthias Ringwald         case SPI_EM9304_RX_W4_STS2_RECEIVED:
128161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_RX_STS2_RECEIVED;
129161a5569SMatthias Ringwald             break;
130161a5569SMatthias Ringwald         case SPI_EM9304_RX_W4_DATA_RECEIVED:
131161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_RX_DATA_RECEIVED;
132161a5569SMatthias Ringwald             break;
133161a5569SMatthias Ringwald         case SPI_EM9304_TX_W4_WRITE_COMMAND_SENT:
134161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_TX_WRITE_COMMAND_SENT;
135161a5569SMatthias Ringwald             break;
136161a5569SMatthias Ringwald         case SPI_EM9304_TX_W4_STS2_RECEIVED:
137161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_TX_STS2_RECEIVED;
138161a5569SMatthias Ringwald             break;
139161a5569SMatthias Ringwald         case SPI_EM9304_TX_W4_DATA_SENT:
140161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_TX_DATA_SENT;
141161a5569SMatthias Ringwald             break;
142161a5569SMatthias Ringwald         default:
143161a5569SMatthias Ringwald             return;
144161a5569SMatthias Ringwald     }
145fc46bba0SMatthias Ringwald     em9304_spi_engine_run();
146161a5569SMatthias Ringwald }
147161a5569SMatthias Ringwald 
em9304_spi_engine_start_tx_transaction(void)148161a5569SMatthias Ringwald static void em9304_spi_engine_start_tx_transaction(void){
149161a5569SMatthias Ringwald     // state = wait for RDY
150161a5569SMatthias Ringwald     em9304_spi_engine_state = SPI_EM9304_TX_W4_RDY;
151161a5569SMatthias Ringwald 
152161a5569SMatthias Ringwald     // chip select
153161a5569SMatthias Ringwald     btstack_em9304_spi->set_chip_select(1);
154161a5569SMatthias Ringwald 
155161a5569SMatthias Ringwald     // enable IRQ
156161a5569SMatthias Ringwald     btstack_em9304_spi->set_ready_callback(&em9304_spi_engine_ready_callback);
157161a5569SMatthias Ringwald }
158161a5569SMatthias Ringwald 
em9304_spi_engine_start_rx_transaction(void)159aed1d832SMatthias Ringwald static void em9304_spi_engine_start_rx_transaction(void){
160161a5569SMatthias Ringwald     // disable interrupt again
161161a5569SMatthias Ringwald     btstack_em9304_spi->set_ready_callback(NULL);
162f2e99339SMatthias Ringwald 
163161a5569SMatthias Ringwald     // enable chip select
164161a5569SMatthias Ringwald     btstack_em9304_spi->set_chip_select(1);
165161a5569SMatthias Ringwald 
166161a5569SMatthias Ringwald     // send read command
167161a5569SMatthias Ringwald     em9304_spi_engine_state = SPI_EM9304_RX_W4_READ_COMMAND_SENT;
168161a5569SMatthias Ringwald     sCommand.bytes[0] = EM9304_SPI_HEADER_RX;
169161a5569SMatthias Ringwald     btstack_em9304_spi->transmit(sCommand.bytes, 1);
170161a5569SMatthias Ringwald }
171aed1d832SMatthias Ringwald 
em9304_engine_space_in_rx_buffer(void)172aed1d832SMatthias Ringwald static inline int em9304_engine_space_in_rx_buffer(void){
173aed1d832SMatthias Ringwald     return btstack_ring_buffer_bytes_free(&em9304_spi_engine_rx_ring_buffer) >= SPI_EM9304_BUFFER_SIZE;
174aed1d832SMatthias Ringwald }
175aed1d832SMatthias Ringwald 
em9304_engine_receive_buffer_ready(void)176aed1d832SMatthias Ringwald static void em9304_engine_receive_buffer_ready(void){
177aed1d832SMatthias Ringwald     // no data ready for receive or transmit, but space in rx ringbuffer  -> enable READY IRQ
178aed1d832SMatthias Ringwald     em9304_spi_engine_state = SPI_EM9304_READY_FOR_TX_AND_RX;
179aed1d832SMatthias Ringwald     btstack_em9304_spi->set_ready_callback(&em9304_spi_engine_ready_callback);
180aed1d832SMatthias Ringwald     // avoid dead lock, check READY again
181aed1d832SMatthias Ringwald     if (btstack_em9304_spi->get_ready()){
182aed1d832SMatthias Ringwald         em9304_spi_engine_start_rx_transaction();
183aed1d832SMatthias Ringwald     }
184aed1d832SMatthias Ringwald }
185aed1d832SMatthias Ringwald 
em9304_engine_start_next_transaction(void)186aed1d832SMatthias Ringwald static void em9304_engine_start_next_transaction(void){
187aed1d832SMatthias Ringwald 
188aed1d832SMatthias Ringwald     switch (em9304_spi_engine_state){
189aed1d832SMatthias Ringwald         case SPI_EM9304_READY_FOR_TX:
190aed1d832SMatthias Ringwald         case SPI_EM9304_READY_FOR_TX_AND_RX:
191aed1d832SMatthias Ringwald         case SPI_EM9304_DONE:
192aed1d832SMatthias Ringwald             break;
193aed1d832SMatthias Ringwald         default:
194aed1d832SMatthias Ringwald             return;
195aed1d832SMatthias Ringwald     }
196aed1d832SMatthias Ringwald 
197aed1d832SMatthias Ringwald     if (btstack_em9304_spi->get_ready() && em9304_engine_space_in_rx_buffer()) {
198aed1d832SMatthias Ringwald         em9304_spi_engine_start_rx_transaction();
199161a5569SMatthias Ringwald     } else if (em9304_spi_engine_tx_size){
200161a5569SMatthias Ringwald         em9304_spi_engine_start_tx_transaction();
201f2e99339SMatthias Ringwald     } else if (em9304_engine_space_in_rx_buffer()){
202fc46bba0SMatthias Ringwald         em9304_engine_receive_buffer_ready();
203161a5569SMatthias Ringwald     }
204f2e99339SMatthias Ringwald }
205f2e99339SMatthias Ringwald 
em9304_engine_action_done(void)206fc46bba0SMatthias Ringwald static void em9304_engine_action_done(void){
207fc46bba0SMatthias Ringwald     // chip deselect & done
208fc46bba0SMatthias Ringwald     btstack_em9304_spi->set_chip_select(0);
209fc46bba0SMatthias Ringwald     em9304_spi_engine_state = SPI_EM9304_DONE;
210fc46bba0SMatthias Ringwald }
211fc46bba0SMatthias Ringwald 
em9304_spi_engine_run(void)212fc46bba0SMatthias Ringwald static void em9304_spi_engine_run(void){
213f2e99339SMatthias Ringwald     uint16_t max_bytes_to_send;
214f2e99339SMatthias Ringwald     switch (em9304_spi_engine_state){
215161a5569SMatthias Ringwald 
216aed1d832SMatthias Ringwald         case SPI_EM9304_READY_FOR_TX_AND_RX:
217aed1d832SMatthias Ringwald             // check if ready
218aed1d832SMatthias Ringwald             if (!btstack_em9304_spi->get_ready()) break;
219aed1d832SMatthias Ringwald             em9304_spi_engine_start_rx_transaction();
220aed1d832SMatthias Ringwald             break;
221aed1d832SMatthias Ringwald 
222161a5569SMatthias Ringwald         case SPI_EM9304_RX_READ_COMMAND_SENT:
223161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_RX_W4_STS2_RECEIVED;
224161a5569SMatthias Ringwald             btstack_em9304_spi->receive(sStas.bytes, 1);
225161a5569SMatthias Ringwald             break;
226161a5569SMatthias Ringwald 
227161a5569SMatthias Ringwald         case SPI_EM9304_RX_STS2_RECEIVED:
228161a5569SMatthias Ringwald             // check slave status
229161a5569SMatthias Ringwald             log_debug("RX: STS2 0x%02X", sStas.bytes[0]);
230161a5569SMatthias Ringwald 
231fc46bba0SMatthias Ringwald             // read data
232161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_RX_W4_DATA_RECEIVED;
233161a5569SMatthias Ringwald             em9304_spi_engine_rx_request_len = sStas.bytes[0];
23424b2b71bSMatthias Ringwald             btstack_em9304_spi->receive(em9304_spi_engine_spi_buffer.bytes, em9304_spi_engine_rx_request_len);
235161a5569SMatthias Ringwald             break;
236161a5569SMatthias Ringwald 
237161a5569SMatthias Ringwald         case SPI_EM9304_RX_DATA_RECEIVED:
238fc46bba0SMatthias Ringwald             // done
239fc46bba0SMatthias Ringwald             em9304_engine_action_done();
240161a5569SMatthias Ringwald 
241161a5569SMatthias Ringwald             // move data into ring buffer
24224b2b71bSMatthias Ringwald             btstack_ring_buffer_write(&em9304_spi_engine_rx_ring_buffer, em9304_spi_engine_spi_buffer.bytes, em9304_spi_engine_rx_request_len);
243161a5569SMatthias Ringwald             em9304_spi_engine_rx_request_len = 0;
244161a5569SMatthias Ringwald 
245fc46bba0SMatthias Ringwald             // notify about new data available -- assume empty
246f2e99339SMatthias Ringwald             (*em9304_spi_engine_rx_available_handler)();
247f2e99339SMatthias Ringwald 
248fc46bba0SMatthias Ringwald             // next
249fc46bba0SMatthias Ringwald             em9304_engine_start_next_transaction();
250161a5569SMatthias Ringwald             break;
251161a5569SMatthias Ringwald 
252161a5569SMatthias Ringwald         case SPI_EM9304_TX_W4_RDY:
253161a5569SMatthias Ringwald             // check if ready
254161a5569SMatthias Ringwald             if (!btstack_em9304_spi->get_ready()) break;
255161a5569SMatthias Ringwald 
256161a5569SMatthias Ringwald             // disable interrupt again
257161a5569SMatthias Ringwald             btstack_em9304_spi->set_ready_callback(NULL);
258161a5569SMatthias Ringwald 
259161a5569SMatthias Ringwald             // send write command
260161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_TX_W4_WRITE_COMMAND_SENT;
261161a5569SMatthias Ringwald             sCommand.bytes[0] = EM9304_SPI_HEADER_TX;
262161a5569SMatthias Ringwald             btstack_em9304_spi->transmit(sCommand.bytes, 1);
263161a5569SMatthias Ringwald             break;
264161a5569SMatthias Ringwald 
265161a5569SMatthias Ringwald         case SPI_EM9304_TX_WRITE_COMMAND_SENT:
266161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_TX_W4_STS2_RECEIVED;
267161a5569SMatthias Ringwald             btstack_em9304_spi->receive(sStas.bytes, 1);
268161a5569SMatthias Ringwald             break;
269161a5569SMatthias Ringwald 
270161a5569SMatthias Ringwald         case SPI_EM9304_TX_STS2_RECEIVED:
271161a5569SMatthias Ringwald             // check slave status and em9304 rx buffer space
272161a5569SMatthias Ringwald             log_debug("TX: STS2 0x%02X", sStas.bytes[0]);
273161a5569SMatthias Ringwald             max_bytes_to_send = sStas.bytes[0];
2744ea43905SMatthias Ringwald             if (max_bytes_to_send == 0u){
275fc46bba0SMatthias Ringwald                 // done
276fc46bba0SMatthias Ringwald                 em9304_engine_action_done();
277fc46bba0SMatthias Ringwald                 // next
278fc46bba0SMatthias Ringwald                 em9304_engine_start_next_transaction();
279161a5569SMatthias Ringwald                 break;
280161a5569SMatthias Ringwald             }
281161a5569SMatthias Ringwald 
282161a5569SMatthias Ringwald             // number bytes to send
283161a5569SMatthias Ringwald             em9304_spi_engine_tx_request_len = btstack_min(em9304_spi_engine_tx_size, max_bytes_to_send);
284161a5569SMatthias Ringwald 
285161a5569SMatthias Ringwald             // send command
286161a5569SMatthias Ringwald             em9304_spi_engine_state = SPI_EM9304_TX_W4_DATA_SENT;
2874ea43905SMatthias Ringwald             if ( (((uintptr_t) em9304_spi_engine_tx_data) & 0x03u) == 0u){
28824b2b71bSMatthias Ringwald                 // 4-byte aligned
289161a5569SMatthias Ringwald                 btstack_em9304_spi->transmit( (uint8_t*) em9304_spi_engine_tx_data, em9304_spi_engine_tx_request_len);
29024b2b71bSMatthias Ringwald             } else {
29124b2b71bSMatthias Ringwald                 // TODO: get rid of alignment requirement
29224b2b71bSMatthias Ringwald                 // enforce alignment by copying to spi buffer first
2936535961aSMatthias Ringwald                 (void)memcpy(em9304_spi_engine_spi_buffer.bytes,
2946535961aSMatthias Ringwald                              em9304_spi_engine_tx_data,
2956535961aSMatthias Ringwald                              em9304_spi_engine_tx_request_len);
29624b2b71bSMatthias Ringwald                 btstack_em9304_spi->transmit( (uint8_t*) em9304_spi_engine_spi_buffer.bytes, em9304_spi_engine_tx_request_len);
29724b2b71bSMatthias Ringwald             }
298161a5569SMatthias Ringwald             break;
299161a5569SMatthias Ringwald 
300161a5569SMatthias Ringwald         case SPI_EM9304_TX_DATA_SENT:
301fc46bba0SMatthias Ringwald             // done
302fc46bba0SMatthias Ringwald             em9304_engine_action_done();
303161a5569SMatthias Ringwald 
304fc46bba0SMatthias Ringwald             // chunk sent
305161a5569SMatthias Ringwald             em9304_spi_engine_tx_size -= em9304_spi_engine_tx_request_len;
306161a5569SMatthias Ringwald             em9304_spi_engine_tx_data += em9304_spi_engine_tx_request_len;
307161a5569SMatthias Ringwald             em9304_spi_engine_tx_request_len = 0;
308161a5569SMatthias Ringwald 
309fc46bba0SMatthias Ringwald             // notify higher layer when complete
3104ea43905SMatthias Ringwald             if (em9304_spi_engine_tx_size == 0u){
311161a5569SMatthias Ringwald                 (*em9304_spi_engine_tx_done_handler)();
312161a5569SMatthias Ringwald             }
313fc46bba0SMatthias Ringwald 
314fc46bba0SMatthias Ringwald             // next
315fc46bba0SMatthias Ringwald             em9304_engine_start_next_transaction();
316161a5569SMatthias Ringwald             break;
317161a5569SMatthias Ringwald 
318161a5569SMatthias Ringwald         default:
319161a5569SMatthias Ringwald             break;
320161a5569SMatthias Ringwald     }
321161a5569SMatthias Ringwald }
322161a5569SMatthias Ringwald 
em9304_spi_engine_init(void)323161a5569SMatthias Ringwald static void em9304_spi_engine_init(void){
324161a5569SMatthias Ringwald     btstack_em9304_spi->open();
325161a5569SMatthias Ringwald     btstack_em9304_spi->set_transfer_done_callback(&em9304_spi_engine_transfer_done);
326161a5569SMatthias Ringwald     btstack_ring_buffer_init(&em9304_spi_engine_rx_ring_buffer, &em9304_spi_engine_rx_ring_buffer_storage[0], SPI_EM9304_RING_BUFFER_SIZE);
327fc46bba0SMatthias Ringwald     em9304_spi_engine_state = SPI_EM9304_DONE;
328fc46bba0SMatthias Ringwald     em9304_engine_start_next_transaction();
329161a5569SMatthias Ringwald }
330161a5569SMatthias Ringwald 
em9304_spi_engine_close(void)331161a5569SMatthias Ringwald static void em9304_spi_engine_close(void){
332c682b8ecSMatthias Ringwald     em9304_spi_engine_state = SPI_EM9304_OFF;
333161a5569SMatthias Ringwald     btstack_em9304_spi->close();
334161a5569SMatthias Ringwald }
335161a5569SMatthias Ringwald 
em9304_spi_engine_set_data_available(void (* the_block_handler)(void))336f2e99339SMatthias Ringwald static void em9304_spi_engine_set_data_available( void (*the_block_handler)(void)){
337f2e99339SMatthias Ringwald     em9304_spi_engine_rx_available_handler = the_block_handler;
338161a5569SMatthias Ringwald }
339161a5569SMatthias Ringwald 
em9304_spi_engine_set_block_sent(void (* the_block_handler)(void))340161a5569SMatthias Ringwald static void em9304_spi_engine_set_block_sent( void (*the_block_handler)(void)){
341161a5569SMatthias Ringwald     em9304_spi_engine_tx_done_handler = the_block_handler;
342161a5569SMatthias Ringwald }
343161a5569SMatthias Ringwald 
em9304_spi_engine_send_block(const uint8_t * buffer,uint16_t length)344161a5569SMatthias Ringwald static void em9304_spi_engine_send_block(const uint8_t *buffer, uint16_t length){
345161a5569SMatthias Ringwald     em9304_spi_engine_tx_data = buffer;
346161a5569SMatthias Ringwald     em9304_spi_engine_tx_size = length;
347fc46bba0SMatthias Ringwald     em9304_engine_start_next_transaction();
348161a5569SMatthias Ringwald }
349161a5569SMatthias Ringwald 
em9304_engine_num_bytes_available(void)350fc46bba0SMatthias Ringwald static uint16_t em9304_engine_num_bytes_available(void){
351f2e99339SMatthias Ringwald     return btstack_ring_buffer_bytes_available(&em9304_spi_engine_rx_ring_buffer);
352161a5569SMatthias Ringwald }
353161a5569SMatthias Ringwald 
em9304_engine_get_bytes(uint8_t * buffer,uint16_t num_bytes)354f2e99339SMatthias Ringwald static void em9304_engine_get_bytes(uint8_t * buffer, uint16_t num_bytes){
355f2e99339SMatthias Ringwald     uint32_t bytes_read;
356f2e99339SMatthias Ringwald     btstack_ring_buffer_read(&em9304_spi_engine_rx_ring_buffer, buffer, num_bytes, &bytes_read);
357f2e99339SMatthias Ringwald }
358f2e99339SMatthias Ringwald 
359161a5569SMatthias Ringwald //////////////////////////////////////////////////////////////////////////////
360161a5569SMatthias Ringwald 
361161a5569SMatthias Ringwald // assert pre-buffer for packet type is available
362161a5569SMatthias Ringwald #if !defined(HCI_OUTGOING_PRE_BUFFER_SIZE) || (HCI_OUTGOING_PRE_BUFFER_SIZE == 0)
363161a5569SMatthias Ringwald #error HCI_OUTGOING_PRE_BUFFER_SIZE not defined. Please update hci.h
364161a5569SMatthias Ringwald #endif
365161a5569SMatthias Ringwald 
366161a5569SMatthias Ringwald static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
367161a5569SMatthias Ringwald 
368161a5569SMatthias Ringwald typedef enum {
369161a5569SMatthias Ringwald     H4_W4_PACKET_TYPE,
370161a5569SMatthias Ringwald     H4_W4_EVENT_HEADER,
371161a5569SMatthias Ringwald     H4_W4_ACL_HEADER,
372161a5569SMatthias Ringwald     H4_W4_PAYLOAD,
373161a5569SMatthias Ringwald } H4_STATE;
374161a5569SMatthias Ringwald 
375161a5569SMatthias Ringwald typedef enum {
376161a5569SMatthias Ringwald     TX_IDLE = 1,
377161a5569SMatthias Ringwald     TX_W4_PACKET_SENT,
378161a5569SMatthias Ringwald } TX_STATE;
379161a5569SMatthias Ringwald 
380161a5569SMatthias Ringwald // write state
381161a5569SMatthias Ringwald static TX_STATE tx_state;
382161a5569SMatthias Ringwald 
383161a5569SMatthias Ringwald static  void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = dummy_handler;
384161a5569SMatthias Ringwald 
385161a5569SMatthias Ringwald // packet reader state machine
386fc46bba0SMatthias Ringwald static H4_STATE hci_transport_em9304_h4_state;
387fc46bba0SMatthias Ringwald static uint16_t hci_transport_em9304_spi_bytes_to_read;
388fc46bba0SMatthias Ringwald static uint16_t hci_transport_em9304_spi_read_pos;
389161a5569SMatthias Ringwald 
390161a5569SMatthias Ringwald // incoming packet buffer
391fc6cde64SMatthias Ringwald static uint8_t hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + HCI_INCOMING_PACKET_BUFFER_SIZE + 1]; // packet type + max(acl header + acl payload, event header + event data)
392161a5569SMatthias Ringwald static uint8_t * hci_packet = &hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE];
393161a5569SMatthias Ringwald 
394f2e99339SMatthias Ringwald static void hci_transport_em9304_spi_block_read(void);
395f2e99339SMatthias Ringwald 
hci_transport_em9304_spi_reset_statemachine(void)396161a5569SMatthias Ringwald static void hci_transport_em9304_spi_reset_statemachine(void){
397fc46bba0SMatthias Ringwald     hci_transport_em9304_h4_state = H4_W4_PACKET_TYPE;
398fc46bba0SMatthias Ringwald     hci_transport_em9304_spi_read_pos = 0;
399fc46bba0SMatthias Ringwald     hci_transport_em9304_spi_bytes_to_read = 1;
400161a5569SMatthias Ringwald }
401161a5569SMatthias Ringwald 
hci_transport_em9304_spi_process_data(void)402f2e99339SMatthias Ringwald static void hci_transport_em9304_spi_process_data(void){
403ff3cc4a5SMatthias Ringwald     while (true){
404fc46bba0SMatthias Ringwald 
405fc46bba0SMatthias Ringwald         uint16_t bytes_available = em9304_engine_num_bytes_available();
406fc46bba0SMatthias Ringwald         log_debug("transfer_rx_data: ring buffer has %u -> hci wants %u", bytes_available, hci_transport_em9304_spi_bytes_to_read);
407f2e99339SMatthias Ringwald 
408f2e99339SMatthias Ringwald         if (!bytes_available) break;
409fc46bba0SMatthias Ringwald         if (!hci_transport_em9304_spi_bytes_to_read) break;
410f2e99339SMatthias Ringwald 
411fc46bba0SMatthias Ringwald         uint16_t bytes_to_copy = btstack_min(bytes_available, hci_transport_em9304_spi_bytes_to_read);
412fc46bba0SMatthias Ringwald         em9304_engine_get_bytes(&hci_packet[hci_transport_em9304_spi_read_pos], bytes_to_copy);
413f2e99339SMatthias Ringwald 
414fc46bba0SMatthias Ringwald         hci_transport_em9304_spi_read_pos      += bytes_to_copy;
415fc46bba0SMatthias Ringwald         hci_transport_em9304_spi_bytes_to_read -= bytes_to_copy;
416f2e99339SMatthias Ringwald 
4174ea43905SMatthias Ringwald         if (hci_transport_em9304_spi_bytes_to_read == 0u){
418fc46bba0SMatthias Ringwald             hci_transport_em9304_spi_block_read();
419f2e99339SMatthias Ringwald         }
420f2e99339SMatthias Ringwald     }
421f2e99339SMatthias Ringwald }
422f2e99339SMatthias Ringwald 
hci_transport_em9304_spi_packet_complete(void)4238c7252e2SMatthias Ringwald static void hci_transport_em9304_spi_packet_complete(void){
4244ea43905SMatthias Ringwald     packet_handler(hci_packet[0u], &hci_packet[1u], hci_transport_em9304_spi_read_pos-1u);
4258c7252e2SMatthias Ringwald     hci_transport_em9304_spi_reset_statemachine();
4268c7252e2SMatthias Ringwald }
4278c7252e2SMatthias Ringwald 
hci_transport_em9304_spi_block_read(void)428161a5569SMatthias Ringwald static void hci_transport_em9304_spi_block_read(void){
429fc46bba0SMatthias Ringwald     switch (hci_transport_em9304_h4_state) {
430161a5569SMatthias Ringwald         case H4_W4_PACKET_TYPE:
431161a5569SMatthias Ringwald             switch (hci_packet[0]){
432161a5569SMatthias Ringwald                 case HCI_EVENT_PACKET:
433fc46bba0SMatthias Ringwald                     hci_transport_em9304_spi_bytes_to_read = HCI_EVENT_HEADER_SIZE;
434fc46bba0SMatthias Ringwald                     hci_transport_em9304_h4_state = H4_W4_EVENT_HEADER;
435161a5569SMatthias Ringwald                     break;
436161a5569SMatthias Ringwald                 case HCI_ACL_DATA_PACKET:
437fc46bba0SMatthias Ringwald                     hci_transport_em9304_spi_bytes_to_read = HCI_ACL_HEADER_SIZE;
438fc46bba0SMatthias Ringwald                     hci_transport_em9304_h4_state = H4_W4_ACL_HEADER;
439161a5569SMatthias Ringwald                     break;
440161a5569SMatthias Ringwald                 default:
441fc46bba0SMatthias Ringwald                     log_error("invalid packet type 0x%02x", hci_packet[0]);
442161a5569SMatthias Ringwald                     hci_transport_em9304_spi_reset_statemachine();
443161a5569SMatthias Ringwald                     break;
444161a5569SMatthias Ringwald             }
445161a5569SMatthias Ringwald             break;
446161a5569SMatthias Ringwald 
447161a5569SMatthias Ringwald         case H4_W4_EVENT_HEADER:
448fc46bba0SMatthias Ringwald             hci_transport_em9304_spi_bytes_to_read = hci_packet[2];
449ea374553SMatthias Ringwald             // check Event length
450b06dfe1fSMatthias Ringwald             if (hci_transport_em9304_spi_bytes_to_read > (HCI_INCOMING_PACKET_BUFFER_SIZE - HCI_EVENT_HEADER_SIZE)){
451e8b81068SMatthias Ringwald                 log_error("invalid Event len %d - only space for %u", hci_transport_em9304_spi_bytes_to_read, HCI_INCOMING_PACKET_BUFFER_SIZE - HCI_EVENT_HEADER_SIZE);
452e8b81068SMatthias Ringwald                 hci_transport_em9304_spi_reset_statemachine();
453e8b81068SMatthias Ringwald                 break;
454e8b81068SMatthias Ringwald             }
4554ea43905SMatthias Ringwald             if (hci_transport_em9304_spi_bytes_to_read == 0u){
4568c7252e2SMatthias Ringwald                 hci_transport_em9304_spi_packet_complete();
4578c7252e2SMatthias Ringwald                 break;
4588c7252e2SMatthias Ringwald             }
459fc46bba0SMatthias Ringwald             hci_transport_em9304_h4_state = H4_W4_PAYLOAD;
460161a5569SMatthias Ringwald             break;
461161a5569SMatthias Ringwald 
462161a5569SMatthias Ringwald         case H4_W4_ACL_HEADER:
463fc46bba0SMatthias Ringwald             hci_transport_em9304_spi_bytes_to_read = little_endian_read_16( hci_packet, 3);
464161a5569SMatthias Ringwald             // check ACL length
465b06dfe1fSMatthias Ringwald             if (hci_transport_em9304_spi_bytes_to_read > (HCI_INCOMING_PACKET_BUFFER_SIZE - HCI_ACL_HEADER_SIZE)){
466fc6cde64SMatthias Ringwald                 log_error("invalid ACL payload len %d - only space for %u", hci_transport_em9304_spi_bytes_to_read, HCI_INCOMING_PACKET_BUFFER_SIZE - HCI_ACL_HEADER_SIZE);
467161a5569SMatthias Ringwald                 hci_transport_em9304_spi_reset_statemachine();
468161a5569SMatthias Ringwald                 break;
469161a5569SMatthias Ringwald             }
4704ea43905SMatthias Ringwald             if (hci_transport_em9304_spi_bytes_to_read == 0u){
4718c7252e2SMatthias Ringwald                 hci_transport_em9304_spi_packet_complete();
4728c7252e2SMatthias Ringwald                 break;
4738c7252e2SMatthias Ringwald             }
474fc46bba0SMatthias Ringwald             hci_transport_em9304_h4_state = H4_W4_PAYLOAD;
475161a5569SMatthias Ringwald             break;
476161a5569SMatthias Ringwald 
477161a5569SMatthias Ringwald         case H4_W4_PAYLOAD:
4788c7252e2SMatthias Ringwald             hci_transport_em9304_spi_packet_complete();
479161a5569SMatthias Ringwald             break;
480161a5569SMatthias Ringwald         default:
481161a5569SMatthias Ringwald             break;
482161a5569SMatthias Ringwald     }
483161a5569SMatthias Ringwald }
484161a5569SMatthias Ringwald 
hci_transport_em9304_spi_block_sent(void)485161a5569SMatthias Ringwald static void hci_transport_em9304_spi_block_sent(void){
4868334d3d8SMatthias Ringwald 
4878334d3d8SMatthias Ringwald     static const uint8_t packet_sent_event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
4888334d3d8SMatthias Ringwald 
489161a5569SMatthias Ringwald     switch (tx_state){
490161a5569SMatthias Ringwald         case TX_W4_PACKET_SENT:
491161a5569SMatthias Ringwald             // packet fully sent, reset state
492161a5569SMatthias Ringwald             tx_state = TX_IDLE;
493161a5569SMatthias Ringwald             // notify upper stack that it can send again
4948334d3d8SMatthias Ringwald             packet_handler(HCI_EVENT_PACKET, (uint8_t *) &packet_sent_event[0], sizeof(packet_sent_event));
495161a5569SMatthias Ringwald             break;
496161a5569SMatthias Ringwald         default:
497161a5569SMatthias Ringwald             break;
498161a5569SMatthias Ringwald     }
499161a5569SMatthias Ringwald }
500161a5569SMatthias Ringwald 
hci_transport_em9304_spi_can_send_now(uint8_t packet_type)501161a5569SMatthias Ringwald static int hci_transport_em9304_spi_can_send_now(uint8_t packet_type){
502cebe3e9eSMatthias Ringwald     UNUSED(packet_type);
503161a5569SMatthias Ringwald     return tx_state == TX_IDLE;
504161a5569SMatthias Ringwald }
505161a5569SMatthias Ringwald 
hci_transport_em9304_spi_send_packet(uint8_t packet_type,uint8_t * packet,int size)506161a5569SMatthias Ringwald static int hci_transport_em9304_spi_send_packet(uint8_t packet_type, uint8_t * packet, int size){
507161a5569SMatthias Ringwald 
508161a5569SMatthias Ringwald     // store packet type before actual data and increase size
509161a5569SMatthias Ringwald     size++;
510161a5569SMatthias Ringwald     packet--;
511161a5569SMatthias Ringwald     *packet = packet_type;
512161a5569SMatthias Ringwald 
513161a5569SMatthias Ringwald     // start sending
514161a5569SMatthias Ringwald     tx_state = TX_W4_PACKET_SENT;
515161a5569SMatthias Ringwald     em9304_spi_engine_send_block(packet, size);
516161a5569SMatthias Ringwald     return 0;
517161a5569SMatthias Ringwald }
518161a5569SMatthias Ringwald 
hci_transport_em9304_spi_init(const void * transport_config)519161a5569SMatthias Ringwald static void hci_transport_em9304_spi_init(const void * transport_config){
520cebe3e9eSMatthias Ringwald     UNUSED(transport_config);
521161a5569SMatthias Ringwald }
522161a5569SMatthias Ringwald 
hci_transport_em9304_spi_open(void)523161a5569SMatthias Ringwald static int hci_transport_em9304_spi_open(void){
524161a5569SMatthias Ringwald 
525161a5569SMatthias Ringwald     // setup UART driver
526161a5569SMatthias Ringwald     em9304_spi_engine_init();
527f2e99339SMatthias Ringwald     em9304_spi_engine_set_data_available(&hci_transport_em9304_spi_process_data);
528161a5569SMatthias Ringwald     em9304_spi_engine_set_block_sent(&hci_transport_em9304_spi_block_sent);
529161a5569SMatthias Ringwald     // setup H4 RX
530161a5569SMatthias Ringwald     hci_transport_em9304_spi_reset_statemachine();
531161a5569SMatthias Ringwald     // setup H4 TX
532161a5569SMatthias Ringwald     tx_state = TX_IDLE;
533161a5569SMatthias Ringwald     return 0;
534161a5569SMatthias Ringwald }
535161a5569SMatthias Ringwald 
hci_transport_em9304_spi_close(void)536161a5569SMatthias Ringwald static int hci_transport_em9304_spi_close(void){
537161a5569SMatthias Ringwald     em9304_spi_engine_close();
538161a5569SMatthias Ringwald     return 0;
539161a5569SMatthias Ringwald }
540161a5569SMatthias Ringwald 
hci_transport_em9304_spi_register_packet_handler(void (* handler)(uint8_t packet_type,uint8_t * packet,uint16_t size))541161a5569SMatthias Ringwald static void hci_transport_em9304_spi_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
542161a5569SMatthias Ringwald     packet_handler = handler;
543161a5569SMatthias Ringwald }
544161a5569SMatthias Ringwald 
dummy_handler(uint8_t packet_type,uint8_t * packet,uint16_t size)545161a5569SMatthias Ringwald static void dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
546cebe3e9eSMatthias Ringwald     UNUSED(packet_type);
547cebe3e9eSMatthias Ringwald     UNUSED(packet);
548cebe3e9eSMatthias Ringwald     UNUSED(size);
549161a5569SMatthias Ringwald }
550161a5569SMatthias Ringwald 
551161a5569SMatthias Ringwald // --- end of eHCILL implementation ---------
552161a5569SMatthias Ringwald 
5538334d3d8SMatthias Ringwald // configure and return h4 singleton
hci_transport_em9304_spi_instance(const btstack_em9304_spi_t * em9304_spi_driver)5548334d3d8SMatthias Ringwald const hci_transport_t * hci_transport_em9304_spi_instance(const btstack_em9304_spi_t * em9304_spi_driver) {
5558334d3d8SMatthias Ringwald 
556161a5569SMatthias Ringwald     static const hci_transport_t hci_transport_em9304_spi = {
557161a5569SMatthias Ringwald             /* const char * name; */                                        "H4",
558161a5569SMatthias Ringwald             /* void   (*init) (const void *transport_config); */            &hci_transport_em9304_spi_init,
559161a5569SMatthias Ringwald             /* int    (*open)(void); */                                     &hci_transport_em9304_spi_open,
560161a5569SMatthias Ringwald             /* int    (*close)(void); */                                    &hci_transport_em9304_spi_close,
561161a5569SMatthias Ringwald             /* void   (*register_packet_handler)(void (*handler)(...); */   &hci_transport_em9304_spi_register_packet_handler,
562161a5569SMatthias Ringwald             /* int    (*can_send_packet_now)(uint8_t packet_type); */       &hci_transport_em9304_spi_can_send_now,
563161a5569SMatthias Ringwald             /* int    (*send_packet)(...); */                               &hci_transport_em9304_spi_send_packet,
564161a5569SMatthias Ringwald             /* int    (*set_baudrate)(uint32_t baudrate); */                NULL,
565161a5569SMatthias Ringwald             /* void   (*reset_link)(void); */                               NULL,
566161a5569SMatthias Ringwald             /* void   (*set_sco_config)(uint16_t voice_setting, int num_connections); */ NULL,
567161a5569SMatthias Ringwald     };
568161a5569SMatthias Ringwald 
569161a5569SMatthias Ringwald     btstack_em9304_spi = em9304_spi_driver;
570161a5569SMatthias Ringwald     return &hci_transport_em9304_spi;
571161a5569SMatthias Ringwald }
572