em9304: process all received data at once, cleanup state machine

This commit is contained in:
Matthias Ringwald 2017-12-20 14:43:00 +01:00
parent f2e99339cd
commit fc46bba0b0

View File

@ -51,7 +51,7 @@ static const btstack_em9304_spi_t * btstack_em9304_spi;
#include "hci.h" #include "hci.h"
#include "hci_transport.h" #include "hci_transport.h"
static void em9304_spi_engine_process(void); static void em9304_spi_engine_run(void);
#define STS_SLAVE_READY 0xc0 #define STS_SLAVE_READY 0xc0
@ -64,7 +64,8 @@ static void em9304_spi_engine_process(void);
// state // state
static volatile enum { static volatile enum {
SPI_EM9304_IDLE, SPI_EM9304_READY_FOR_TX,
SPI_EM9304_READY_FOR_TX_AND_RX,
SPI_EM9304_RX_W4_READ_COMMAND_SENT, SPI_EM9304_RX_W4_READ_COMMAND_SENT,
SPI_EM9304_RX_READ_COMMAND_SENT, SPI_EM9304_RX_READ_COMMAND_SENT,
SPI_EM9304_RX_W4_STS2_RECEIVED, SPI_EM9304_RX_W4_STS2_RECEIVED,
@ -78,6 +79,7 @@ static volatile enum {
SPI_EM9304_TX_STS2_RECEIVED, SPI_EM9304_TX_STS2_RECEIVED,
SPI_EM9304_TX_W4_DATA_SENT, SPI_EM9304_TX_W4_DATA_SENT,
SPI_EM9304_TX_DATA_SENT, SPI_EM9304_TX_DATA_SENT,
SPI_EM9304_DONE,
} em9304_spi_engine_state; } em9304_spi_engine_state;
static uint16_t em9304_spi_engine_rx_request_len; static uint16_t em9304_spi_engine_rx_request_len;
@ -110,7 +112,8 @@ union {
} em9304_spi_engine_spi_rx_buffer; } em9304_spi_engine_spi_rx_buffer;
static void em9304_spi_engine_ready_callback(void){ static void em9304_spi_engine_ready_callback(void){
em9304_spi_engine_process(); // TODO: collect states
em9304_spi_engine_run();
} }
static void em9304_spi_engine_transfer_done(void){ static void em9304_spi_engine_transfer_done(void){
@ -136,7 +139,7 @@ static void em9304_spi_engine_transfer_done(void){
default: default:
return; return;
} }
em9304_spi_engine_process(); em9304_spi_engine_run();
} }
static void em9304_spi_engine_start_tx_transaction(void){ static void em9304_spi_engine_start_tx_transaction(void){
@ -154,9 +157,15 @@ static inline int em9304_engine_space_in_rx_buffer(void){
return btstack_ring_buffer_bytes_free(&em9304_spi_engine_rx_ring_buffer) >= SPI_EM9304_RX_BUFFER_SIZE; return btstack_ring_buffer_bytes_free(&em9304_spi_engine_rx_ring_buffer) >= SPI_EM9304_RX_BUFFER_SIZE;
} }
static void em9304_engine_idle(void){ static void em9304_engine_receive_buffer_ready(void){
// no data ready for receive or transmit, but space in rx ringbuffer -> enable READY IRQ
em9304_spi_engine_state = SPI_EM9304_READY_FOR_TX_AND_RX;
btstack_em9304_spi->set_ready_callback(&em9304_spi_engine_ready_callback);
}
if (em9304_spi_engine_state != SPI_EM9304_IDLE) return; static void em9304_engine_start_next_transaction(void){
if (em9304_spi_engine_state != SPI_EM9304_DONE) return;
if (btstack_em9304_spi->get_ready()){ if (btstack_em9304_spi->get_ready()){
// RDY -> data available // RDY -> data available
@ -173,22 +182,21 @@ static void em9304_engine_idle(void){
btstack_em9304_spi->transmit(sCommand.bytes, 1); btstack_em9304_spi->transmit(sCommand.bytes, 1);
} }
} else if (em9304_spi_engine_tx_size){ } else if (em9304_spi_engine_tx_size){
// start TX
em9304_spi_engine_start_tx_transaction(); em9304_spi_engine_start_tx_transaction();
} else if (em9304_engine_space_in_rx_buffer()){ } else if (em9304_engine_space_in_rx_buffer()){
// no data ready for receive or transmit, but space in rx ringbuffer -> enable READY IRQ em9304_engine_receive_buffer_ready();
btstack_em9304_spi->set_ready_callback(&em9304_spi_engine_ready_callback);
} }
} }
static void em9304_spi_engine_process(void){ static void em9304_engine_action_done(void){
uint16_t max_bytes_to_send; // chip deselect & done
btstack_em9304_spi->set_chip_select(0);
em9304_spi_engine_state = SPI_EM9304_DONE;
}
static void em9304_spi_engine_run(void){
uint16_t max_bytes_to_send;
switch (em9304_spi_engine_state){ switch (em9304_spi_engine_state){
case SPI_EM9304_IDLE:
em9304_engine_idle();
break;
case SPI_EM9304_RX_READ_COMMAND_SENT: case SPI_EM9304_RX_READ_COMMAND_SENT:
em9304_spi_engine_state = SPI_EM9304_RX_W4_STS2_RECEIVED; em9304_spi_engine_state = SPI_EM9304_RX_W4_STS2_RECEIVED;
@ -199,27 +207,25 @@ static void em9304_spi_engine_process(void){
// check slave status // check slave status
log_debug("RX: STS2 0x%02X", sStas.bytes[0]); log_debug("RX: STS2 0x%02X", sStas.bytes[0]);
// read data and send '0's // read data
em9304_spi_engine_state = SPI_EM9304_RX_W4_DATA_RECEIVED; em9304_spi_engine_state = SPI_EM9304_RX_W4_DATA_RECEIVED;
em9304_spi_engine_rx_request_len = sStas.bytes[0]; em9304_spi_engine_rx_request_len = sStas.bytes[0];
btstack_em9304_spi->receive(em9304_spi_engine_spi_rx_buffer.bytes, em9304_spi_engine_rx_request_len); btstack_em9304_spi->receive(em9304_spi_engine_spi_rx_buffer.bytes, em9304_spi_engine_rx_request_len);
break; break;
case SPI_EM9304_RX_DATA_RECEIVED: case SPI_EM9304_RX_DATA_RECEIVED:
// done
// chip deselect & done em9304_engine_action_done();
btstack_em9304_spi->set_chip_select(0);
em9304_spi_engine_state = SPI_EM9304_IDLE;
// move data into ring buffer // move data into ring buffer
btstack_ring_buffer_write(&em9304_spi_engine_rx_ring_buffer, em9304_spi_engine_spi_rx_buffer.bytes, em9304_spi_engine_rx_request_len); btstack_ring_buffer_write(&em9304_spi_engine_rx_ring_buffer, em9304_spi_engine_spi_rx_buffer.bytes, em9304_spi_engine_rx_request_len);
em9304_spi_engine_rx_request_len = 0; em9304_spi_engine_rx_request_len = 0;
// deliver new data // notify about new data available -- assume empty
(*em9304_spi_engine_rx_available_handler)(); (*em9304_spi_engine_rx_available_handler)();
// idle, look for more work // next
em9304_engine_idle(); em9304_engine_start_next_transaction();
break; break;
case SPI_EM9304_TX_W4_RDY: case SPI_EM9304_TX_W4_RDY:
@ -245,9 +251,10 @@ static void em9304_spi_engine_process(void){
log_debug("TX: STS2 0x%02X", sStas.bytes[0]); log_debug("TX: STS2 0x%02X", sStas.bytes[0]);
max_bytes_to_send = sStas.bytes[0]; max_bytes_to_send = sStas.bytes[0];
if (max_bytes_to_send == 0){ if (max_bytes_to_send == 0){
// chip deselect & retry // done
btstack_em9304_spi->set_chip_select(0); em9304_engine_action_done();
em9304_spi_engine_state = SPI_EM9304_IDLE; // next
em9304_engine_start_next_transaction();
break; break;
} }
@ -260,27 +267,21 @@ static void em9304_spi_engine_process(void){
break; break;
case SPI_EM9304_TX_DATA_SENT: case SPI_EM9304_TX_DATA_SENT:
// done
em9304_engine_action_done();
// chip deselect & done // chunk sent
btstack_em9304_spi->set_chip_select(0);
em9304_spi_engine_state = SPI_EM9304_IDLE;
// chunk processed
em9304_spi_engine_tx_size -= em9304_spi_engine_tx_request_len; em9304_spi_engine_tx_size -= em9304_spi_engine_tx_request_len;
em9304_spi_engine_tx_data += em9304_spi_engine_tx_request_len; em9304_spi_engine_tx_data += em9304_spi_engine_tx_request_len;
em9304_spi_engine_tx_request_len = 0; em9304_spi_engine_tx_request_len = 0;
// handle TX Complete // notify higher layer when complete
if (em9304_spi_engine_tx_size){ if (em9304_spi_engine_tx_size == 0){
// more data to send
em9304_spi_engine_start_tx_transaction();
} else {
// notify higher layer
(*em9304_spi_engine_tx_done_handler)(); (*em9304_spi_engine_tx_done_handler)();
// idle, look for more work
em9304_engine_idle();
} }
// next
em9304_engine_start_next_transaction();
break; break;
default: default:
@ -292,6 +293,8 @@ static void em9304_spi_engine_init(void){
btstack_em9304_spi->open(); btstack_em9304_spi->open();
btstack_em9304_spi->set_transfer_done_callback(&em9304_spi_engine_transfer_done); btstack_em9304_spi->set_transfer_done_callback(&em9304_spi_engine_transfer_done);
btstack_ring_buffer_init(&em9304_spi_engine_rx_ring_buffer, &em9304_spi_engine_rx_ring_buffer_storage[0], SPI_EM9304_RING_BUFFER_SIZE); btstack_ring_buffer_init(&em9304_spi_engine_rx_ring_buffer, &em9304_spi_engine_rx_ring_buffer_storage[0], SPI_EM9304_RING_BUFFER_SIZE);
em9304_spi_engine_state = SPI_EM9304_DONE;
em9304_engine_start_next_transaction();
} }
static void em9304_spi_engine_close(void){ static void em9304_spi_engine_close(void){
@ -309,10 +312,10 @@ static void em9304_spi_engine_set_block_sent( void (*the_block_handler)(void)){
static void em9304_spi_engine_send_block(const uint8_t *buffer, uint16_t length){ static void em9304_spi_engine_send_block(const uint8_t *buffer, uint16_t length){
em9304_spi_engine_tx_data = buffer; em9304_spi_engine_tx_data = buffer;
em9304_spi_engine_tx_size = length; em9304_spi_engine_tx_size = length;
em9304_spi_engine_process(); em9304_engine_start_next_transaction();
} }
static int em9304_engine_num_bytes_available(void){ static uint16_t em9304_engine_num_bytes_available(void){
return btstack_ring_buffer_bytes_available(&em9304_spi_engine_rx_ring_buffer); return btstack_ring_buffer_bytes_available(&em9304_spi_engine_rx_ring_buffer);
} }
@ -321,7 +324,6 @@ static void em9304_engine_get_bytes(uint8_t * buffer, uint16_t num_bytes){
btstack_ring_buffer_read(&em9304_spi_engine_rx_ring_buffer, buffer, num_bytes, &bytes_read); btstack_ring_buffer_read(&em9304_spi_engine_rx_ring_buffer, buffer, num_bytes, &bytes_read);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// assert pre-buffer for packet type is available // assert pre-buffer for packet type is available
@ -351,106 +353,85 @@ static uint8_t packet_sent_event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
static void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = dummy_handler; static void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = dummy_handler;
// packet reader state machine // packet reader state machine
static H4_STATE h4_state; static H4_STATE hci_transport_em9304_h4_state;
static int bytes_to_read; static uint16_t hci_transport_em9304_spi_bytes_to_read;
static int read_pos; static uint16_t hci_transport_em9304_spi_read_pos;
// incoming packet buffer // incoming packet buffer
static uint8_t hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + 1 + HCI_PACKET_BUFFER_SIZE]; // packet type + max(acl header + acl payload, event header + event data) static uint8_t hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + 1 + HCI_PACKET_BUFFER_SIZE]; // packet type + max(acl header + acl payload, event header + event data)
static uint8_t * hci_packet = &hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE]; static uint8_t * hci_packet = &hci_packet_with_pre_buffer[HCI_INCOMING_PRE_BUFFER_SIZE];
static uint8_t * hci_transport_em9304_spi_rx_buffer;
static uint16_t hci_transport_em9304_spi_rx_len;
static void hci_transport_em9304_spi_block_read(void); static void hci_transport_em9304_spi_block_read(void);
static void hci_transport_em9304_spi_reset_statemachine(void){ static void hci_transport_em9304_spi_reset_statemachine(void){
h4_state = H4_W4_PACKET_TYPE; hci_transport_em9304_h4_state = H4_W4_PACKET_TYPE;
read_pos = 0; hci_transport_em9304_spi_read_pos = 0;
bytes_to_read = 1; hci_transport_em9304_spi_bytes_to_read = 1;
} }
static void hci_transport_em9304_spi_process_data(void){ static void hci_transport_em9304_spi_process_data(void){
while (1){ while (1){
int bytes_available = em9304_engine_num_bytes_available();
log_debug("transfer_rx_data: ring buffer has %u -> hci buffer needs %u", bytes_available, hci_transport_em9304_spi_rx_len); uint16_t bytes_available = em9304_engine_num_bytes_available();
log_debug("transfer_rx_data: ring buffer has %u -> hci wants %u", bytes_available, hci_transport_em9304_spi_bytes_to_read);
if (!bytes_available) break; if (!bytes_available) break;
if (!hci_transport_em9304_spi_rx_len) break; if (!hci_transport_em9304_spi_bytes_to_read) break;
int bytes_to_copy = btstack_min(bytes_available, hci_transport_em9304_spi_rx_len); uint16_t bytes_to_copy = btstack_min(bytes_available, hci_transport_em9304_spi_bytes_to_read);
em9304_engine_get_bytes(hci_transport_em9304_spi_rx_buffer, bytes_to_copy); em9304_engine_get_bytes(&hci_packet[hci_transport_em9304_spi_read_pos], bytes_to_copy);
hci_transport_em9304_spi_rx_buffer += bytes_to_copy; hci_transport_em9304_spi_read_pos += bytes_to_copy;
hci_transport_em9304_spi_rx_len -= bytes_to_copy; hci_transport_em9304_spi_bytes_to_read -= bytes_to_copy;
if (hci_transport_em9304_spi_rx_len == 0){ if (hci_transport_em9304_spi_bytes_to_read == 0){
(*hci_transport_em9304_spi_block_read)(); hci_transport_em9304_spi_block_read();
break;
} }
} }
} }
static void em9304_spi_engine_receive_block(uint8_t *buffer, uint16_t length){
log_debug("em9304_spi_engine_receive_block: len %u, ring buffer has %u, UART_RX_LEN %u", length, btstack_ring_buffer_bytes_available(&em9304_spi_engine_rx_ring_buffer), hci_transport_em9304_spi_rx_len);
hci_transport_em9304_spi_rx_buffer = buffer;
hci_transport_em9304_spi_rx_len = length;
hci_transport_em9304_spi_process_data();
em9304_spi_engine_process();
}
static void hci_transport_em9304_spi_trigger_next_read(void){
// log_info("hci_transport_em9304_spi_trigger_next_read: %u bytes", bytes_to_read);
em9304_spi_engine_receive_block(&hci_packet[read_pos], bytes_to_read);
}
static void hci_transport_em9304_spi_block_read(void){ static void hci_transport_em9304_spi_block_read(void){
switch (hci_transport_em9304_h4_state) {
read_pos += bytes_to_read;
switch (h4_state) {
case H4_W4_PACKET_TYPE: case H4_W4_PACKET_TYPE:
switch (hci_packet[0]){ switch (hci_packet[0]){
case HCI_EVENT_PACKET: case HCI_EVENT_PACKET:
bytes_to_read = HCI_EVENT_HEADER_SIZE; hci_transport_em9304_spi_bytes_to_read = HCI_EVENT_HEADER_SIZE;
h4_state = H4_W4_EVENT_HEADER; hci_transport_em9304_h4_state = H4_W4_EVENT_HEADER;
break; break;
case HCI_ACL_DATA_PACKET: case HCI_ACL_DATA_PACKET:
bytes_to_read = HCI_ACL_HEADER_SIZE; hci_transport_em9304_spi_bytes_to_read = HCI_ACL_HEADER_SIZE;
h4_state = H4_W4_ACL_HEADER; hci_transport_em9304_h4_state = H4_W4_ACL_HEADER;
break; break;
default: default:
log_error("hci_transport_h4: invalid packet type 0x%02x", hci_packet[0]); log_error("invalid packet type 0x%02x", hci_packet[0]);
hci_transport_em9304_spi_reset_statemachine(); hci_transport_em9304_spi_reset_statemachine();
break; break;
} }
break; break;
case H4_W4_EVENT_HEADER: case H4_W4_EVENT_HEADER:
bytes_to_read = hci_packet[2]; hci_transport_em9304_spi_bytes_to_read = hci_packet[2];
h4_state = H4_W4_PAYLOAD; hci_transport_em9304_h4_state = H4_W4_PAYLOAD;
break; break;
case H4_W4_ACL_HEADER: case H4_W4_ACL_HEADER:
bytes_to_read = little_endian_read_16( hci_packet, 3); hci_transport_em9304_spi_bytes_to_read = little_endian_read_16( hci_packet, 3);
// check ACL length // check ACL length
if (HCI_ACL_HEADER_SIZE + bytes_to_read > HCI_PACKET_BUFFER_SIZE){ if (HCI_ACL_HEADER_SIZE + hci_transport_em9304_spi_bytes_to_read > HCI_PACKET_BUFFER_SIZE){
log_error("hci_transport_h4: invalid ACL payload len %d - only space for %u", bytes_to_read, HCI_PACKET_BUFFER_SIZE - HCI_ACL_HEADER_SIZE); log_error("invalid ACL payload len %d - only space for %u", hci_transport_em9304_spi_bytes_to_read, HCI_PACKET_BUFFER_SIZE - HCI_ACL_HEADER_SIZE);
hci_transport_em9304_spi_reset_statemachine(); hci_transport_em9304_spi_reset_statemachine();
break; break;
} }
h4_state = H4_W4_PAYLOAD; hci_transport_em9304_h4_state = H4_W4_PAYLOAD;
break; break;
case H4_W4_PAYLOAD: case H4_W4_PAYLOAD:
packet_handler(hci_packet[0], &hci_packet[1], read_pos-1); packet_handler(hci_packet[0], &hci_packet[1], hci_transport_em9304_spi_read_pos-1);
hci_transport_em9304_spi_reset_statemachine(); hci_transport_em9304_spi_reset_statemachine();
break; break;
default: default:
break; break;
} }
hci_transport_em9304_spi_trigger_next_read();
} }
static void hci_transport_em9304_spi_block_sent(void){ static void hci_transport_em9304_spi_block_sent(void){
@ -494,7 +475,6 @@ static int hci_transport_em9304_spi_open(void){
em9304_spi_engine_set_block_sent(&hci_transport_em9304_spi_block_sent); em9304_spi_engine_set_block_sent(&hci_transport_em9304_spi_block_sent);
// setup H4 RX // setup H4 RX
hci_transport_em9304_spi_reset_statemachine(); hci_transport_em9304_spi_reset_statemachine();
hci_transport_em9304_spi_trigger_next_read();
// setup H4 TX // setup H4 TX
tx_state = TX_IDLE; tx_state = TX_IDLE;
return 0; return 0;