packet oriented approach
This commit is contained in:
parent
e2a6ca7035
commit
fe70ee1c86
532
src/main.c
532
src/main.c
|
@ -53,6 +53,9 @@ NET_BUF_POOL_DEFINE(acl_tx_pool, TX_BUF_COUNT, BT_BUF_ACL_SIZE,
|
||||||
static BT_STACK_NOINIT(tx_stack, 256);
|
static BT_STACK_NOINIT(tx_stack, 256);
|
||||||
static struct k_thread tx_thread_data;
|
static struct k_thread tx_thread_data;
|
||||||
|
|
||||||
|
static BT_STACK_NOINIT(unproc_stack, 256);
|
||||||
|
static struct k_thread unproc_thread_data;
|
||||||
|
|
||||||
static struct k_delayed_work ack_work;
|
static struct k_delayed_work ack_work;
|
||||||
static struct k_delayed_work retx_work;
|
static struct k_delayed_work retx_work;
|
||||||
|
|
||||||
|
@ -103,11 +106,12 @@ static bool reliable_packet(u8_t type)
|
||||||
((hdr)[2] |= (len) >> 4))
|
((hdr)[2] |= (len) >> 4))
|
||||||
|
|
||||||
static struct h5 {
|
static struct h5 {
|
||||||
struct net_buf *rx_buf;
|
//struct net_buf *rx_buf;
|
||||||
|
|
||||||
struct k_fifo tx_queue;
|
struct k_fifo controller_queue;
|
||||||
struct k_fifo rx_queue;
|
struct k_fifo host_queue;
|
||||||
struct k_fifo unack_queue;
|
struct k_fifo unack_queue;
|
||||||
|
struct k_fifo unprocessed_queue;
|
||||||
|
|
||||||
u8_t tx_win;
|
u8_t tx_win;
|
||||||
u8_t tx_ack;
|
u8_t tx_ack;
|
||||||
|
@ -131,18 +135,25 @@ static struct h5 {
|
||||||
|
|
||||||
static u8_t unack_queue_len;
|
static u8_t unack_queue_len;
|
||||||
|
|
||||||
|
#define MAX_PACKETS_IN_FLIGHT (0x01)
|
||||||
|
|
||||||
static const u8_t sync_req[] = { 0x01, 0x7e };
|
static const u8_t sync_req[] = { 0x01, 0x7e };
|
||||||
static const u8_t sync_rsp[] = { 0x02, 0x7d };
|
static const u8_t sync_rsp[] = { 0x02, 0x7d };
|
||||||
/* Third byte may change */
|
/* Third byte may change */
|
||||||
static u8_t conf_req[] = { 0x03, 0xfc };
|
static u8_t conf_req[] = { 0x03, 0xfc };
|
||||||
static const u8_t conf_rsp[] = { 0x04, 0x7b, 0x4 };
|
static const u8_t conf_rsp[] = { 0x04, 0x7b, MAX_PACKETS_IN_FLIGHT };
|
||||||
|
|
||||||
/* H5 signal buffers pool */
|
/* H5 signal buffers pool */
|
||||||
#define MAX_SIG_LEN 3
|
#define MAX_SIG_LEN 3
|
||||||
#define SIGNAL_COUNT 2
|
#define SIGNAL_COUNT 10
|
||||||
#define SIG_BUF_SIZE (CONFIG_BT_HCI_RESERVE + MAX_SIG_LEN)
|
#define SIG_BUF_SIZE (CONFIG_BT_HCI_RESERVE + MAX_SIG_LEN)
|
||||||
NET_BUF_POOL_DEFINE(h5_pool, SIGNAL_COUNT, SIG_BUF_SIZE, 0, NULL);
|
NET_BUF_POOL_DEFINE(h5_pool, SIGNAL_COUNT, SIG_BUF_SIZE, 0, NULL);
|
||||||
|
|
||||||
|
/* H5 Packet Buf */
|
||||||
|
#define MAX_PACKET_LEN 255 // CMD Header + 255 max payload
|
||||||
|
#define PACKET_BUF_SIZE (CONFIG_BT_HCI_RESERVE + MAX_PACKET_LEN)
|
||||||
|
NET_BUF_POOL_DEFINE(h5_pack_pool, MAX_PACKETS_IN_FLIGHT + 10, PACKET_BUF_SIZE, 0, NULL);
|
||||||
|
|
||||||
static inline void bt_uart_drain(struct device *dev)
|
static inline void bt_uart_drain(struct device *dev)
|
||||||
{
|
{
|
||||||
u8_t c;
|
u8_t c;
|
||||||
|
@ -152,46 +163,6 @@ static inline void bt_uart_drain(struct device *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void h5_reset_rx(void)
|
|
||||||
{
|
|
||||||
SYS_LOG_DBG("Reset");
|
|
||||||
if (h5.rx_buf) {
|
|
||||||
net_buf_unref(h5.rx_buf);
|
|
||||||
h5.rx_buf = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5.rx_state = START;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int h5_unslip_byte(u8_t *byte)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
|
|
||||||
if (*byte != SLIP_ESC) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_LOG_DBG("ESCAPE\n");
|
|
||||||
|
|
||||||
do {
|
|
||||||
count = uart_fifo_read(hci_uart_dev, byte, sizeof(*byte));
|
|
||||||
} while (!count);
|
|
||||||
|
|
||||||
switch (*byte) {
|
|
||||||
case SLIP_ESC_DELIM:
|
|
||||||
*byte = SLIP_DELIMITER;
|
|
||||||
break;
|
|
||||||
case SLIP_ESC_ESC:
|
|
||||||
*byte = SLIP_ESC;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SYS_LOG_ERR("Invalid escape byte %x\n", *byte);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void process_unack(void)
|
static void process_unack(void)
|
||||||
{
|
{
|
||||||
u8_t next_seq = h5.tx_seq;
|
u8_t next_seq = h5.tx_seq;
|
||||||
|
@ -235,7 +206,7 @@ static void process_unack(void)
|
||||||
/* TODO: print or do something with packet */
|
/* TODO: print or do something with packet */
|
||||||
SYS_LOG_DBG("Remove buf from the unack_queue");
|
SYS_LOG_DBG("Remove buf from the unack_queue");
|
||||||
|
|
||||||
net_buf_unref(buf);
|
//net_buf_unref(buf);
|
||||||
unack_queue_len--;
|
unack_queue_len--;
|
||||||
number_removed--;
|
number_removed--;
|
||||||
}
|
}
|
||||||
|
@ -308,7 +279,7 @@ void h5_send(const u8_t *payload, u8_t type, int len)
|
||||||
u8_t hdr[4];
|
u8_t hdr[4];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
hexdump("To Host <= ", payload, len);
|
//hexdump("To Host <= ", payload, len);
|
||||||
|
|
||||||
memset(hdr, 0, sizeof(hdr));
|
memset(hdr, 0, sizeof(hdr));
|
||||||
|
|
||||||
|
@ -328,7 +299,7 @@ void h5_send(const u8_t *payload, u8_t type, int len)
|
||||||
/* Calculate CRC */
|
/* Calculate CRC */
|
||||||
hdr[3] = ~((hdr[0] + hdr[1] + hdr[2]) & 0xff);
|
hdr[3] = ~((hdr[0] + hdr[1] + hdr[2]) & 0xff);
|
||||||
|
|
||||||
h5_print_header(hdr, "TX: <");
|
//h5_print_header(hdr, "TX: <");
|
||||||
|
|
||||||
uart_poll_out(hci_uart_dev, SLIP_DELIMITER);
|
uart_poll_out(hci_uart_dev, SLIP_DELIMITER);
|
||||||
|
|
||||||
|
@ -357,21 +328,21 @@ static void retx_timeout(struct k_work *work)
|
||||||
k_fifo_init(&tmp_queue);
|
k_fifo_init(&tmp_queue);
|
||||||
|
|
||||||
/* Queue to temperary queue */
|
/* Queue to temperary queue */
|
||||||
while ((buf = net_buf_get(&h5.tx_queue, K_NO_WAIT))) {
|
while ((buf = net_buf_get(&h5.host_queue, K_NO_WAIT))) {
|
||||||
net_buf_put(&tmp_queue, buf);
|
net_buf_put(&tmp_queue, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Queue unack packets to the beginning of the queue */
|
/* Queue unack packets to the beginning of the queue */
|
||||||
while ((buf = net_buf_get(&h5.unack_queue, K_NO_WAIT))) {
|
while ((buf = net_buf_get(&h5.unack_queue, K_NO_WAIT))) {
|
||||||
/* include also packet type */
|
/* include also packet type */
|
||||||
net_buf_put(&h5.tx_queue, buf);
|
net_buf_put(&h5.host_queue, buf);
|
||||||
h5.tx_seq = (h5.tx_seq - 1) & 0x07;
|
h5.tx_seq = (h5.tx_seq - 1) & 0x07;
|
||||||
unack_queue_len--;
|
unack_queue_len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Queue saved packets from temp queue */
|
/* Queue saved packets from temp queue */
|
||||||
while ((buf = net_buf_get(&tmp_queue, K_NO_WAIT))) {
|
while ((buf = net_buf_get(&tmp_queue, K_NO_WAIT))) {
|
||||||
net_buf_put(&h5.tx_queue, buf);
|
net_buf_put(&h5.host_queue, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,13 +360,157 @@ static void ack_timeout(struct k_work *work)
|
||||||
//STACK_ANALYZE("rx_stack", rx_stack);
|
//STACK_ANALYZE("rx_stack", rx_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void h5_process_complete_packet(u8_t *hdr)
|
int unslip_next_byte(struct net_buf *buf) {
|
||||||
|
if (!buf->len) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
u8_t next = net_buf_pull_u8(buf);
|
||||||
|
if (next != SLIP_ESC) {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
if (!buf->len) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
next = net_buf_pull_u8(buf);
|
||||||
|
if (next == SLIP_ESC_ESC) {
|
||||||
|
return SLIP_ESC;
|
||||||
|
}
|
||||||
|
if (next == SLIP_ESC_DELIM) {
|
||||||
|
return SLIP_DELIMITER;
|
||||||
|
}
|
||||||
|
SYS_LOG_WRN("Bad Escape Seqence: %02X %02X", SLIP_ESC, next);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_uart_isr(struct device *unused)
|
||||||
{
|
{
|
||||||
|
static u8_t byte;
|
||||||
|
static struct net_buf *buf = NULL;
|
||||||
|
|
||||||
|
ARG_UNUSED(unused);
|
||||||
|
|
||||||
|
while (uart_irq_update(hci_uart_dev) &&
|
||||||
|
uart_irq_is_pending(hci_uart_dev)) {
|
||||||
|
|
||||||
|
if (!uart_irq_rx_ready(hci_uart_dev)) {
|
||||||
|
/* Only the UART RX path is interrupt-enabled */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
buf = net_buf_alloc(&h5_pack_pool, K_NO_WAIT);
|
||||||
|
if (!buf) {
|
||||||
|
bt_uart_drain(hci_uart_dev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SYS_LOG_DBG("ALLOC %p", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uart_fifo_read(hci_uart_dev, &byte, sizeof(byte))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (byte == SLIP_DELIMITER) {
|
||||||
|
if (buf->len > 0) {
|
||||||
|
net_buf_put(&h5.unprocessed_queue, buf);
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
net_buf_add_u8(buf, byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pull_header(struct net_buf *buf, u8_t *hdr) {
|
||||||
|
// Packet too short to contain an h5 header
|
||||||
|
if (buf->len < 4) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u8_t i = 0; i < 4; i++) {
|
||||||
|
int byte = unslip_next_byte(buf);
|
||||||
|
if (byte < 0) {
|
||||||
|
// Packet too short due to escaped bytes
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
hdr[i] = byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checksum
|
||||||
|
if (((hdr[3] + hdr[0] + hdr[1] + hdr[2]) & 0xff) != 0xff) {
|
||||||
|
SYS_LOG_WRN("Invalid Header Checksum\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unproc_thread(void) {
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
|
|
||||||
//SYS_LOG_DBG("");
|
while (true) {
|
||||||
|
buf = net_buf_get(&h5.unprocessed_queue, K_FOREVER);
|
||||||
|
//hexdump("Packet: ", buf->data, buf->len);
|
||||||
|
|
||||||
|
u8_t hdr[4];
|
||||||
|
if (pull_header(buf, hdr) < 0) {
|
||||||
|
// Header is invalid
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct net_buf *rx_buf = NULL;
|
||||||
|
|
||||||
|
switch (H5_HDR_PKT_TYPE(hdr)) {
|
||||||
|
case HCI_ACLDATA_PKT:
|
||||||
|
rx_buf = net_buf_alloc(&acl_tx_pool, K_NO_WAIT);
|
||||||
|
if (!rx_buf) {
|
||||||
|
SYS_LOG_WRN("No available data buffers");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bt_buf_set_type(rx_buf, BT_BUF_ACL_OUT);
|
||||||
|
break;
|
||||||
|
case HCI_COMMAND_PKT:
|
||||||
|
rx_buf = net_buf_alloc(&cmd_tx_pool, K_NO_WAIT);
|
||||||
|
if (!rx_buf) {
|
||||||
|
SYS_LOG_WRN("No available data buffers");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bt_buf_set_type(rx_buf, BT_BUF_CMD);
|
||||||
|
break;
|
||||||
|
case HCI_3WIRE_LINK_PKT:
|
||||||
|
case HCI_3WIRE_ACK_PKT:
|
||||||
|
rx_buf = net_buf_alloc(&h5_pool, K_NO_WAIT);
|
||||||
|
if (!rx_buf) {
|
||||||
|
SYS_LOG_WRN("No available signal buffers");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SYS_LOG_ERR("Wrong packet type from host: %u", H5_HDR_PKT_TYPE(hdr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int byte;
|
||||||
|
while ((byte = unslip_next_byte(buf)) >= 0) {
|
||||||
|
net_buf_add_u8(rx_buf, (u8_t) byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (H5_HDR_LEN(hdr) != rx_buf->len) {
|
||||||
|
SYS_LOG_ERR("Payload too short\n");
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
//h5_print_header(hdr, "From Host =>");
|
||||||
|
//hexdump("\tDecoded: ", rx_buf->data, rx_buf->len);
|
||||||
|
/* Check when full packet is received, it can be done
|
||||||
|
* when parsing packet header but we need to receive
|
||||||
|
* full packet anyway to clear UART.
|
||||||
|
*/
|
||||||
|
if (H5_HDR_RELIABLE(hdr) &&
|
||||||
|
H5_HDR_SEQ(hdr) != h5.tx_ack) {
|
||||||
|
SYS_LOG_ERR("Seq expected %u got %u. Drop packet", h5.tx_ack,
|
||||||
|
H5_HDR_SEQ(hdr));
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
/* rx_ack should be in every packet */
|
|
||||||
h5.rx_ack = H5_HDR_ACK(hdr);
|
h5.rx_ack = H5_HDR_ACK(hdr);
|
||||||
|
|
||||||
if (reliable_packet(H5_HDR_PKT_TYPE(hdr))) {
|
if (reliable_packet(H5_HDR_PKT_TYPE(hdr))) {
|
||||||
|
@ -405,202 +520,33 @@ static void h5_process_complete_packet(u8_t *hdr)
|
||||||
k_delayed_work_submit(&ack_work, H5_RX_ACK_TIMEOUT);
|
k_delayed_work_submit(&ack_work, H5_RX_ACK_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
h5_print_header(hdr, "From Host =>");
|
//process_unack();
|
||||||
|
|
||||||
process_unack();
|
|
||||||
|
|
||||||
buf = h5.rx_buf;
|
|
||||||
h5.rx_buf = NULL;
|
|
||||||
|
|
||||||
switch (H5_HDR_PKT_TYPE(hdr)) {
|
switch (H5_HDR_PKT_TYPE(hdr)) {
|
||||||
case HCI_3WIRE_ACK_PKT:
|
case HCI_3WIRE_ACK_PKT:
|
||||||
net_buf_unref(buf);
|
// No further action required
|
||||||
break;
|
break;
|
||||||
case HCI_3WIRE_LINK_PKT:
|
case HCI_3WIRE_LINK_PKT:
|
||||||
net_buf_put(&h5.rx_queue, buf);
|
net_buf_put(&h5.host_queue, rx_buf);
|
||||||
break;
|
break;
|
||||||
case HCI_COMMAND_PKT:
|
case HCI_COMMAND_PKT:
|
||||||
case HCI_ACLDATA_PKT:
|
case HCI_ACLDATA_PKT:
|
||||||
hexdump("HOST -> TX_QUEUE: ", buf->data, buf->len);
|
//SYS_LOG_DBG("Adding to controller queue\n");
|
||||||
net_buf_put(&h5.tx_queue, buf);
|
net_buf_put(&h5.controller_queue, rx_buf);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SYS_LOG_WRN("Unknown packet type %u\n", H5_HDR_PKT_TYPE(hdr));
|
SYS_LOG_WRN("Unknown packet type %u\n", H5_HDR_PKT_TYPE(hdr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
next:
|
||||||
|
SYS_LOG_DBG("UNREF: %p", buf);
|
||||||
void bt_uart_isr(struct device *unused)
|
net_buf_unref(buf);
|
||||||
{
|
|
||||||
static int remaining;
|
|
||||||
u8_t byte;
|
|
||||||
int ret;
|
|
||||||
static u8_t hdr[4];
|
|
||||||
|
|
||||||
ARG_UNUSED(unused);
|
|
||||||
|
|
||||||
while (uart_irq_update(hci_uart_dev) &&
|
|
||||||
uart_irq_is_pending(hci_uart_dev)) {
|
|
||||||
|
|
||||||
if (!uart_irq_rx_ready(hci_uart_dev)) {
|
|
||||||
if (uart_irq_tx_ready(hci_uart_dev)) {
|
|
||||||
SYS_LOG_DBG("transmit ready");
|
|
||||||
} else {
|
|
||||||
SYS_LOG_DBG("spurious interrupt");
|
|
||||||
}
|
|
||||||
/* Only the UART RX path is interrupt-enabled */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = uart_fifo_read(hci_uart_dev, &byte, sizeof(byte));
|
|
||||||
SYS_LOG_DBG("BYTE: %02X, STATE: %02X", byte, h5.rx_state);
|
|
||||||
if (!ret) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (h5.rx_state) {
|
|
||||||
case START:
|
|
||||||
if (byte == SLIP_DELIMITER) {
|
|
||||||
h5.rx_state = HEADER;
|
|
||||||
remaining = sizeof(hdr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HEADER:
|
|
||||||
/* In a case we confuse ending slip delimeter
|
|
||||||
* with starting one.
|
|
||||||
*/
|
|
||||||
if (byte == SLIP_DELIMITER) {
|
|
||||||
remaining = sizeof(hdr);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (h5_unslip_byte(&byte) < 0) {
|
|
||||||
h5_reset_rx();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&hdr[sizeof(hdr) - remaining], &byte, 1);
|
|
||||||
remaining--;
|
|
||||||
|
|
||||||
if (remaining) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
remaining = H5_HDR_LEN(hdr);
|
|
||||||
SYS_LOG_DBG("Payload len: %u", remaining);
|
|
||||||
switch (H5_HDR_PKT_TYPE(hdr)) {
|
|
||||||
case HCI_ACLDATA_PKT:
|
|
||||||
h5.rx_buf = net_buf_alloc(&acl_tx_pool, K_NO_WAIT);
|
|
||||||
if (!h5.rx_buf) {
|
|
||||||
SYS_LOG_WRN("No available data buffers");
|
|
||||||
h5_reset_rx();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bt_buf_set_type(h5.rx_buf, BT_BUF_ACL_OUT);
|
|
||||||
h5.rx_state = PAYLOAD;
|
|
||||||
break;
|
|
||||||
case HCI_COMMAND_PKT:
|
|
||||||
h5.rx_buf = net_buf_alloc(&cmd_tx_pool, K_NO_WAIT);
|
|
||||||
if (!h5.rx_buf) {
|
|
||||||
SYS_LOG_WRN("No available data buffers");
|
|
||||||
h5_reset_rx();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bt_buf_set_type(h5.rx_buf, BT_BUF_CMD);
|
|
||||||
h5.rx_state = PAYLOAD;
|
|
||||||
break;
|
|
||||||
case HCI_3WIRE_LINK_PKT:
|
|
||||||
case HCI_3WIRE_ACK_PKT:
|
|
||||||
h5.rx_buf = net_buf_alloc(&h5_pool, K_NO_WAIT);
|
|
||||||
if (!h5.rx_buf) {
|
|
||||||
SYS_LOG_WRN("No available signal buffers");
|
|
||||||
h5_reset_rx();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
h5.rx_state = PAYLOAD;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
SYS_LOG_ERR("Wrong packet type %u", H5_HDR_PKT_TYPE(hdr));
|
|
||||||
h5.rx_state = END;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PAYLOAD:
|
|
||||||
if (h5_unslip_byte(&byte) < 0) {
|
|
||||||
SYS_LOG_WRN("Slip error\n");
|
|
||||||
h5_reset_rx();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_buf_add_u8(h5.rx_buf, byte);
|
|
||||||
remaining--;
|
|
||||||
SYS_LOG_DBG("Payload remaining: %u", remaining);
|
|
||||||
if (!remaining) {
|
|
||||||
h5.rx_state = END;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case END:
|
|
||||||
if (byte != SLIP_DELIMITER) {
|
|
||||||
SYS_LOG_ERR("Missing ending SLIP_DELIMITER");
|
|
||||||
h5_reset_rx();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_LOG_DBG("Received full packet: type %u",
|
|
||||||
H5_HDR_PKT_TYPE(hdr));
|
|
||||||
|
|
||||||
/* Check when full packet is received, it can be done
|
|
||||||
* when parsing packet header but we need to receive
|
|
||||||
* full packet anyway to clear UART.
|
|
||||||
*/
|
|
||||||
if (H5_HDR_RELIABLE(hdr) &&
|
|
||||||
H5_HDR_SEQ(hdr) != h5.tx_ack) {
|
|
||||||
SYS_LOG_ERR("Seq expected %u got %u. Drop packet",
|
|
||||||
h5.tx_ack, H5_HDR_SEQ(hdr));
|
|
||||||
h5_reset_rx();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5_process_complete_packet(hdr);
|
|
||||||
h5.rx_state = START;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
u8_t h5_get_type(struct net_buf *buf)
|
|
||||||
{
|
|
||||||
return net_buf_pull_u8(buf) & 0xf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*static int h5_queue(struct net_buf *buf)
|
|
||||||
{
|
|
||||||
u8_t type;
|
|
||||||
|
|
||||||
BT_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
|
|
||||||
|
|
||||||
switch (bt_buf_get_type(buf)) {
|
|
||||||
case BT_BUF_CMD:
|
|
||||||
type = HCI_COMMAND_PKT;
|
|
||||||
break;
|
|
||||||
case BT_BUF_ACL_OUT:
|
|
||||||
type = HCI_ACLDATA_PKT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BT_ERR("Unknown packet type %u", bt_buf_get_type(buf));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(net_buf_push(buf, sizeof(type)), &type, sizeof(type));
|
|
||||||
|
|
||||||
net_buf_put(&h5.tx_queue, buf);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
static void tx_thread(void)
|
static void tx_thread(void)
|
||||||
{
|
{
|
||||||
SYS_LOG_DBG("");
|
SYS_LOG_DBG("TX Thread is alive.");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
|
@ -609,25 +555,26 @@ static void tx_thread(void)
|
||||||
|
|
||||||
switch (h5.link_state) {
|
switch (h5.link_state) {
|
||||||
case UNINIT:
|
case UNINIT:
|
||||||
/* FIXME: send sync */
|
|
||||||
k_sleep(100);
|
|
||||||
break;
|
|
||||||
case INIT:
|
case INIT:
|
||||||
/* FIXME: send conf */
|
/* FIXME: send conf */
|
||||||
k_sleep(100);
|
k_sleep(250);
|
||||||
break;
|
break;
|
||||||
case ACTIVE:
|
case ACTIVE:
|
||||||
buf = net_buf_get(&h5.tx_queue, K_FOREVER);
|
buf = net_buf_get(&h5.controller_queue, K_MSEC(250));
|
||||||
|
if (!buf) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
hexdump("TX_QUEUE -> CTRL", buf->data, buf->len);
|
hexdump("TX_QUEUE -> CTRL", buf->data, buf->len);
|
||||||
bt_send(buf);
|
bt_send(buf);
|
||||||
|
|
||||||
/* buf is dequeued from tx_queue and queued to unack
|
/* buf is dequeued from tx_queue and queued to unack
|
||||||
* queue.
|
* queue.
|
||||||
*/
|
*/
|
||||||
net_buf_put(&h5.unack_queue, buf);
|
|
||||||
unack_queue_len++;
|
|
||||||
|
|
||||||
k_delayed_work_submit(&retx_work, H5_TX_ACK_TIMEOUT);
|
//net_buf_put(&h5.unack_queue, buf);
|
||||||
|
//unack_queue_len++;
|
||||||
|
|
||||||
|
//k_delayed_work_submit(&retx_work, H5_TX_ACK_TIMEOUT);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -643,14 +590,14 @@ static void h5_init(void)
|
||||||
h5.tx_win = 4;
|
h5.tx_win = 4;
|
||||||
|
|
||||||
/* TX thread */
|
/* TX thread */
|
||||||
k_fifo_init(&h5.tx_queue);
|
k_fifo_init(&h5.controller_queue);
|
||||||
k_thread_create(&tx_thread_data, tx_stack,
|
k_thread_create(&tx_thread_data, tx_stack,
|
||||||
K_THREAD_STACK_SIZEOF(tx_stack),
|
K_THREAD_STACK_SIZEOF(tx_stack),
|
||||||
(k_thread_entry_t)tx_thread, NULL, NULL, NULL,
|
(k_thread_entry_t)tx_thread, NULL, NULL, NULL,
|
||||||
K_PRIO_COOP(CONFIG_BT_HCI_TX_PRIO),
|
K_PRIO_COOP(CONFIG_BT_HCI_TX_PRIO),
|
||||||
0, K_NO_WAIT);
|
0, K_NO_WAIT);
|
||||||
|
|
||||||
k_fifo_init(&h5.rx_queue);
|
k_fifo_init(&h5.host_queue);
|
||||||
/*k_thread_create(&rx_thread_data, rx_stack,
|
/*k_thread_create(&rx_thread_data, rx_stack,
|
||||||
K_THREAD_STACK_SIZEOF(rx_stack),
|
K_THREAD_STACK_SIZEOF(rx_stack),
|
||||||
(k_thread_entry_t)rx_thread, NULL, NULL, NULL,
|
(k_thread_entry_t)rx_thread, NULL, NULL, NULL,
|
||||||
|
@ -660,6 +607,14 @@ static void h5_init(void)
|
||||||
/* Unack queue */
|
/* Unack queue */
|
||||||
k_fifo_init(&h5.unack_queue);
|
k_fifo_init(&h5.unack_queue);
|
||||||
|
|
||||||
|
/* Thread & queue to un-slip and un-h5 incoming packets */
|
||||||
|
k_fifo_init(&h5.unprocessed_queue);
|
||||||
|
k_thread_create(&unproc_thread_data, unproc_stack,
|
||||||
|
K_THREAD_STACK_SIZEOF(unproc_stack),
|
||||||
|
(k_thread_entry_t)unproc_thread, NULL, NULL, NULL,
|
||||||
|
K_PRIO_COOP(CONFIG_BT_RX_PRIO),
|
||||||
|
0, K_NO_WAIT);
|
||||||
|
|
||||||
/* Init delayed work */
|
/* Init delayed work */
|
||||||
k_delayed_work_init(&ack_work, ack_timeout);
|
k_delayed_work_init(&ack_work, ack_timeout);
|
||||||
k_delayed_work_init(&retx_work, retx_timeout);
|
k_delayed_work_init(&retx_work, retx_timeout);
|
||||||
|
@ -739,71 +694,100 @@ void bt_ctlr_assert_handle(char *file, u32_t line)
|
||||||
DEVICE_INIT(hci_uart, "hci_uart", &h5_open, NULL, NULL,
|
DEVICE_INIT(hci_uart, "hci_uart", &h5_open, NULL, NULL,
|
||||||
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|
||||||
|
|
||||||
|
bool _link_ctrl_memcmp(struct net_buf const * const buf, u8_t const * const ref) {
|
||||||
|
return !memcmp(buf->data, ref, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool packet_is_sync(struct net_buf *buf) {
|
||||||
|
return _link_ctrl_memcmp(buf, sync_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool packet_is_sync_response(struct net_buf *buf) {
|
||||||
|
return _link_ctrl_memcmp(buf, sync_rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool packet_is_config(struct net_buf *buf) {
|
||||||
|
return _link_ctrl_memcmp(buf, conf_req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool packet_is_config_response(struct net_buf *buf) {
|
||||||
|
return _link_ctrl_memcmp(buf, conf_rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _send_link_control(u8_t const * const buf, u8_t len) {
|
||||||
|
h5_send(buf, HCI_3WIRE_LINK_PKT, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void h5_send_sync(void) {
|
||||||
|
_send_link_control(sync_req, sizeof(sync_req));
|
||||||
|
}
|
||||||
|
static void h5_send_sync_response(void) {
|
||||||
|
_send_link_control(sync_rsp, sizeof(sync_rsp));
|
||||||
|
}
|
||||||
|
static void h5_send_config(void) {
|
||||||
|
_send_link_control(conf_req, sizeof(conf_req));
|
||||||
|
}
|
||||||
|
static void h5_send_config_response(void) {
|
||||||
|
_send_link_control(conf_rsp, sizeof(conf_rsp));
|
||||||
|
}
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
SYS_LOG_DBG("Start");
|
SYS_LOG_DBG("Start");
|
||||||
|
|
||||||
bt_enable_raw(&h5.rx_queue);
|
// Adds controller output to host output queue
|
||||||
|
bt_enable_raw(&h5.host_queue);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
|
|
||||||
buf = net_buf_get(&h5.rx_queue, K_FOREVER);
|
buf = net_buf_get(&h5.host_queue, K_FOREVER);
|
||||||
|
|
||||||
if (!memcmp(buf->data, sync_req, sizeof(sync_req))) {
|
if (packet_is_sync(buf)) {
|
||||||
SYS_LOG_DBG("Host sends SYNC\n");
|
|
||||||
h5.link_state = UNINIT;
|
h5.link_state = UNINIT;
|
||||||
|
h5_send_sync_response();
|
||||||
h5_send(sync_rsp, HCI_3WIRE_LINK_PKT, sizeof(sync_rsp));
|
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h5.link_state == UNINIT) {
|
if (h5.link_state == UNINIT) {
|
||||||
if (!memcmp(buf->data, sync_rsp, sizeof(sync_rsp))) {
|
if (packet_is_sync_response(buf)) {
|
||||||
SYS_LOG_DBG("Host sends SYNC_RESP\n");
|
|
||||||
h5.link_state = INIT;
|
h5.link_state = INIT;
|
||||||
h5_send(conf_req, HCI_3WIRE_LINK_PKT, sizeof(conf_req));
|
h5_send_config();
|
||||||
} else {
|
} else {
|
||||||
/* SYNC is the answer to any non-SYNC_RESP packets in UNINIT
|
/* SYNC is the answer to any non-SYNC_RESP packets in UNINIT
|
||||||
state */
|
state */
|
||||||
h5_send(sync_req, HCI_3WIRE_LINK_PKT, sizeof(sync_req));
|
h5_send_sync();
|
||||||
}
|
}
|
||||||
}
|
} else if (h5.link_state == INIT) {
|
||||||
|
if (packet_is_config(buf)) {
|
||||||
if (h5.link_state == INIT) {
|
h5_send_config_response();
|
||||||
if (!memcmp(buf->data, conf_req, 2)) {
|
} else if (packet_is_config_response(buf)) {
|
||||||
SYS_LOG_DBG("Host sends CONFIG\n");
|
|
||||||
h5_send(conf_rsp, HCI_3WIRE_LINK_PKT, sizeof(conf_rsp));
|
|
||||||
h5.tx_win = conf_rsp[2] & 0x7;
|
|
||||||
} else if (!memcmp(buf->data, conf_rsp, 2)) {
|
|
||||||
SYS_LOG_DBG("Host sends CONFIG_RESP\n");
|
|
||||||
h5.link_state = ACTIVE;
|
h5.link_state = ACTIVE;
|
||||||
|
h5.tx_win = conf_rsp[2] & 0x7;
|
||||||
h5.tx_seq = 0;
|
h5.tx_seq = 0;
|
||||||
h5.tx_ack = 0;
|
h5.tx_ack = 0;
|
||||||
SYS_LOG_DBG("Finished H5 configuration, tx_win %u", h5.tx_win);
|
SYS_LOG_DBG("Finished H5 configuration, tx_win %u", h5.tx_win);
|
||||||
}
|
}
|
||||||
}
|
} else if (h5.link_state == ACTIVE) {
|
||||||
|
if (packet_is_config(buf)) {
|
||||||
if (h5.link_state == ACTIVE) {
|
h5_send_config_response();
|
||||||
if (!memcmp(buf->data, conf_req, 2)) {
|
} else if (packet_is_config_response(buf)) {
|
||||||
SYS_LOG_DBG("Host sends CONFIG\n");
|
|
||||||
h5_send(conf_rsp, HCI_3WIRE_LINK_PKT, sizeof(conf_rsp));
|
|
||||||
h5.tx_win = conf_rsp[2] & 0x7;
|
|
||||||
goto next;
|
goto next;
|
||||||
} else if (!memcmp(buf->data, conf_rsp, 2)) {
|
} else if (packet_is_sync_response(buf) || packet_is_config(buf)) {
|
||||||
// Skip CONFIG_RESP in ACTIVE Mode
|
h5.link_state = UNINIT;
|
||||||
goto next;
|
h5_send_sync();
|
||||||
}
|
} else {
|
||||||
|
// Presumably something from the controller
|
||||||
u8_t type = bt_buf_get_type(buf);
|
u8_t type = bt_buf_get_type(buf);
|
||||||
if (type == BT_BUF_EVT) {
|
if (type == BT_BUF_EVT) {
|
||||||
SYS_LOG_DBG("EVENT from CTRL\n");
|
//hexdump("From CTRL To HOST => ", buf->data, buf->len);
|
||||||
hexdump("CTRL => rx_queue", buf->data, buf->len);
|
|
||||||
h5_send(buf->data, HCI_EVENT_PKT, buf->len);
|
h5_send(buf->data, HCI_EVENT_PKT, buf->len);
|
||||||
} else {
|
} else {
|
||||||
SYS_LOG_DBG("WTF is this (%u): ", bt_buf_get_type(buf));
|
SYS_LOG_DBG("WTF is this (%u): ", bt_buf_get_type(buf));
|
||||||
hexdump("CTRL WTF: ", buf->data, buf->len);
|
hexdump("CTRL WTF: ", buf->data, buf->len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
next:
|
next:
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue