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 23161a5569SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24161a5569SMatthias Ringwald * RINGWALD 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" 41*c8dfe071SMatthias Ringwald #include "hci_transport_em9304_spi.h" 42*c8dfe071SMatthias Ringwald 43*c8dfe071SMatthias 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 519161a5569SMatthias Ringwald static void hci_transport_em9304_spi_init(const void * transport_config){ 520cebe3e9eSMatthias Ringwald UNUSED(transport_config); 521161a5569SMatthias Ringwald } 522161a5569SMatthias Ringwald 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 536161a5569SMatthias Ringwald static int hci_transport_em9304_spi_close(void){ 537161a5569SMatthias Ringwald em9304_spi_engine_close(); 538161a5569SMatthias Ringwald return 0; 539161a5569SMatthias Ringwald } 540161a5569SMatthias Ringwald 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 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 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