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_transport.h"
static void em9304_spi_engine_process(void);
static void em9304_spi_engine_run(void);
#define STS_SLAVE_READY 0xc0
@ -64,7 +64,8 @@ static void em9304_spi_engine_process(void);
// state
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_READ_COMMAND_SENT,
SPI_EM9304_RX_W4_STS2_RECEIVED,
@ -78,6 +79,7 @@ static volatile enum {
SPI_EM9304_TX_STS2_RECEIVED,
SPI_EM9304_TX_W4_DATA_SENT,
SPI_EM9304_TX_DATA_SENT,
SPI_EM9304_DONE,
} em9304_spi_engine_state;
static uint16_t em9304_spi_engine_rx_request_len;
@ -110,7 +112,8 @@ union {
} em9304_spi_engine_spi_rx_buffer;
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){
@ -136,7 +139,7 @@ static void em9304_spi_engine_transfer_done(void){
default:
return;
}
em9304_spi_engine_process();
em9304_spi_engine_run();
}
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;
}
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()){
// RDY -> data available
@ -173,22 +182,21 @@ static void em9304_engine_idle(void){
btstack_em9304_spi->transmit(sCommand.bytes, 1);
}
} else if (em9304_spi_engine_tx_size){
// start TX
em9304_spi_engine_start_tx_transaction();
} else if (em9304_engine_space_in_rx_buffer()){
// no data ready for receive or transmit, but space in rx ringbuffer -> enable READY IRQ
btstack_em9304_spi->set_ready_callback(&em9304_spi_engine_ready_callback);
em9304_engine_receive_buffer_ready();
}
}
static void em9304_spi_engine_process(void){
uint16_t max_bytes_to_send;
static void em9304_engine_action_done(void){
// 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){
case SPI_EM9304_IDLE:
em9304_engine_idle();
break;
case SPI_EM9304_RX_READ_COMMAND_SENT:
em9304_spi_engine_state = SPI_EM9304_RX_W4_STS2_RECEIVED;
@ -199,27 +207,25 @@ static void em9304_spi_engine_process(void){
// check slave status
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_rx_request_len = sStas.bytes[0];
btstack_em9304_spi->receive(em9304_spi_engine_spi_rx_buffer.bytes, em9304_spi_engine_rx_request_len);
break;
case SPI_EM9304_RX_DATA_RECEIVED:
// chip deselect & done
btstack_em9304_spi->set_chip_select(0);
em9304_spi_engine_state = SPI_EM9304_IDLE;
// done
em9304_engine_action_done();
// 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);
em9304_spi_engine_rx_request_len = 0;
// deliver new data
// notify about new data available -- assume empty
(*em9304_spi_engine_rx_available_handler)();
// idle, look for more work
em9304_engine_idle();
// next
em9304_engine_start_next_transaction();
break;
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]);
max_bytes_to_send = sStas.bytes[0];
if (max_bytes_to_send == 0){
// chip deselect & retry
btstack_em9304_spi->set_chip_select(0);
em9304_spi_engine_state = SPI_EM9304_IDLE;
// done
em9304_engine_action_done();
// next
em9304_engine_start_next_transaction();
break;
}
@ -260,27 +267,21 @@ static void em9304_spi_engine_process(void){
break;
case SPI_EM9304_TX_DATA_SENT:
// done
em9304_engine_action_done();
// chip deselect & done
btstack_em9304_spi->set_chip_select(0);
em9304_spi_engine_state = SPI_EM9304_IDLE;
// chunk processed
// chunk sent
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_request_len = 0;
// handle TX Complete
if (em9304_spi_engine_tx_size){
// more data to send
em9304_spi_engine_start_tx_transaction();
} else {
// notify higher layer
// notify higher layer when complete
if (em9304_spi_engine_tx_size == 0){
(*em9304_spi_engine_tx_done_handler)();
// idle, look for more work
em9304_engine_idle();
}
// next
em9304_engine_start_next_transaction();
break;
default:
@ -292,6 +293,8 @@ static void em9304_spi_engine_init(void){
btstack_em9304_spi->open();
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);
em9304_spi_engine_state = SPI_EM9304_DONE;
em9304_engine_start_next_transaction();
}
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){
em9304_spi_engine_tx_data = buffer;
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);
}
@ -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);
}
//////////////////////////////////////////////////////////////////////////////
// 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;
// packet reader state machine
static H4_STATE h4_state;
static int bytes_to_read;
static int read_pos;
static H4_STATE hci_transport_em9304_h4_state;
static uint16_t hci_transport_em9304_spi_bytes_to_read;
static uint16_t hci_transport_em9304_spi_read_pos;
// 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 = &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_reset_statemachine(void){
h4_state = H4_W4_PACKET_TYPE;
read_pos = 0;
bytes_to_read = 1;
hci_transport_em9304_h4_state = H4_W4_PACKET_TYPE;
hci_transport_em9304_spi_read_pos = 0;
hci_transport_em9304_spi_bytes_to_read = 1;
}
static void hci_transport_em9304_spi_process_data(void){
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 (!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);
em9304_engine_get_bytes(hci_transport_em9304_spi_rx_buffer, bytes_to_copy);
uint16_t bytes_to_copy = btstack_min(bytes_available, hci_transport_em9304_spi_bytes_to_read);
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_rx_len -= bytes_to_copy;
hci_transport_em9304_spi_read_pos += bytes_to_copy;
hci_transport_em9304_spi_bytes_to_read -= bytes_to_copy;
if (hci_transport_em9304_spi_rx_len == 0){
(*hci_transport_em9304_spi_block_read)();
break;
if (hci_transport_em9304_spi_bytes_to_read == 0){
hci_transport_em9304_spi_block_read();
}
}
}
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){
read_pos += bytes_to_read;
switch (h4_state) {
switch (hci_transport_em9304_h4_state) {
case H4_W4_PACKET_TYPE:
switch (hci_packet[0]){
case HCI_EVENT_PACKET:
bytes_to_read = HCI_EVENT_HEADER_SIZE;
h4_state = H4_W4_EVENT_HEADER;
hci_transport_em9304_spi_bytes_to_read = HCI_EVENT_HEADER_SIZE;
hci_transport_em9304_h4_state = H4_W4_EVENT_HEADER;
break;
case HCI_ACL_DATA_PACKET:
bytes_to_read = HCI_ACL_HEADER_SIZE;
h4_state = H4_W4_ACL_HEADER;
hci_transport_em9304_spi_bytes_to_read = HCI_ACL_HEADER_SIZE;
hci_transport_em9304_h4_state = H4_W4_ACL_HEADER;
break;
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();
break;
}
break;
case H4_W4_EVENT_HEADER:
bytes_to_read = hci_packet[2];
h4_state = H4_W4_PAYLOAD;
hci_transport_em9304_spi_bytes_to_read = hci_packet[2];
hci_transport_em9304_h4_state = H4_W4_PAYLOAD;
break;
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
if (HCI_ACL_HEADER_SIZE + 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);
if (HCI_ACL_HEADER_SIZE + hci_transport_em9304_spi_bytes_to_read > HCI_PACKET_BUFFER_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();
break;
}
h4_state = H4_W4_PAYLOAD;
hci_transport_em9304_h4_state = H4_W4_PAYLOAD;
break;
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();
break;
default:
break;
}
hci_transport_em9304_spi_trigger_next_read();
}
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);
// setup H4 RX
hci_transport_em9304_spi_reset_statemachine();
hci_transport_em9304_spi_trigger_next_read();
// setup H4 TX
tx_state = TX_IDLE;
return 0;