summaryrefslogtreecommitdiff
path: root/src/libs/mynewt-nimble/nimble/transport/uart
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/mynewt-nimble/nimble/transport/uart')
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/uart/include/transport/uart/ble_hci_uart.h33
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/uart/pkg.yml38
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/uart/src/ble_hci_uart.c1187
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/uart/syscfg.yml72
4 files changed, 1330 insertions, 0 deletions
diff --git a/src/libs/mynewt-nimble/nimble/transport/uart/include/transport/uart/ble_hci_uart.h b/src/libs/mynewt-nimble/nimble/transport/uart/include/transport/uart/ble_hci_uart.h
new file mode 100644
index 00000000..e5e10841
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/uart/include/transport/uart/ble_hci_uart.h
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef H_BLE_HCI_UART_
+#define H_BLE_HCI_UART_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ble_hci_uart_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/mynewt-nimble/nimble/transport/uart/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/uart/pkg.yml
new file mode 100644
index 00000000..95681373
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/uart/pkg.yml
@@ -0,0 +1,38 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: nimble/transport/uart
+pkg.description: XXX
+pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+
+pkg.deps:
+ - "@apache-mynewt-core/hw/hal"
+ - "@apache-mynewt-core/kernel/os"
+ - "@apache-mynewt-core/util/mem"
+ - nimble
+
+pkg.apis:
+ - ble_transport
+
+pkg.init:
+ ble_hci_uart_init: 'MYNEWT_VAL(BLE_TRANS_UART_SYSINIT_STAGE)'
diff --git a/src/libs/mynewt-nimble/nimble/transport/uart/src/ble_hci_uart.c b/src/libs/mynewt-nimble/nimble/transport/uart/src/ble_hci_uart.c
new file mode 100644
index 00000000..ac6af28e
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/uart/src/ble_hci_uart.c
@@ -0,0 +1,1187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include "sysinit/sysinit.h"
+#include "syscfg/syscfg.h"
+#include "os/os_cputime.h"
+#include "bsp/bsp.h"
+#include "os/os.h"
+#include "mem/mem.h"
+#include "hal/hal_gpio.h"
+#include "hal/hal_uart.h"
+
+/* BLE */
+#include "nimble/ble.h"
+#include "nimble/nimble_opt.h"
+#include "nimble/hci_common.h"
+#include "nimble/ble_hci_trans.h"
+
+#include "transport/uart/ble_hci_uart.h"
+
+#define BLE_HCI_UART_EVT_COUNT \
+ (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT))
+
+/***
+ * NOTES:
+ * The UART HCI transport doesn't use event buffer priorities. All incoming
+ * and outgoing events use buffers from the same pool.
+ *
+ * The "skip" definitions are here so that when buffers cannot be allocated,
+ * the command or acl packets are simply skipped so that the HCI interface
+ * does not lose synchronization and resets dont (necessarily) occur.
+ */
+
+/* XXX: for now, define this here */
+#if MYNEWT_VAL(BLE_CONTROLLER)
+extern void ble_ll_data_buffer_overflow(void);
+extern void ble_ll_hw_error(uint8_t err);
+
+static const uint8_t ble_hci_uart_reset_cmd[4] = { 0x01, 0x03, 0x0C, 0x00 };
+#endif
+
+/***
+ * NOTES:
+ * The "skip" definitions are here so that when buffers cannot be allocated,
+ * the command or acl packets are simply skipped so that the HCI interface
+ * does not lose synchronization and resets dont (necessarily) occur.
+ */
+#define BLE_HCI_UART_H4_NONE 0x00
+#define BLE_HCI_UART_H4_CMD 0x01
+#define BLE_HCI_UART_H4_ACL 0x02
+#define BLE_HCI_UART_H4_SCO 0x03
+#define BLE_HCI_UART_H4_EVT 0x04
+#define BLE_HCI_UART_H4_SYNC_LOSS 0x80
+#define BLE_HCI_UART_H4_SKIP_CMD 0x81
+#define BLE_HCI_UART_H4_SKIP_ACL 0x82
+#define BLE_HCI_UART_H4_LE_EVT 0x83
+#define BLE_HCI_UART_H4_SKIP_EVT 0x84
+
+static ble_hci_trans_rx_cmd_fn *ble_hci_uart_rx_cmd_cb;
+static void *ble_hci_uart_rx_cmd_arg;
+
+static ble_hci_trans_rx_acl_fn *ble_hci_uart_rx_acl_cb;
+static void *ble_hci_uart_rx_acl_arg;
+
+static struct os_mempool ble_hci_uart_evt_hi_pool;
+static os_membuf_t ble_hci_uart_evt_hi_buf[
+ OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
+];
+
+static struct os_mempool ble_hci_uart_evt_lo_pool;
+static os_membuf_t ble_hci_uart_evt_lo_buf[
+ OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
+];
+
+static struct os_mempool ble_hci_uart_cmd_pool;
+static os_membuf_t ble_hci_uart_cmd_buf[
+ OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ)
+];
+
+static struct os_mbuf_pool ble_hci_uart_acl_mbuf_pool;
+static struct os_mempool_ext ble_hci_uart_acl_pool;
+
+/*
+ * The MBUF payload size must accommodate the HCI data header size plus the
+ * maximum ACL data packet length. The ACL block size is the size of the
+ * mbufs we will allocate.
+ */
+#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \
+ + BLE_MBUF_MEMBLOCK_OVERHEAD \
+ + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)
+
+static os_membuf_t ble_hci_uart_acl_buf[
+ OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ ACL_BLOCK_SIZE)
+];
+
+/**
+ * A packet to be sent over the UART. This can be a command, an event, or ACL
+ * data.
+ */
+struct ble_hci_uart_pkt {
+ STAILQ_ENTRY(ble_hci_uart_pkt) next;
+ void *data;
+ uint8_t type;
+};
+
+static struct os_mempool ble_hci_uart_pkt_pool;
+static os_membuf_t ble_hci_uart_pkt_buf[
+ OS_MEMPOOL_SIZE(BLE_HCI_UART_EVT_COUNT + 1 +
+ MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT),
+ sizeof (struct ble_hci_uart_pkt))
+];
+
+/**
+ * An incoming or outgoing command or event.
+ */
+struct ble_hci_uart_cmd {
+ uint8_t *data; /* Pointer to ble_hci_uart_cmd data */
+ uint16_t cur; /* Number of bytes read/written */
+ uint16_t len; /* Total number of bytes to read/write */
+};
+
+/**
+ * An incoming ACL data packet.
+ */
+struct ble_hci_uart_acl {
+ struct os_mbuf *buf; /* Buffer containing the data */
+ uint8_t *dptr; /* Pointer to where bytes should be placed */
+ uint16_t len; /* Target size when buf is considered complete */
+ uint16_t rxd_bytes; /* current count of bytes received for packet */
+};
+
+/**
+ * Structure for transmitting ACL packets over UART
+ *
+ */
+struct ble_hci_uart_h4_acl_tx
+{
+ uint8_t *dptr;
+ struct os_mbuf *tx_acl;
+};
+
+static struct {
+ /*** State of data received over UART. */
+ uint8_t rx_type; /* Pending packet type. 0 means nothing pending */
+ union {
+ struct ble_hci_uart_cmd rx_cmd;
+ struct ble_hci_uart_acl rx_acl;
+ };
+
+ /*** State of data transmitted over UART. */
+ uint8_t tx_type; /* Pending packet type. 0 means nothing pending */
+ uint16_t rem_tx_len; /* Used for acl tx only currently */
+ union {
+ struct ble_hci_uart_cmd tx_cmd;
+ struct ble_hci_uart_h4_acl_tx tx_pkt;
+ };
+ STAILQ_HEAD(, ble_hci_uart_pkt) tx_pkts; /* Packet queue to send to UART */
+} ble_hci_uart_state;
+
+/**
+ * Allocates a buffer (mbuf) for ACL operation.
+ *
+ * @return The allocated buffer on success;
+ * NULL on buffer exhaustion.
+ */
+static struct os_mbuf *
+ble_hci_trans_acl_buf_alloc(void)
+{
+ struct os_mbuf *m;
+ uint8_t usrhdr_len;
+
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ usrhdr_len = sizeof(struct ble_mbuf_hdr);
+#elif MYNEWT_VAL(BLE_HS_FLOW_CTRL)
+ usrhdr_len = BLE_MBUF_HS_HDR_LEN;
+#else
+ usrhdr_len = 0;
+#endif
+
+ m = os_mbuf_get_pkthdr(&ble_hci_uart_acl_mbuf_pool, usrhdr_len);
+ return m;
+}
+
+static int
+ble_hci_uart_acl_tx(struct os_mbuf *om)
+{
+ struct ble_hci_uart_pkt *pkt;
+ os_sr_t sr;
+
+ /* If this packet is zero length, just free it */
+ if (OS_MBUF_PKTLEN(om) == 0) {
+ os_mbuf_free_chain(om);
+ return 0;
+ }
+
+ pkt = os_memblock_get(&ble_hci_uart_pkt_pool);
+ if (pkt == NULL) {
+ os_mbuf_free_chain(om);
+ return BLE_ERR_MEM_CAPACITY;
+ }
+
+ pkt->type = BLE_HCI_UART_H4_ACL;
+ pkt->data = om;
+
+ OS_ENTER_CRITICAL(sr);
+ STAILQ_INSERT_TAIL(&ble_hci_uart_state.tx_pkts, pkt, next);
+ OS_EXIT_CRITICAL(sr);
+
+ hal_uart_start_tx(MYNEWT_VAL(BLE_HCI_UART_PORT));
+
+ return 0;
+}
+
+static int
+ble_hci_uart_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type)
+{
+ struct ble_hci_uart_pkt *pkt;
+ os_sr_t sr;
+
+ pkt = os_memblock_get(&ble_hci_uart_pkt_pool);
+ if (pkt == NULL) {
+ ble_hci_trans_buf_free(hci_ev);
+ return BLE_ERR_MEM_CAPACITY;
+ }
+
+ pkt->type = h4_type;
+ pkt->data = hci_ev;
+
+ OS_ENTER_CRITICAL(sr);
+ STAILQ_INSERT_TAIL(&ble_hci_uart_state.tx_pkts, pkt, next);
+ OS_EXIT_CRITICAL(sr);
+
+ hal_uart_start_tx(MYNEWT_VAL(BLE_HCI_UART_PORT));
+
+ return 0;
+}
+
+/**
+ * @return The packet type to transmit on success;
+ * -1 if there is nothing to send.
+ */
+static int
+ble_hci_uart_tx_pkt_type(void)
+{
+ struct ble_hci_uart_pkt *pkt;
+ struct os_mbuf *om;
+ os_sr_t sr;
+ int rc;
+
+ OS_ENTER_CRITICAL(sr);
+
+ pkt = STAILQ_FIRST(&ble_hci_uart_state.tx_pkts);
+ if (!pkt) {
+ OS_EXIT_CRITICAL(sr);
+ return -1;
+ }
+
+ STAILQ_REMOVE(&ble_hci_uart_state.tx_pkts, pkt, ble_hci_uart_pkt, next);
+
+ OS_EXIT_CRITICAL(sr);
+
+ rc = pkt->type;
+ switch (pkt->type) {
+ case BLE_HCI_UART_H4_CMD:
+ ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_CMD;
+ ble_hci_uart_state.tx_cmd.data = pkt->data;
+ ble_hci_uart_state.tx_cmd.cur = 0;
+ ble_hci_uart_state.tx_cmd.len = ble_hci_uart_state.tx_cmd.data[2] +
+ sizeof(struct ble_hci_cmd);
+ break;
+
+ case BLE_HCI_UART_H4_EVT:
+ ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_EVT;
+ ble_hci_uart_state.tx_cmd.data = pkt->data;
+ ble_hci_uart_state.tx_cmd.cur = 0;
+ ble_hci_uart_state.tx_cmd.len = ble_hci_uart_state.tx_cmd.data[1] +
+ sizeof(struct ble_hci_ev);
+ break;
+
+ case BLE_HCI_UART_H4_ACL:
+ ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_ACL;
+ om = (struct os_mbuf *)pkt->data;
+ /* NOTE: first mbuf must have non-zero length */
+ os_mbuf_trim_front(om);
+ ble_hci_uart_state.tx_pkt.tx_acl = om;
+ ble_hci_uart_state.tx_pkt.dptr = om->om_data;
+ ble_hci_uart_state.rem_tx_len = OS_MBUF_PKTLEN(om);
+ break;
+
+ default:
+ rc = -1;
+ break;
+ }
+
+ os_memblock_put(&ble_hci_uart_pkt_pool, pkt);
+
+ return rc;
+}
+
+/**
+ * @return The byte to transmit on success;
+ * -1 if there is nothing to send.
+ */
+static int
+ble_hci_uart_tx_char(void *arg)
+{
+ uint8_t u8;
+ int rc;
+ struct os_mbuf *om;
+
+ switch (ble_hci_uart_state.tx_type) {
+ case BLE_HCI_UART_H4_NONE: /* No pending packet, pick one from the queue */
+ rc = ble_hci_uart_tx_pkt_type();
+ break;
+
+ case BLE_HCI_UART_H4_CMD:
+ case BLE_HCI_UART_H4_EVT:
+ rc = ble_hci_uart_state.tx_cmd.data[ble_hci_uart_state.tx_cmd.cur++];
+
+ if (ble_hci_uart_state.tx_cmd.cur == ble_hci_uart_state.tx_cmd.len) {
+ ble_hci_trans_buf_free(ble_hci_uart_state.tx_cmd.data);
+ ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE;
+ }
+ break;
+
+ case BLE_HCI_UART_H4_ACL:
+ /* Copy the first unsent byte from the tx buffer and remove it from the
+ * source.
+ */
+ u8 = ble_hci_uart_state.tx_pkt.dptr[0];
+ --ble_hci_uart_state.rem_tx_len;
+ if (ble_hci_uart_state.rem_tx_len == 0) {
+ os_mbuf_free_chain(ble_hci_uart_state.tx_pkt.tx_acl);
+ ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE;
+ } else {
+ om = ble_hci_uart_state.tx_pkt.tx_acl;
+ --om->om_len;
+ if (om->om_len == 0) {
+ /* Remove and free any zero mbufs */
+ while ((om != NULL) && (om->om_len == 0)) {
+ ble_hci_uart_state.tx_pkt.tx_acl = SLIST_NEXT(om, om_next);
+ os_mbuf_free(om);
+ om = ble_hci_uart_state.tx_pkt.tx_acl;
+ }
+ /* NOTE: om should never be NULL! What to do? */
+ if (om == NULL) {
+ assert(0);
+ ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE;
+ } else {
+ ble_hci_uart_state.tx_pkt.dptr = om->om_data;
+ }
+ } else {
+ ble_hci_uart_state.tx_pkt.dptr++;
+ }
+ }
+ rc = u8;
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+
+ return rc;
+}
+
+#if MYNEWT_VAL(BLE_CONTROLLER)
+/**
+ * HCI uart sync lost.
+ *
+ * This occurs when the controller receives an invalid packet type or a length
+ * field that is out of range. The controller needs to send a HW error to the
+ * host and wait to find a LL reset command.
+ */
+static void
+ble_hci_uart_sync_lost(void)
+{
+ ble_hci_uart_state.rx_cmd.len = 0;
+ ble_hci_uart_state.rx_cmd.cur = 0;
+ ble_hci_uart_state.rx_cmd.data =
+ ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
+ ble_ll_hw_error(BLE_HW_ERR_HCI_SYNC_LOSS);
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_SYNC_LOSS;
+}
+#endif
+
+/**
+ * @return The type of packet to follow success;
+ * -1 if there is no valid packet to receive.
+ */
+static int
+ble_hci_uart_rx_pkt_type(uint8_t data)
+{
+ struct os_mbuf *m;
+
+ ble_hci_uart_state.rx_type = data;
+
+ switch (ble_hci_uart_state.rx_type) {
+ /* Host should never receive a command! */
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ case BLE_HCI_UART_H4_CMD:
+ ble_hci_uart_state.rx_cmd.len = 0;
+ ble_hci_uart_state.rx_cmd.cur = 0;
+ ble_hci_uart_state.rx_cmd.data =
+ ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
+ if (ble_hci_uart_state.rx_cmd.data == NULL) {
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_SKIP_CMD;
+ }
+ break;
+#endif
+
+ /* Controller should never receive an event */
+#if MYNEWT_VAL(BLE_HOST)
+ case BLE_HCI_UART_H4_EVT:
+ /*
+ * The event code is unknown at the moment. Depending on event priority,
+ * buffer *shall* be allocated from ble_hci_uart_evt_hi_pool
+ * or "may* be allocated from ble_hci_uart_evt_lo_pool.
+ * Thus do not allocate the buffer yet.
+ */
+ ble_hci_uart_state.rx_cmd.data = NULL;
+ ble_hci_uart_state.rx_cmd.len = 0;
+ ble_hci_uart_state.rx_cmd.cur = 0;
+ break;
+#endif
+
+ case BLE_HCI_UART_H4_ACL:
+ ble_hci_uart_state.rx_acl.len = 0;
+ ble_hci_uart_state.rx_acl.rxd_bytes = 0;
+ m = ble_hci_trans_acl_buf_alloc();
+ if (m) {
+ ble_hci_uart_state.rx_acl.dptr = m->om_data;
+ } else {
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_SKIP_ACL;
+ }
+ ble_hci_uart_state.rx_acl.buf = m;
+ break;
+
+ default:
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ /*
+ * If we receive an unknown HCI packet type this is considered a loss
+ * of sync.
+ */
+ ble_hci_uart_sync_lost();
+#else
+ /*
+ * XXX: not sure what to do about host in this case. Just go back to
+ * none for now.
+ */
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+#if MYNEWT_VAL(BLE_CONTROLLER)
+/**
+ * HCI uart sync loss.
+ *
+ * Find a LL reset command in the byte stream. The LL reset command is a
+ * sequence of 4 bytes:
+ * 0x01 HCI Packet Type = HCI CMD
+ * 0x03 OCF for reset command
+ * 0x0C OGF for reset command (0x03 shifted left by two bits as the OGF
+ * occupies the uopper 6 bits of this byte.
+ * 0x00 Parameter length of reset command (no parameters).
+ *
+ * @param data Byte received over serial port
+ */
+void
+ble_hci_uart_rx_sync_loss(uint8_t data)
+{
+ int rc;
+ int index;
+
+ /*
+ * If we couldnt allocate a command buffer (should not occur but
+ * possible) try to allocate one on each received character. If we get
+ * a reset and buffer is not available we have to ignore reset.
+ */
+ if (ble_hci_uart_state.rx_cmd.data == NULL) {
+ ble_hci_uart_state.rx_cmd.data =
+ ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
+ }
+
+ index = ble_hci_uart_state.rx_cmd.cur;
+ if (data == ble_hci_uart_reset_cmd[index]) {
+ if (index == 3) {
+ if (ble_hci_uart_state.rx_cmd.data == NULL) {
+ index = 0;
+ } else {
+ assert(ble_hci_uart_rx_cmd_cb != NULL);
+ ble_hci_uart_state.rx_cmd.data[0] = 0x03;
+ ble_hci_uart_state.rx_cmd.data[1] = 0x0C;
+ ble_hci_uart_state.rx_cmd.data[2] = 0x00;
+ rc = ble_hci_uart_rx_cmd_cb(ble_hci_uart_state.rx_cmd.data,
+ ble_hci_uart_rx_cmd_arg);
+ if (rc != 0) {
+ ble_hci_trans_buf_free(ble_hci_uart_state.rx_cmd.data);
+ }
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+ }
+ } else {
+ ++index;
+ }
+ } else {
+ index = 0;
+ }
+
+ ble_hci_uart_state.rx_cmd.cur = index;
+}
+
+static void
+ble_hci_uart_rx_cmd(uint8_t data)
+{
+ int rc;
+
+ ble_hci_uart_state.rx_cmd.data[ble_hci_uart_state.rx_cmd.cur++] = data;
+
+ if (ble_hci_uart_state.rx_cmd.cur < sizeof(struct ble_hci_cmd)) {
+ return;
+ }
+
+ if (ble_hci_uart_state.rx_cmd.cur == sizeof(struct ble_hci_cmd)) {
+ ble_hci_uart_state.rx_cmd.len = ble_hci_uart_state.rx_cmd.data[2] +
+ sizeof(struct ble_hci_cmd);
+ }
+
+ if (ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) {
+ assert(ble_hci_uart_rx_cmd_cb != NULL);
+ rc = ble_hci_uart_rx_cmd_cb(ble_hci_uart_state.rx_cmd.data,
+ ble_hci_uart_rx_cmd_arg);
+ if (rc != 0) {
+ ble_hci_trans_buf_free(ble_hci_uart_state.rx_cmd.data);
+ }
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+ }
+}
+
+static void
+ble_hci_uart_rx_skip_cmd(uint8_t data)
+{
+ ble_hci_uart_state.rx_cmd.cur++;
+
+ if (ble_hci_uart_state.rx_cmd.cur < sizeof(struct ble_hci_cmd)) {
+ return;
+ }
+
+ if (ble_hci_uart_state.rx_cmd.cur == sizeof(struct ble_hci_cmd)) {
+ ble_hci_uart_state.rx_cmd.len = data + sizeof(struct ble_hci_cmd);
+ }
+
+ if (ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) {
+ /*
+ * XXX: for now we simply skip the command and do nothing. This
+ * should not happen but at least we retain HCI synch. The host
+ * can decide what to do in this case. It may be appropriate for
+ * the controller to attempt to send back a command complete or
+ * command status in this case.
+ */
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+ }
+}
+#endif
+
+#if MYNEWT_VAL(BLE_HOST)
+static inline void
+ble_hci_uart_rx_evt_cb(void)
+{
+ int rc;
+
+ if (ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) {
+ assert(ble_hci_uart_rx_cmd_cb != NULL);
+ rc = ble_hci_uart_rx_cmd_cb(ble_hci_uart_state.rx_cmd.data,
+ ble_hci_uart_rx_cmd_arg);
+ if (rc != 0) {
+ ble_hci_trans_buf_free(ble_hci_uart_state.rx_cmd.data);
+ }
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+ }
+}
+
+static void
+ble_hci_uart_rx_evt(uint8_t data)
+{
+ /* Determine event priority to allocate buffer */
+ if (!ble_hci_uart_state.rx_cmd.data) {
+ /* In case of LE Meta Event priority might be still unknown */
+ if (data == BLE_HCI_EVCODE_LE_META) {
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_LE_EVT;
+ ble_hci_uart_state.rx_cmd.cur++;
+ return;
+ }
+
+ ble_hci_uart_state.rx_cmd.data =
+ ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
+ assert(ble_hci_uart_state.rx_cmd.data != NULL);
+ }
+
+ ble_hci_uart_state.rx_cmd.data[ble_hci_uart_state.rx_cmd.cur++] = data;
+
+ if (ble_hci_uart_state.rx_cmd.cur < sizeof(struct ble_hci_ev)) {
+ return;
+ }
+
+ if (ble_hci_uart_state.rx_cmd.cur == sizeof(struct ble_hci_ev)) {
+ ble_hci_uart_state.rx_cmd.len = ble_hci_uart_state.rx_cmd.data[1] +
+ sizeof(struct ble_hci_ev);
+ }
+
+ ble_hci_uart_rx_evt_cb();
+}
+
+static void
+ble_hci_uart_rx_le_evt(uint8_t data)
+{
+ ble_hci_uart_state.rx_cmd.cur++;
+
+ if (ble_hci_uart_state.rx_cmd.cur == sizeof(struct ble_hci_ev)) {
+ /* LE Meta Event parameter length is never 0 */
+ assert(data != 0);
+ ble_hci_uart_state.rx_cmd.len = data + sizeof(struct ble_hci_ev);
+ return;
+ }
+
+ /* Determine event priority to allocate buffer */
+ if (!ble_hci_uart_state.rx_cmd.data) {
+ /* Determine event priority to allocate buffer */
+ if (data == BLE_HCI_LE_SUBEV_ADV_RPT ||
+ data == BLE_HCI_LE_SUBEV_EXT_ADV_RPT) {
+ ble_hci_uart_state.rx_cmd.data =
+ ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
+ if (ble_hci_uart_state.rx_cmd.data == NULL) {
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_SKIP_EVT;
+ return;
+ }
+ } else {
+ ble_hci_uart_state.rx_cmd.data =
+ ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
+ assert(ble_hci_uart_state.rx_cmd.data != NULL);
+ }
+
+ ble_hci_uart_state.rx_cmd.data[0] = BLE_HCI_EVCODE_LE_META;
+ ble_hci_uart_state.rx_cmd.data[1] =
+ ble_hci_uart_state.rx_cmd.len - sizeof(struct ble_hci_ev);
+ }
+
+ ble_hci_uart_state.rx_cmd.data[ble_hci_uart_state.rx_cmd.cur - 1] = data;
+ ble_hci_uart_rx_evt_cb();
+}
+
+static void
+ble_hci_uart_rx_skip_evt(uint8_t data)
+{
+ if (++ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) {
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+ }
+}
+#endif
+
+static void
+ble_hci_uart_rx_acl(uint8_t data)
+{
+ uint16_t rxd_bytes;
+ uint16_t pktlen;
+
+ rxd_bytes = ble_hci_uart_state.rx_acl.rxd_bytes;
+ ble_hci_uart_state.rx_acl.dptr[rxd_bytes] = data;
+ ++rxd_bytes;
+ ble_hci_uart_state.rx_acl.rxd_bytes = rxd_bytes;
+
+ if (rxd_bytes < BLE_HCI_DATA_HDR_SZ) {
+ return;
+ }
+
+ if (rxd_bytes == BLE_HCI_DATA_HDR_SZ) {
+ pktlen = ble_hci_uart_state.rx_acl.dptr[3];
+ pktlen = (pktlen << 8) + ble_hci_uart_state.rx_acl.dptr[2];
+ ble_hci_uart_state.rx_acl.len = pktlen + BLE_HCI_DATA_HDR_SZ;
+
+ /*
+ * Data portion cannot exceed data length of acl buffer. If it does
+ * this is considered to be a loss of sync.
+ */
+ if (pktlen > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) {
+ os_mbuf_free_chain(ble_hci_uart_state.rx_acl.buf);
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ ble_hci_uart_sync_lost();
+#else
+ /*
+ * XXX: not sure what to do about host in this case. Just go back to
+ * none for now.
+ */
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+#endif
+ }
+ }
+
+ if (rxd_bytes == ble_hci_uart_state.rx_acl.len) {
+ assert(ble_hci_uart_rx_acl_cb != NULL);
+ /* XXX: can this callback fail? What if it does? */
+ OS_MBUF_PKTLEN(ble_hci_uart_state.rx_acl.buf) = rxd_bytes;
+ ble_hci_uart_state.rx_acl.buf->om_len = rxd_bytes;
+ ble_hci_uart_rx_acl_cb(ble_hci_uart_state.rx_acl.buf,
+ ble_hci_uart_rx_acl_arg);
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+ }
+}
+
+static void
+ble_hci_uart_rx_skip_acl(uint8_t data)
+{
+ uint16_t rxd_bytes;
+ uint16_t pktlen;
+
+ rxd_bytes = ble_hci_uart_state.rx_acl.rxd_bytes;
+ ++rxd_bytes;
+ ble_hci_uart_state.rx_acl.rxd_bytes = rxd_bytes;
+
+ if (rxd_bytes == (BLE_HCI_DATA_HDR_SZ - 1)) {
+ ble_hci_uart_state.rx_acl.len = data;
+ return;
+ }
+
+ if (rxd_bytes == BLE_HCI_DATA_HDR_SZ) {
+ pktlen = data;
+ pktlen = (pktlen << 8) + ble_hci_uart_state.rx_acl.len;
+ ble_hci_uart_state.rx_acl.len = pktlen + BLE_HCI_DATA_HDR_SZ;
+ }
+
+ if (rxd_bytes == ble_hci_uart_state.rx_acl.len) {
+/* XXX: I dont like this but for now this denotes controller only */
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ ble_ll_data_buffer_overflow();
+#endif
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+ }
+}
+
+static int
+ble_hci_uart_rx_char(void *arg, uint8_t data)
+{
+ switch (ble_hci_uart_state.rx_type) {
+ case BLE_HCI_UART_H4_NONE:
+ return ble_hci_uart_rx_pkt_type(data);
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ case BLE_HCI_UART_H4_CMD:
+ ble_hci_uart_rx_cmd(data);
+ return 0;
+ case BLE_HCI_UART_H4_SKIP_CMD:
+ ble_hci_uart_rx_skip_cmd(data);
+ return 0;
+ case BLE_HCI_UART_H4_SYNC_LOSS:
+ ble_hci_uart_rx_sync_loss(data);
+ return 0;
+#endif
+#if MYNEWT_VAL(BLE_HOST)
+ case BLE_HCI_UART_H4_EVT:
+ ble_hci_uart_rx_evt(data);
+ return 0;
+ case BLE_HCI_UART_H4_LE_EVT:
+ ble_hci_uart_rx_le_evt(data);
+ return 0;
+ case BLE_HCI_UART_H4_SKIP_EVT:
+ ble_hci_uart_rx_skip_evt(data);
+ return 0;
+#endif
+ case BLE_HCI_UART_H4_ACL:
+ ble_hci_uart_rx_acl(data);
+ return 0;
+ case BLE_HCI_UART_H4_SKIP_ACL:
+ ble_hci_uart_rx_skip_acl(data);
+ return 0;
+ default:
+ /* This should never happen! */
+ assert(0);
+ return 0;
+ }
+}
+
+static void
+ble_hci_uart_set_rx_cbs(ble_hci_trans_rx_cmd_fn *cmd_cb,
+ void *cmd_arg,
+ ble_hci_trans_rx_acl_fn *acl_cb,
+ void *acl_arg)
+{
+ ble_hci_uart_rx_cmd_cb = cmd_cb;
+ ble_hci_uart_rx_cmd_arg = cmd_arg;
+ ble_hci_uart_rx_acl_cb = acl_cb;
+ ble_hci_uart_rx_acl_arg = acl_arg;
+}
+
+static void
+ble_hci_uart_free_pkt(uint8_t type, uint8_t *cmdevt, struct os_mbuf *acl)
+{
+ switch (type) {
+ case BLE_HCI_UART_H4_NONE:
+ break;
+
+ case BLE_HCI_UART_H4_CMD:
+ case BLE_HCI_UART_H4_EVT:
+ ble_hci_trans_buf_free(cmdevt);
+ break;
+
+ case BLE_HCI_UART_H4_ACL:
+ os_mbuf_free_chain(acl);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+}
+
+static int
+ble_hci_uart_config(void)
+{
+ int rc;
+
+ rc = hal_uart_init_cbs(MYNEWT_VAL(BLE_HCI_UART_PORT),
+ ble_hci_uart_tx_char, NULL,
+ ble_hci_uart_rx_char, NULL);
+ if (rc != 0) {
+ return BLE_ERR_UNSPECIFIED;
+ }
+
+ rc = hal_uart_config(MYNEWT_VAL(BLE_HCI_UART_PORT),
+ MYNEWT_VAL(BLE_HCI_UART_BAUD),
+ MYNEWT_VAL(BLE_HCI_UART_DATA_BITS),
+ MYNEWT_VAL(BLE_HCI_UART_STOP_BITS),
+ MYNEWT_VAL(BLE_HCI_UART_PARITY),
+ MYNEWT_VAL(BLE_HCI_UART_FLOW_CTRL));
+ if (rc != 0) {
+ return BLE_ERR_HW_FAIL;
+ }
+
+ return 0;
+}
+
+/**
+ * Sends an HCI event from the controller to the host.
+ *
+ * @param cmd The HCI event to send. This buffer must be
+ * allocated via ble_hci_trans_buf_alloc().
+ *
+ * @return 0 on success;
+ * A BLE_ERR_[...] error code on failure.
+ */
+int
+ble_hci_trans_ll_evt_tx(uint8_t *cmd)
+{
+ int rc;
+
+ rc = ble_hci_uart_cmdevt_tx(cmd, BLE_HCI_UART_H4_EVT);
+ return rc;
+}
+
+/**
+ * Sends ACL data from controller to host.
+ *
+ * @param om The ACL data packet to send.
+ *
+ * @return 0 on success;
+ * A BLE_ERR_[...] error code on failure.
+ */
+int
+ble_hci_trans_ll_acl_tx(struct os_mbuf *om)
+{
+ int rc;
+
+ rc = ble_hci_uart_acl_tx(om);
+ return rc;
+}
+
+/**
+ * Sends an HCI command from the host to the controller.
+ *
+ * @param cmd The HCI command to send. This buffer must be
+ * allocated via ble_hci_trans_buf_alloc().
+ *
+ * @return 0 on success;
+ * A BLE_ERR_[...] error code on failure.
+ */
+int
+ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
+{
+ int rc;
+
+ rc = ble_hci_uart_cmdevt_tx(cmd, BLE_HCI_UART_H4_CMD);
+ return rc;
+}
+
+/**
+ * Sends ACL data from host to controller.
+ *
+ * @param om The ACL data packet to send.
+ *
+ * @return 0 on success;
+ * A BLE_ERR_[...] error code on failure.
+ */
+int
+ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
+{
+ int rc;
+
+ rc = ble_hci_uart_acl_tx(om);
+ return rc;
+}
+
+/**
+ * Configures the HCI transport to call the specified callback upon receiving
+ * HCI packets from the controller. This function should only be called by by
+ * host.
+ *
+ * @param cmd_cb The callback to execute upon receiving an HCI
+ * event.
+ * @param cmd_arg Optional argument to pass to the command
+ * callback.
+ * @param acl_cb The callback to execute upon receiving ACL
+ * data.
+ * @param acl_arg Optional argument to pass to the ACL
+ * callback.
+ */
+void
+ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
+ void *cmd_arg,
+ ble_hci_trans_rx_acl_fn *acl_cb,
+ void *acl_arg)
+{
+ ble_hci_uart_set_rx_cbs(cmd_cb, cmd_arg, acl_cb, acl_arg);
+}
+
+/**
+ * Configures the HCI transport to operate with a host. The transport will
+ * execute specified callbacks upon receiving HCI packets from the controller.
+ *
+ * @param cmd_cb The callback to execute upon receiving an HCI
+ * event.
+ * @param cmd_arg Optional argument to pass to the command
+ * callback.
+ * @param acl_cb The callback to execute upon receiving ACL
+ * data.
+ * @param acl_arg Optional argument to pass to the ACL
+ * callback.
+ */
+void
+ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb,
+ void *cmd_arg,
+ ble_hci_trans_rx_acl_fn *acl_cb,
+ void *acl_arg)
+{
+ ble_hci_uart_set_rx_cbs(cmd_cb, cmd_arg, acl_cb, acl_arg);
+}
+
+/**
+ * Allocates a flat buffer of the specified type.
+ *
+ * @param type The type of buffer to allocate; one of the
+ * BLE_HCI_TRANS_BUF_[...] constants.
+ *
+ * @return The allocated buffer on success;
+ * NULL on buffer exhaustion.
+ */
+uint8_t *
+ble_hci_trans_buf_alloc(int type)
+{
+ uint8_t *buf;
+
+ switch (type) {
+ case BLE_HCI_TRANS_BUF_CMD:
+ buf = os_memblock_get(&ble_hci_uart_cmd_pool);
+ break;
+ case BLE_HCI_TRANS_BUF_EVT_HI:
+ buf = os_memblock_get(&ble_hci_uart_evt_hi_pool);
+ if (buf == NULL) {
+ /* If no high-priority event buffers remain, try to grab a
+ * low-priority one.
+ */
+ buf = os_memblock_get(&ble_hci_uart_evt_lo_pool);
+ }
+ break;
+
+ case BLE_HCI_TRANS_BUF_EVT_LO:
+ buf = os_memblock_get(&ble_hci_uart_evt_lo_pool);
+ break;
+
+ default:
+ assert(0);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+/**
+ * Frees the specified flat buffer. The buffer must have been allocated via
+ * ble_hci_trans_buf_alloc().
+ *
+ * @param buf The buffer to free.
+ */
+void
+ble_hci_trans_buf_free(uint8_t *buf)
+{
+ int rc;
+
+ /*
+ * XXX: this may look a bit odd, but the controller uses the command
+ * buffer to send back the command complete/status as an immediate
+ * response to the command. This was done to insure that the controller
+ * could always send back one of these events when a command was received.
+ * Thus, we check to see which pool the buffer came from so we can free
+ * it to the appropriate pool
+ */
+ if (os_memblock_from(&ble_hci_uart_evt_hi_pool, buf)) {
+ rc = os_memblock_put(&ble_hci_uart_evt_hi_pool, buf);
+ assert(rc == 0);
+ } else if (os_memblock_from(&ble_hci_uart_evt_lo_pool, buf)) {
+ rc = os_memblock_put(&ble_hci_uart_evt_lo_pool, buf);
+ assert(rc == 0);
+ } else {
+ assert(os_memblock_from(&ble_hci_uart_cmd_pool, buf));
+ rc = os_memblock_put(&ble_hci_uart_cmd_pool, buf);
+ assert(rc == 0);
+ }
+}
+
+/**
+ * Configures a callback to get executed whenever an ACL data packet is freed.
+ * The function is called in lieu of actually freeing the packet.
+ *
+ * @param cb The callback to configure.
+ *
+ * @return 0 on success.
+ */
+int
+ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
+{
+ ble_hci_uart_acl_pool.mpe_put_cb = cb;
+ ble_hci_uart_acl_pool.mpe_put_arg = arg;
+ return 0;
+}
+
+/**
+ * Resets the HCI UART transport to a clean state. Frees all buffers and
+ * reconfigures the UART.
+ *
+ * @return 0 on success;
+ * A BLE_ERR_[...] error code on failure.
+ */
+int
+ble_hci_trans_reset(void)
+{
+ struct ble_hci_uart_pkt *pkt;
+ int rc;
+
+ /* Close the UART to prevent race conditions as the buffers are freed. */
+ rc = hal_uart_close(MYNEWT_VAL(BLE_HCI_UART_PORT));
+ if (rc != 0) {
+ return BLE_ERR_HW_FAIL;
+ }
+
+ ble_hci_uart_free_pkt(ble_hci_uart_state.rx_type,
+ ble_hci_uart_state.rx_cmd.data,
+ ble_hci_uart_state.rx_acl.buf);
+ ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE;
+
+ ble_hci_uart_free_pkt(ble_hci_uart_state.tx_type,
+ ble_hci_uart_state.tx_cmd.data,
+ ble_hci_uart_state.tx_pkt.tx_acl);
+ ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE;
+
+ while ((pkt = STAILQ_FIRST(&ble_hci_uart_state.tx_pkts)) != NULL) {
+ STAILQ_REMOVE(&ble_hci_uart_state.tx_pkts, pkt, ble_hci_uart_pkt,
+ next);
+ ble_hci_uart_free_pkt(pkt->type, pkt->data, pkt->data);
+ os_memblock_put(&ble_hci_uart_pkt_pool, pkt);
+ }
+
+ /* Reopen the UART. */
+ rc = ble_hci_uart_config();
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Initializes the UART HCI transport module.
+ *
+ * @return 0 on success;
+ * A BLE_ERR_[...] error code on failure.
+ */
+void
+ble_hci_uart_init(void)
+{
+ int rc;
+
+ /* Ensure this function only gets called by sysinit. */
+ SYSINIT_ASSERT_ACTIVE();
+
+ rc = os_mempool_ext_init(&ble_hci_uart_acl_pool,
+ MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ ACL_BLOCK_SIZE,
+ ble_hci_uart_acl_buf,
+ "ble_hci_uart_acl_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mbuf_pool_init(&ble_hci_uart_acl_mbuf_pool,
+ &ble_hci_uart_acl_pool.mpe_mp,
+ ACL_BLOCK_SIZE,
+ MYNEWT_VAL(BLE_ACL_BUF_COUNT));
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ /*
+ * Create memory pool of HCI command buffers. NOTE: we currently dont
+ * allow this to be configured. The controller will only allow one
+ * outstanding command. We decided to keep this a pool in case we allow
+ * allow the controller to handle more than one outstanding command.
+ */
+ rc = os_mempool_init(&ble_hci_uart_cmd_pool,
+ 1,
+ BLE_HCI_TRANS_CMD_SZ,
+ ble_hci_uart_cmd_buf,
+ "ble_hci_uart_cmd_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&ble_hci_uart_evt_hi_pool,
+ MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ ble_hci_uart_evt_hi_buf,
+ "ble_hci_uart_evt_hi_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&ble_hci_uart_evt_lo_pool,
+ MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ ble_hci_uart_evt_lo_buf,
+ "ble_hci_uart_evt_lo_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ /*
+ * Create memory pool of packet list nodes. NOTE: the number of these
+ * buffers should be, at least, the total number of event buffers (hi
+ * and lo), the number of command buffers (currently 1) and the total
+ * number of buffers that the controller could possibly hand to the host.
+ */
+ rc = os_mempool_init(&ble_hci_uart_pkt_pool,
+ BLE_HCI_UART_EVT_COUNT + 1 +
+ MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT),
+ sizeof (struct ble_hci_uart_pkt),
+ ble_hci_uart_pkt_buf,
+ "ble_hci_uart_pkt_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = ble_hci_uart_config();
+ SYSINIT_PANIC_ASSERT_MSG(rc == 0, "Failure configuring UART HCI");
+
+ memset(&ble_hci_uart_state, 0, sizeof ble_hci_uart_state);
+ STAILQ_INIT(&ble_hci_uart_state.tx_pkts);
+}
diff --git a/src/libs/mynewt-nimble/nimble/transport/uart/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/uart/syscfg.yml
new file mode 100644
index 00000000..43486a8b
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/uart/syscfg.yml
@@ -0,0 +1,72 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+syscfg.defs:
+ BLE_HCI_EVT_BUF_SIZE:
+ description: 'The size of the allocated event buffers'
+ value: 70
+ BLE_HCI_EVT_HI_BUF_COUNT:
+ description: 'The number of high priority event buffers'
+ value: 8
+ BLE_HCI_EVT_LO_BUF_COUNT:
+ description: 'The number of low priority event buffers'
+ value: 8
+ BLE_ACL_BUF_COUNT:
+ description: 'The number of ACL data buffers'
+ value: 12
+ BLE_ACL_BUF_SIZE:
+ description: >
+ This is the maximum size of the data portion of HCI ACL data
+ packets. It does not include the HCI data header (of 4 bytes).
+ value: 255
+
+ BLE_HCI_ACL_OUT_COUNT:
+ description: >
+ This count is used in creating a pool of elements used by the
+ code to enqueue various elements. In the case of the controller
+ only HCI, this number should be equal to the number of mbufs in
+ the msys pool. For host only, it is really dependent on the
+ number of ACL buffers that the controller tells the host it
+ has.
+ value: 12
+
+ BLE_HCI_UART_PORT:
+ description: 'The uart to use for the HCI uart interface'
+ value: 0
+ BLE_HCI_UART_BAUD:
+ description: 'The baud rate of the HCI uart interface'
+ value: 1000000
+ BLE_HCI_UART_DATA_BITS:
+ description: 'Number of data bits used for HCI uart interface'
+ value: 8
+ BLE_HCI_UART_STOP_BITS:
+ description: 'Number of stop bits used for HCI uart interface'
+ value: 1
+ BLE_HCI_UART_PARITY:
+ description: 'Parity used for HCI uart interface'
+ value: HAL_UART_PARITY_NONE
+ BLE_HCI_UART_FLOW_CTRL:
+ description: 'Flow control used for HCI uart interface'
+ value: HAL_UART_FLOW_CTL_RTS_CTS
+ BLE_TRANS_UART_SYSINIT_STAGE:
+ description: >
+ Sysinit stage for the UART BLE transport.
+ value: 500
+
+syscfg.vals.BLE_EXT_ADV:
+ BLE_HCI_EVT_BUF_SIZE: 257