summaryrefslogtreecommitdiff
path: root/src/libs/mynewt-nimble/nimble/transport
diff options
context:
space:
mode:
authorJF002 <JF002@users.noreply.github.com>2020-05-16 16:15:38 +0200
committerGitHub <noreply@github.com>2020-05-16 16:15:38 +0200
commitd58f57b1b5a616debf893f209f1d96cac101489e (patch)
tree9df19606a2615586bb533d39fb42c84be8774092 /src/libs/mynewt-nimble/nimble/transport
parent24a1f87a78584d3b67f07ea7972ea0d8e1f8167c (diff)
parentd6c6ac4cf5801e17caf7bfc0878423703ed0413b (diff)
Merge pull request #30 from JF002/nimble
Nimble
Diffstat (limited to 'src/libs/mynewt-nimble/nimble/transport')
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore2
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/README13
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h37
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml27
-rwxr-xr-xsrc/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh51
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c326
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml23
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml38
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c368
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml43
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/emspi/include/transport/emspi/ble_hci_emspi.h33
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/emspi/pkg.yml36
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/emspi/src/ble_hci_emspi.c965
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/emspi/syscfg.yml99
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/pkg.yml45
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/ram/include/transport/ram/ble_hci_ram.h35
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/ram/pkg.yml36
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/ram/src/ble_hci_ram.c238
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/ram/syscfg.yml48
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/socket/include/socket/ble_hci_socket.h34
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/socket/pkg.yml38
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/socket/src/ble_hci_socket.c886
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/socket/syscfg.yml79
-rw-r--r--src/libs/mynewt-nimble/nimble/transport/syscfg.yml68
-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
28 files changed, 4898 insertions, 0 deletions
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore b/src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore
new file mode 100644
index 00000000..bba9f995
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/.gitignore
@@ -0,0 +1,2 @@
+/src/libble_stack_da1469x.a
+
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/README b/src/libs/mynewt-nimble/nimble/transport/da1469x/README
new file mode 100644
index 00000000..b30a01c4
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/README
@@ -0,0 +1,13 @@
+Integrated BLE Controller (CMAC) requires a binary firmware to be loaded. Such
+firmware is distributed by Dialog Semiconductor in SDK package which has to be
+obtained separately, see:
+https://www.dialog-semiconductor.com/products/da1469x-product-family
+
+Firmware is available as part of following library in SDK package:
+sdk/interfaces/ble/binaries/DA1469x-Release/libble_stack_da1469x.a
+
+By default, CMAC driver will look for this file in its package root directory
+(i.e. nimble/transport/da1469x/cmac_driver) but this can be changed using
+CMAC_IMAGE_FILE_NAME syscfg variable.
+
+Current version of CMAC driver was tested with SDK version 10.0.4.66.
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h
new file mode 100644
index 00000000..f623a48a
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h
@@ -0,0 +1,37 @@
+/*
+ * 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 __CMAC_HOST_H_
+#define __CMAC_HOST_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (* cmac_mbox_read_cb)(const uint8_t *, uint16_t len);
+
+void cmac_host_init(void);
+void cmac_mbox_write(const uint8_t *buf, size_t len);
+void cmac_mbox_set_read_cb(cmac_mbox_read_cb cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CMAC_HOST_H_ */
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml
new file mode 100644
index 00000000..90a89318
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/pkg.yml
@@ -0,0 +1,27 @@
+#
+# 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/da1469x/cmac_driver
+pkg.description: Driver for Dialog's BLE controller
+pkg.author:
+pkg.homepage:
+pkg.keywords:
+
+pkg.pre_link_cmds.BLE_HOST:
+ scripts/build_libcmac.sh: 100
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh
new file mode 100755
index 00000000..659c2b9f
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+# 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.
+
+if [ ! -f ${MYNEWT_VAL_CMAC_IMAGE_FILE_NAME} ]; then
+ >&2 echo ERROR: BLE stack library not found. Please check nimble/transport/da1469x/README for details.
+ exit 1
+fi
+
+OBJCOPY=${MYNEWT_OBJCOPY_PATH}
+AR=${MYNEWT_AR_PATH}
+LIBBLE_A=$(readlink -e ${MYNEWT_VAL_CMAC_IMAGE_FILE_NAME})
+LIBCMAC_A=${MYNEWT_USER_SRC_DIR}/libcmac.a
+
+BASENAME_ROM=cmac.rom
+BASENAME_RAM=cmac.ram
+
+cd ${MYNEWT_USER_WORK_DIR}
+
+# Extract firmware binary from .a since we do not need to link all other
+# objects with our image.
+${AR} x ${LIBBLE_A} cmac_fw.c.obj
+${OBJCOPY} -O binary --only-section=.cmi_fw_area cmac_fw.c.obj cmac.bin
+
+# We need separate copies for RAM and ROM image since section names are derived
+# from file names. For now files are the same, but it would be possible to
+# link ROM image without data and shared sections which contains zeroes anyway.
+cp cmac.bin ${BASENAME_ROM}.bin
+cp cmac.bin ${BASENAME_RAM}.bin
+
+# Convert both binaries to objects and create archive to link
+${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \
+ --rename-section .data=.libcmac.rom ${BASENAME_ROM}.bin ${BASENAME_ROM}.o
+${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \
+ --rename-section .data=.libcmac.ram ${BASENAME_RAM}.bin ${BASENAME_RAM}.o
+${AR} -rcs ${LIBCMAC_A} ${BASENAME_ROM}.o ${BASENAME_RAM}.o
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c
new file mode 100644
index 00000000..0bfb715e
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/src/cmac_host.c
@@ -0,0 +1,326 @@
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include "os/os.h"
+#include "mcu/cmsis_nvic.h"
+#include "mcu/da1469x_lpclk.h"
+#include "mcu/da1469x_hal.h"
+#include "mcu/da1469x_pdc.h"
+#include "mcu/mcu.h"
+#include "cmac_driver/cmac_host.h"
+
+#define CMAC_SYM_CONFIG ((void *)(0x00818f20 + MEMCTRL->CMI_CODE_BASE_REG))
+#define CMAC_SYM_CONFIG_DYN ((void *)(0x00821af8 + MEMCTRL->CMI_CODE_BASE_REG))
+#define CMAC_SYM_MBOX_RX ((void *)(0x008216b0 + MEMCTRL->CMI_CODE_BASE_REG))
+#define CMAC_SYM_MBOX_TX ((void *)(0x008218b0 + MEMCTRL->CMI_CODE_BASE_REG))
+
+#define CMAC_MBOX_SIZE 504
+#define CMAC_MBOX_F_RESET 0x0008
+#define CMAC_MBOX_F_WRITEPENDING 0x0010
+
+struct cmac_config {
+ uint8_t bdaddr[6]; /* Device address */
+
+ uint8_t rf_calibration_delay;
+
+ uint8_t lp_clock_freq; /* Sleep clock frequency (0 = 32768Hz, 1 = 32000Hz) */
+ uint16_t lp_clock_sca; /* Sleep clock accuracy [ppm] */
+
+ uint16_t rx_buf_len; /* RX buffer size */
+ uint16_t tx_buf_len; /* TX buffer size */
+ bool initial_length_req;
+
+ /* Channel assessment algorithm settings */
+ uint16_t chan_assess_itvl;
+ uint8_t chan_assess_itvl_mult;
+ int8_t chan_assess_min_rssi;
+ uint16_t chan_assess_pkt_num;
+ uint16_t chan_assess_bad_pkt_num;
+
+ /* Calibration settings */
+ uint8_t system_tcs_length;
+ uint8_t synth_tcs_length;
+ uint8_t rfcu_tcs_length;
+
+ uint8_t default_tx_power; /* Default TX power for connection/advertising */
+ bool filter_dup_ov_discard; /* Discard unknown devices when filter buffer is full */
+ bool use_hp_1m;
+ bool use_hp_2m;
+};
+
+struct cmac_config_dynamic {
+ bool enable_sleep; /* Enable sleep */
+
+ /* More options here, don't care now */
+};
+
+struct cmac_mbox {
+ volatile uint16_t magic;
+ volatile uint16_t flags;
+ volatile uint16_t wr_off;
+ volatile uint16_t rd_off;
+ uint8_t data[CMAC_MBOX_SIZE];
+};
+
+/* CMAC data */
+extern char _binary_cmac_rom_bin_start[];
+extern char _binary_cmac_rom_bin_end;
+extern char _binary_cmac_ram_bin_start[];
+extern char _binary_cmac_ram_bin_end;
+
+struct cmac_image_info {
+ uint32_t _dummy1;
+ uint32_t size_rom;
+ uint32_t _dummy2;
+ uint32_t magic;
+ uint32_t _dummy3[5];
+};
+
+/* Mailboxes for SYS<->CMAC communication */
+static struct cmac_mbox *cmac_mbox_rx;
+static struct cmac_mbox *cmac_mbox_tx;
+
+/* PDC entry for waking up CMAC */
+static int8_t g_cmac_host_pdc_sys2cmac;
+/* PDC entry for waking up M33 */
+static int8_t g_cmac_host_pdc_cmac2sys;
+/* Callback for data ready from CMAC */
+static cmac_mbox_read_cb g_cmac_mbox_read_cb;
+
+static inline void
+cmac_host_signal2cmac(void)
+{
+ da1469x_pdc_set(g_cmac_host_pdc_sys2cmac);
+}
+
+static void
+cmac2sys_isr(void)
+{
+ uint16_t wr_off;
+ uint16_t rd_off;
+ uint16_t chunk;
+ uint16_t len;
+
+ os_trace_isr_enter();
+
+ /* Clear CMAC2SYS interrupt */
+ *(volatile uint32_t *)0x40002000 = 2;
+
+ if (*(volatile uint32_t *)0x40002000 & 0x1c00) {
+ /* XXX CMAC is in error state, need to recover */
+ assert(0);
+ }
+
+ if (cmac_mbox_rx->flags & CMAC_MBOX_F_RESET) {
+ cmac_mbox_rx->flags &= ~CMAC_MBOX_F_RESET;
+ goto done;
+ }
+
+ if (!g_cmac_mbox_read_cb) {
+ cmac_mbox_rx->rd_off = cmac_mbox_rx->wr_off;
+ goto done;
+ }
+
+ do {
+ rd_off = cmac_mbox_rx->rd_off;
+ wr_off = cmac_mbox_rx->wr_off;
+
+ if (rd_off <= wr_off) {
+ chunk = wr_off - rd_off;
+ } else {
+ chunk = CMAC_MBOX_SIZE - rd_off;
+ }
+
+ while (chunk) {
+ len = g_cmac_mbox_read_cb(&cmac_mbox_rx->data[rd_off], chunk);
+
+ rd_off += len;
+ chunk -= len;
+ };
+
+ cmac_mbox_rx->rd_off = rd_off % CMAC_MBOX_SIZE;
+ } while (cmac_mbox_rx->rd_off != cmac_mbox_rx->wr_off);
+
+done:
+
+ if (cmac_mbox_rx->flags & CMAC_MBOX_F_WRITEPENDING) {
+ cmac_host_signal2cmac();
+ }
+
+ os_trace_isr_exit();
+}
+
+static void
+cmac_host_lpclk_cb(uint32_t freq)
+{
+ struct cmac_config_dynamic *cmac_config_dyn;
+
+ cmac_config_dyn = CMAC_SYM_CONFIG_DYN;
+ cmac_config_dyn->enable_sleep = freq == 32768;
+}
+
+void
+cmac_mbox_write(const uint8_t *buf, size_t len)
+{
+ uint16_t wr_off;
+ uint16_t rd_off;
+ uint16_t chunk;
+ uint32_t primask;
+
+ __HAL_DISABLE_INTERRUPTS(primask);
+
+ while (len) {
+ rd_off = cmac_mbox_tx->rd_off;
+ wr_off = cmac_mbox_tx->wr_off;
+
+ if (rd_off > wr_off) {
+ chunk = min(len, rd_off - wr_off);
+ } else {
+ chunk = min(len, CMAC_MBOX_SIZE - wr_off);
+ }
+
+ if (chunk == 0) {
+ continue;
+ }
+
+ memcpy(&cmac_mbox_tx->data[wr_off], buf, chunk);
+
+ wr_off += chunk;
+ cmac_mbox_tx->wr_off = wr_off % CMAC_MBOX_SIZE;
+
+ cmac_host_signal2cmac();
+
+ len -= chunk;
+ buf += chunk;
+ }
+
+ __HAL_ENABLE_INTERRUPTS(primask);
+}
+
+void
+cmac_mbox_set_read_cb(cmac_mbox_read_cb cb)
+{
+ g_cmac_mbox_read_cb = cb;
+}
+
+void
+cmac_host_init(void)
+{
+ struct cmac_image_info ii;
+ uint32_t cmac_rom_size;
+ uint32_t cmac_ram_size;
+ struct cmac_config *cmac_config;
+ struct cmac_config_dynamic *cmac_config_dyn;
+
+ /* Add PDC entry to wake up CMAC from M33 */
+ g_cmac_host_pdc_sys2cmac = da1469x_pdc_add(MCU_PDC_TRIGGER_MAC_TIMER,
+ MCU_PDC_MASTER_CMAC,
+ MCU_PDC_EN_XTAL);
+ da1469x_pdc_set(g_cmac_host_pdc_sys2cmac);
+ da1469x_pdc_ack(g_cmac_host_pdc_sys2cmac);
+
+ /* Add PDC entry to wake up M33 from CMAC, if does not exist yet */
+ g_cmac_host_pdc_cmac2sys = da1469x_pdc_find(MCU_PDC_TRIGGER_COMBO,
+ MCU_PDC_MASTER_M33, 0);
+ if (g_cmac_host_pdc_cmac2sys < 0) {
+ g_cmac_host_pdc_cmac2sys = da1469x_pdc_add(MCU_PDC_TRIGGER_COMBO,
+ MCU_PDC_MASTER_M33,
+ MCU_PDC_EN_XTAL);
+ da1469x_pdc_set(g_cmac_host_pdc_cmac2sys);
+ da1469x_pdc_ack(g_cmac_host_pdc_cmac2sys);
+ }
+
+ /* Enable Radio LDO */
+ CRG_TOP->POWER_CTRL_REG |= CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk;
+
+ /* Enable CMAC, but keep it in reset */
+ CRG_TOP->CLK_RADIO_REG = (1 << CRG_TOP_CLK_RADIO_REG_RFCU_ENABLE_Pos) |
+ (1 << CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Pos) |
+ (0 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_SEL_Pos) |
+ (1 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_ENABLE_Pos) |
+ (0 << CRG_TOP_CLK_RADIO_REG_CMAC_DIV_Pos);
+
+ /* Calculate size of ROM and RAM area (for now they should be the same) */
+ cmac_rom_size = &_binary_cmac_rom_bin_end - &_binary_cmac_rom_bin_start[0];
+ cmac_ram_size = &_binary_cmac_ram_bin_end - &_binary_cmac_ram_bin_start[0];
+ assert(cmac_rom_size == cmac_ram_size);
+
+ /* Load image header and check if image can be loaded */
+ memcpy(&ii, &_binary_cmac_rom_bin_start, sizeof(ii));
+ assert(ii.magic == 0x43414d43); /* "CMAC" */
+
+ /* Copy CMAC image to RAM */
+ memset(&_binary_cmac_ram_bin_start, 0, cmac_ram_size);
+ memcpy(&_binary_cmac_ram_bin_start, &_binary_cmac_rom_bin_start[sizeof(ii)],
+ ii.size_rom);
+
+ /*
+ * Setup memory controller for CMAC
+ * Code and data are set to the same address initially since CMAC will
+ * update data address on init. Also shared address is updated on init.
+ */
+ MEMCTRL->CMI_CODE_BASE_REG = (uint32_t)&_binary_cmac_ram_bin_start;
+ MEMCTRL->CMI_DATA_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG;
+ MEMCTRL->CMI_SHARED_BASE_REG = 0;
+ MEMCTRL->CMI_END_REG = (uint32_t)&_binary_cmac_ram_bin_end;
+
+ /* Symbols below are in shared memory, can update them now */
+ cmac_config = CMAC_SYM_CONFIG;
+ cmac_config_dyn = CMAC_SYM_CONFIG_DYN;
+ cmac_mbox_rx = CMAC_SYM_MBOX_RX;
+ cmac_mbox_tx = CMAC_SYM_MBOX_TX;
+
+ /* Update CMAC configuration */
+ cmac_config->lp_clock_freq = 0;
+ cmac_config->lp_clock_sca = 50;
+ cmac_config->rx_buf_len = 251 + 11;
+ cmac_config->tx_buf_len = 251 + 11;
+ cmac_config->initial_length_req = 0;
+ cmac_config->system_tcs_length = 0;
+ cmac_config->synth_tcs_length = 0;
+ cmac_config->rfcu_tcs_length = 0;
+ cmac_config->default_tx_power = 4;
+ cmac_config_dyn->enable_sleep = false;
+
+ /* Release CMAC from reset */
+ CRG_TOP->CLK_RADIO_REG &= ~CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk;
+
+ /* Wait for CMAC to update registers */
+ while (MEMCTRL->CMI_DATA_BASE_REG == MEMCTRL->CMI_CODE_BASE_REG);
+ while (MEMCTRL->CMI_SHARED_BASE_REG != (MEMCTRL->CMI_END_REG & 0xfffffc00));
+
+ /* Initialize mailboxes and sync with CMAC */
+ cmac_mbox_tx->flags = CMAC_MBOX_F_RESET;
+ cmac_mbox_tx->wr_off = 0;
+ cmac_mbox_tx->rd_off = 0;
+ cmac_mbox_tx->magic = 0xa55a;
+ while (cmac_mbox_rx->magic != 0xa55a);
+
+ NVIC_SetVector(CMAC2SYS_IRQn, (uint32_t)cmac2sys_isr);
+ NVIC_SetPriority(CMAC2SYS_IRQn, 0);
+ NVIC_EnableIRQ(CMAC2SYS_IRQn);
+
+ cmac_host_signal2cmac();
+
+ da1469x_lpclk_register_cmac_cb(cmac_host_lpclk_cb);
+}
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml
new file mode 100644
index 00000000..be2e62d9
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/cmac_driver/syscfg.yml
@@ -0,0 +1,23 @@
+# 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:
+ CMAC_IMAGE_FILE_NAME:
+ description: >
+ Path to library with CMAC firmware. See README for details.
+ value: "libble_stack_da1469x.a"
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/pkg.yml
new file mode 100644
index 00000000..5d9b533c
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/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/da1469x
+pkg.description: HCI transport for DA1469x
+pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+
+pkg.deps:
+ - "@apache-mynewt-nimble/nimble"
+ - "@apache-mynewt-nimble/nimble/transport/da1469x/cmac_driver"
+ - "@apache-mynewt-core/kernel/os"
+
+pkg.apis:
+ - ble_transport
+
+pkg.init:
+ da1469x_ble_hci_init: 100
+ da1469x_ble_hci_cmac_init: 201
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c b/src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c
new file mode 100644
index 00000000..971d0cd0
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/src/da1469x_ble_hci.c
@@ -0,0 +1,368 @@
+/*
+ * 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 "os/mynewt.h"
+#include "nimble/ble.h"
+#include "nimble/ble_hci_trans.h"
+#include "nimble/hci_common.h"
+#include "cmac_driver/cmac_host.h"
+
+#define HCI_PKT_NONE 0x00
+#define HCI_PKT_CMD 0x01
+#define HCI_PKT_ACL 0x02
+#define HCI_PKT_EVT 0x04
+
+#define POOL_ACL_BLOCK_SIZE \
+ OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) + \
+ BLE_MBUF_MEMBLOCK_OVERHEAD + \
+ BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)
+
+struct da1469x_ble_hci_host_api {
+ ble_hci_trans_rx_cmd_fn *evt_cb;
+ void *evt_arg;
+ ble_hci_trans_rx_acl_fn *acl_cb;
+ void *acl_arg;
+};
+
+struct da1469x_ble_hci_rx_data {
+ uint8_t type;
+ uint8_t hdr[4];
+ uint8_t min_len;
+ uint16_t len;
+ uint16_t expected_len;
+ union {
+ uint8_t *buf;
+ struct os_mbuf *om;
+ };
+};
+
+struct da1469x_ble_hci_pool_cmd {
+ uint8_t cmd[BLE_HCI_TRANS_CMD_SZ];
+ bool allocated;
+};
+
+/* (Pseudo)pool for HCI commands */
+static struct da1469x_ble_hci_pool_cmd da1469x_ble_hci_pool_cmd;
+
+/* Pools for HCI events (high and low priority) */
+static uint8_t da1469x_ble_hci_pool_evt_hi_buf[ OS_MEMPOOL_BYTES(
+ MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) ];
+static struct os_mempool da1469x_ble_hci_pool_evt_hi;
+static uint8_t da1469x_ble_hci_pool_evt_lo_buf[ OS_MEMPOOL_BYTES(
+ MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) ];
+static struct os_mempool da1469x_ble_hci_pool_evt_lo;
+
+/* Pool for ACL data */
+static uint8_t da1469x_ble_hci_pool_acl_buf[ OS_MEMPOOL_BYTES(
+ MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ POOL_ACL_BLOCK_SIZE) ];
+static struct os_mempool da1469x_ble_hci_pool_acl;
+static struct os_mbuf_pool da1469x_ble_hci_pool_acl_mbuf;
+
+/* Interface to host */
+static struct da1469x_ble_hci_host_api da1469x_ble_hci_host_api;
+
+/* State of RX currently in progress (needs to reassemble frame) */
+static struct da1469x_ble_hci_rx_data da1469x_ble_hci_rx_data;
+
+int
+ble_hci_trans_reset(void)
+{
+ /* XXX Should we do something with RF and/or BLE core? */
+ return 0;
+}
+
+void
+ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, void *evt_arg,
+ ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg)
+{
+ da1469x_ble_hci_host_api.evt_cb = evt_cb;
+ da1469x_ble_hci_host_api.evt_arg = evt_arg;
+ da1469x_ble_hci_host_api.acl_cb = acl_cb;
+ da1469x_ble_hci_host_api.acl_arg = acl_arg;
+}
+
+uint8_t *
+ble_hci_trans_buf_alloc(int type)
+{
+ uint8_t *buf;
+
+ switch (type) {
+ case BLE_HCI_TRANS_BUF_CMD:
+ assert(!da1469x_ble_hci_pool_cmd.allocated);
+ da1469x_ble_hci_pool_cmd.allocated = 1;
+ buf = da1469x_ble_hci_pool_cmd.cmd;
+ break;
+ case BLE_HCI_TRANS_BUF_EVT_HI:
+ buf = os_memblock_get(&da1469x_ble_hci_pool_evt_hi);
+ if (buf) {
+ break;
+ }
+ /* no break */
+ case BLE_HCI_TRANS_BUF_EVT_LO:
+ buf = os_memblock_get(&da1469x_ble_hci_pool_evt_lo);
+ break;
+ default:
+ assert(0);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+void
+ble_hci_trans_buf_free(uint8_t *buf)
+{
+ int rc;
+
+ if (buf == da1469x_ble_hci_pool_cmd.cmd) {
+ assert(da1469x_ble_hci_pool_cmd.allocated);
+ da1469x_ble_hci_pool_cmd.allocated = 0;
+ } else if (os_memblock_from(&da1469x_ble_hci_pool_evt_hi, buf)) {
+ rc = os_memblock_put(&da1469x_ble_hci_pool_evt_hi, buf);
+ assert(rc == 0);
+ } else {
+ assert(os_memblock_from(&da1469x_ble_hci_pool_evt_lo, buf));
+ rc = os_memblock_put(&da1469x_ble_hci_pool_evt_lo, buf);
+ assert(rc == 0);
+ }
+}
+
+int
+ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
+{
+ uint8_t ind = HCI_PKT_CMD;
+ int len = 3 + cmd[2];
+
+ cmac_mbox_write(&ind, 1);
+ cmac_mbox_write(cmd, len);
+
+ ble_hci_trans_buf_free(cmd);
+
+ return 0;
+}
+
+int
+ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
+{
+ uint8_t ind = HCI_PKT_ACL;
+ struct os_mbuf *x;
+
+ cmac_mbox_write(&ind, 1);
+
+ x = om;
+ while (x) {
+ cmac_mbox_write(x->om_data, x->om_len);
+ x = SLIST_NEXT(x, om_next);
+ }
+
+ os_mbuf_free_chain(om);
+
+ return 0;
+}
+
+static int
+da1469x_ble_hci_trans_ll_rx(const uint8_t *buf, uint16_t len)
+{
+ struct da1469x_ble_hci_rx_data *rxd = &da1469x_ble_hci_rx_data;
+ void *data;
+ int pool = BLE_HCI_TRANS_BUF_EVT_HI;
+ int rc;
+
+ assert(len);
+
+ if (rxd->type == HCI_PKT_NONE) {
+ rxd->type = buf[0];
+ rxd->len = 0;
+ rxd->expected_len = 0;
+
+ switch (rxd->type) {
+ case HCI_PKT_ACL:
+ rxd->min_len = 4;
+ break;
+ case HCI_PKT_EVT:
+ rxd->min_len = 2;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ return 1;
+ }
+
+ /* Ensure we have minimum length of bytes required to process header */
+ if (rxd->len < rxd->min_len) {
+ len = min(len, rxd->min_len - rxd->len);
+ memcpy(&rxd->hdr[rxd->len], buf, len);
+ rxd->len += len;
+ return len;
+ }
+
+ /* Parse header and allocate proper buffer if not done yet */
+ if (rxd->expected_len == 0) {
+ switch (rxd->type) {
+ case HCI_PKT_ACL:
+ data = os_mbuf_get_pkthdr(&da1469x_ble_hci_pool_acl_mbuf,
+ sizeof(struct ble_mbuf_hdr));
+ if (!data) {
+ return 0;
+ }
+
+ rxd->om = data;
+ os_mbuf_append(rxd->om, rxd->hdr, rxd->len);
+ rxd->expected_len = get_le16(&rxd->hdr[2]) + 4;
+ break;
+ case HCI_PKT_EVT:
+ if (rxd->hdr[0] == BLE_HCI_EVCODE_LE_META) {
+ /* For LE Meta event we need 3 bytes to parse header */
+ if (rxd->min_len < 3) {
+ rxd->min_len = 3;
+ return 0;
+ }
+
+ /* Advertising reports shall be allocated from low-prio pool */
+ if ((rxd->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) ||
+ (rxd->hdr[2] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
+ pool = BLE_HCI_TRANS_BUF_EVT_LO;
+ }
+ }
+
+ data = ble_hci_trans_buf_alloc(pool);
+ if (!data) {
+ /*
+ * Only care about valid buffer when shall be allocated from
+ * high-prio pool, otherwise NULL is fine and we'll just skip
+ * this event.
+ */
+ if (pool != BLE_HCI_TRANS_BUF_EVT_LO) {
+ data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
+ if (!data) {
+ return 0;
+ }
+ }
+ }
+
+ rxd->buf = data;
+ memcpy(rxd->buf, rxd->hdr, rxd->len);
+ rxd->expected_len = rxd->hdr[1] + 2;
+ break;
+ default:
+ assert(0);
+ return len;
+ }
+ }
+
+ len = min(len, rxd->expected_len - rxd->len);
+
+ switch (rxd->type) {
+ case HCI_PKT_ACL:
+ os_mbuf_append(rxd->om, buf, len);
+ rxd->len += len;
+
+ if (rxd->len == rxd->expected_len) {
+ rc = da1469x_ble_hci_host_api.acl_cb(rxd->om,
+ da1469x_ble_hci_host_api.acl_arg);
+ if (rc != 0) {
+ os_mbuf_free_chain(rxd->om);
+ }
+ rxd->type = HCI_PKT_NONE;
+ }
+ break;
+ case HCI_PKT_EVT:
+ if (rxd->buf) {
+ memcpy(&rxd->buf[rxd->len], buf, len);
+ }
+ rxd->len += len;
+
+ if (rxd->len == rxd->expected_len) {
+ /*
+ * XXX for unknown reason at startup controller sends command
+ * complete for a vendor specific command which we never sent
+ * and this messes up with our ack code - just discard this
+ * event
+ */
+ if ((rxd->buf[0] == 0x0E) && (get_le16(&rxd->buf[3]) == 0xfc11)) {
+ ble_hci_trans_buf_free(rxd->buf);
+ } else if (rxd->buf) {
+ rc = da1469x_ble_hci_host_api.evt_cb(rxd->buf,
+ da1469x_ble_hci_host_api.evt_arg);
+ if (rc != 0) {
+ ble_hci_trans_buf_free(rxd->buf);
+ }
+ }
+ rxd->type = HCI_PKT_NONE;
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ return len;
+}
+
+static int
+da1469x_ble_hci_read_cb(const uint8_t *buf, uint16_t len)
+{
+ return da1469x_ble_hci_trans_ll_rx(buf, len);
+}
+
+void
+da1469x_ble_hci_init(void)
+{
+ int rc;
+
+ SYSINIT_ASSERT_ACTIVE();
+
+ rc = os_mempool_init(&da1469x_ble_hci_pool_acl, MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ POOL_ACL_BLOCK_SIZE, da1469x_ble_hci_pool_acl_buf,
+ "da1469x_ble_hci_pool_acl");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mbuf_pool_init(&da1469x_ble_hci_pool_acl_mbuf,
+ &da1469x_ble_hci_pool_acl, POOL_ACL_BLOCK_SIZE,
+ MYNEWT_VAL(BLE_ACL_BUF_COUNT));
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&da1469x_ble_hci_pool_evt_hi,
+ MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ da1469x_ble_hci_pool_evt_hi_buf,
+ "da1469x_ble_hci_pool_evt_hi");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&da1469x_ble_hci_pool_evt_lo,
+ MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ da1469x_ble_hci_pool_evt_lo_buf,
+ "da1469x_ble_hci_pool_evt_lo");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+}
+
+void
+da1469x_ble_hci_cmac_init(void)
+{
+ cmac_mbox_set_read_cb(da1469x_ble_hci_read_cb);
+ cmac_host_init();
+}
diff --git a/src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml
new file mode 100644
index 00000000..4ea9da9b
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/da1469x/syscfg.yml
@@ -0,0 +1,43 @@
+# 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_HI_BUF_COUNT:
+ description: 'Number of high-priority event buffers.'
+ value: 2
+
+ BLE_HCI_EVT_LO_BUF_COUNT:
+ description: 'Number of low-priority event buffers.'
+ value: 8
+
+ BLE_HCI_EVT_BUF_SIZE:
+ description: 'Size of each event buffer, in bytes.'
+ value: 70
+
+ BLE_ACL_BUF_COUNT:
+ description: 'The number of ACL data buffers'
+ value: 4
+
+ 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
+
+syscfg.vals.BLE_EXT_ADV:
+ BLE_HCI_EVT_BUF_SIZE: 274
diff --git a/src/libs/mynewt-nimble/nimble/transport/emspi/include/transport/emspi/ble_hci_emspi.h b/src/libs/mynewt-nimble/nimble/transport/emspi/include/transport/emspi/ble_hci_emspi.h
new file mode 100644
index 00000000..738d9e6d
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/emspi/include/transport/emspi/ble_hci_emspi.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_EMSPI_
+#define H_BLE_HCI_EMSPI_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ble_hci_emspi_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/mynewt-nimble/nimble/transport/emspi/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/emspi/pkg.yml
new file mode 100644
index 00000000..5df5a5bb
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/emspi/pkg.yml
@@ -0,0 +1,36 @@
+#
+# 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/emspi
+pkg.description: "HCI transport using EM's HCI SPI protocol."
+pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+
+pkg.deps:
+ - "@apache-mynewt-core/kernel/os"
+ - nimble
+
+pkg.apis:
+ - ble_transport
+
+pkg.init:
+ ble_hci_emspi_init: 'MYNEWT_VAL(BLE_HCI_EMSPI_SYSINIT_STAGE)'
diff --git a/src/libs/mynewt-nimble/nimble/transport/emspi/src/ble_hci_emspi.c b/src/libs/mynewt-nimble/nimble/transport/emspi/src/ble_hci_emspi.c
new file mode 100644
index 00000000..61c0c9cb
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/emspi/src/ble_hci_emspi.c
@@ -0,0 +1,965 @@
+/*
+ * 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_spi.h"
+
+/* BLE */
+#include "nimble/ble.h"
+#include "nimble/nimble_opt.h"
+#include "nimble/hci_common.h"
+#include "nimble/ble_hci_trans.h"
+
+#include "transport/emspi/ble_hci_emspi.h"
+
+#include "am_mcu_apollo.h"
+
+/***
+ * NOTES:
+ * The emspi HCI transport doesn't use event buffer priorities. All incoming
+ * and outgoing events use buffers from the same pool.
+ *
+ */
+
+#define BLE_HCI_EMSPI_PKT_EVT_COUNT \
+ (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + \
+ MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT))
+
+#define BLE_HCI_EMSPI_PKT_NONE 0x00
+#define BLE_HCI_EMSPI_PKT_CMD 0x01
+#define BLE_HCI_EMSPI_PKT_ACL 0x02
+#define BLE_HCI_EMSPI_PKT_EVT 0x04
+
+#define BLE_HCI_EMSPI_CTLR_STATUS_OK 0xc0
+#define BLE_HCI_EMSPI_OP_TX 0x42
+#define BLE_HCI_EMSPI_OP_RX 0x81
+
+static os_event_fn ble_hci_emspi_event_txrx;
+
+static struct os_event ble_hci_emspi_ev_txrx = {
+ .ev_cb = ble_hci_emspi_event_txrx,
+};
+
+static struct os_eventq ble_hci_emspi_evq;
+static struct os_task ble_hci_emspi_task;
+static os_stack_t ble_hci_emspi_stack[MYNEWT_VAL(BLE_HCI_EMSPI_STACK_SIZE)];
+
+static ble_hci_trans_rx_cmd_fn *ble_hci_emspi_rx_cmd_cb;
+static void *ble_hci_emspi_rx_cmd_arg;
+
+static ble_hci_trans_rx_acl_fn *ble_hci_emspi_rx_acl_cb;
+static void *ble_hci_emspi_rx_acl_arg;
+
+static struct os_mempool ble_hci_emspi_evt_hi_pool;
+static os_membuf_t ble_hci_emspi_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_emspi_evt_lo_pool;
+static os_membuf_t ble_hci_emspi_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_emspi_cmd_pool;
+static os_membuf_t ble_hci_emspi_cmd_buf[
+ OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ)
+];
+
+static struct os_mbuf_pool ble_hci_emspi_acl_mbuf_pool;
+static struct os_mempool_ext ble_hci_emspi_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_emspi_acl_buf[
+ OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ ACL_BLOCK_SIZE)
+];
+
+/**
+ * A packet to be sent over the EMSPI. This can be a command, an event, or ACL
+ * data.
+ */
+struct ble_hci_emspi_pkt {
+ STAILQ_ENTRY(ble_hci_emspi_pkt) next;
+ void *data;
+ uint8_t type;
+};
+STAILQ_HEAD(, ble_hci_emspi_pkt) ble_hci_emspi_tx_q;
+
+static struct os_mempool ble_hci_emspi_pkt_pool;
+static os_membuf_t ble_hci_emspi_pkt_buf[
+ OS_MEMPOOL_SIZE(BLE_HCI_EMSPI_PKT_EVT_COUNT + 1 +
+ MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT),
+ sizeof (struct ble_hci_emspi_pkt))
+];
+
+static void
+ble_hci_emspi_rdy_isr(void *arg)
+{
+ os_eventq_put(&ble_hci_emspi_evq, &ble_hci_emspi_ev_txrx);
+}
+
+static void
+ble_hci_emspi_initiate_write(void)
+{
+ hal_gpio_irq_disable(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN));
+
+ /* Assert slave select. */
+ hal_gpio_write(MYNEWT_VAL(BLE_HCI_EMSPI_SS_PIN), 0);
+
+ /* Wait for controller to indicate ready-to-receive. */
+ while (!hal_gpio_read(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN))) { }
+}
+
+static void
+ble_hci_emspi_terminate_write(void)
+{
+ const uint64_t rdy_mask =
+ AM_HAL_GPIO_BIT(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN));
+ os_sr_t sr;
+
+ am_hal_gpio_int_clear(rdy_mask);
+
+ /* Deassert slave select. */
+ hal_gpio_write(MYNEWT_VAL(BLE_HCI_EMSPI_SS_PIN), 1);
+
+ OS_ENTER_CRITICAL(sr);
+ hal_gpio_irq_enable(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN));
+
+ if (hal_gpio_read(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN))) {
+ am_hal_gpio_int_set(rdy_mask);
+ }
+
+ OS_EXIT_CRITICAL(sr);
+}
+
+static int
+ble_hci_emspi_write_hdr(uint8_t first_byte, uint8_t *out_buf_size)
+{
+ const uint8_t hdr[2] = { first_byte, 0x00 };
+ uint8_t rx[2];
+ int rc;
+
+ /* Send command header. */
+ rc = hal_spi_txrx(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM), (void *)hdr, rx, 2);
+ if (rc != 0) {
+ return rc;
+ }
+
+ /* Check for "OK" status. */
+ if (rx[0] != BLE_HCI_EMSPI_CTLR_STATUS_OK) {
+ return BLE_ERR_HW_FAIL;
+ }
+
+ *out_buf_size = rx[1];
+ return 0;
+}
+
+/**
+ * Transmits a chunk of bytes to the controller.
+ */
+static int
+ble_hci_emspi_tx_chunk(const uint8_t *data, int len, int *out_bytes_txed)
+{
+ uint8_t buf_size;
+ int rc;
+
+ /* Silence spurious "may be used uninitialized" warning. */
+ *out_bytes_txed = 0;
+
+ ble_hci_emspi_initiate_write();
+
+ rc = ble_hci_emspi_write_hdr(BLE_HCI_EMSPI_OP_TX, &buf_size);
+ if (rc != 0) {
+ goto done;
+ }
+
+ if (buf_size == 0) {
+ rc = 0;
+ goto done;
+ }
+
+ if (buf_size < len) {
+ len = buf_size;
+ }
+ rc = hal_spi_txrx(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM), (void *)data, NULL,
+ len);
+ if (rc != 0) {
+ goto done;
+ }
+ *out_bytes_txed = len;
+
+done:
+ ble_hci_emspi_terminate_write();
+ return rc;
+}
+
+/**
+ * Transmits a full command or ACL data packet to the controller.
+ */
+static int
+ble_hci_emspi_tx(const uint8_t *data, int len)
+{
+ int bytes_txed;
+ int rc;
+
+ while (len > 0) {
+ rc = ble_hci_emspi_tx_chunk(data, len, &bytes_txed);
+ if (rc != 0) {
+ goto done;
+ }
+
+ data += bytes_txed;
+ len -= bytes_txed;
+ }
+
+ rc = 0;
+
+done:
+ return rc;
+}
+
+/**
+ * Reads the specified number of bytes from the controller.
+ */
+static int
+ble_hci_emspi_rx(uint8_t *data, int max_len)
+{
+ uint8_t buf_size;
+ int rc;
+
+ ble_hci_emspi_initiate_write();
+
+ rc = ble_hci_emspi_write_hdr(BLE_HCI_EMSPI_OP_RX, &buf_size);
+ if (rc != 0) {
+ goto done;
+ }
+
+ if (buf_size > max_len) {
+ buf_size = max_len;
+ }
+
+ rc = hal_spi_txrx(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM), NULL, data, buf_size);
+ if (rc != 0) {
+ rc = BLE_ERR_HW_FAIL;
+ goto done;
+ }
+
+done:
+ ble_hci_emspi_terminate_write();
+ return rc;
+}
+
+/**
+ * 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)
+{
+ uint8_t usrhdr_len;
+
+#if MYNEWT_VAL(BLE_HS_FLOW_CTRL)
+ usrhdr_len = BLE_MBUF_HS_HDR_LEN;
+#else
+ usrhdr_len = 0;
+#endif
+
+ return os_mbuf_get_pkthdr(&ble_hci_emspi_acl_mbuf_pool, usrhdr_len);
+}
+
+/**
+ * Transmits an ACL data packet to the controller. The caller relinquishes the
+ * specified mbuf, regardless of return status.
+ */
+static int
+ble_hci_emspi_acl_tx(struct os_mbuf *om)
+{
+ struct ble_hci_emspi_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_emspi_pkt_pool);
+ if (pkt == NULL) {
+ os_mbuf_free_chain(om);
+ return BLE_ERR_MEM_CAPACITY;
+ }
+
+ pkt->type = BLE_HCI_EMSPI_PKT_ACL;
+ pkt->data = om;
+
+ OS_ENTER_CRITICAL(sr);
+ STAILQ_INSERT_TAIL(&ble_hci_emspi_tx_q, pkt, next);
+ OS_EXIT_CRITICAL(sr);
+
+ os_eventq_put(&ble_hci_emspi_evq, &ble_hci_emspi_ev_txrx);
+
+ return 0;
+}
+
+/**
+ * Transmits a command packet to the controller. The caller relinquishes the
+ * specified buffer, regardless of return status.
+ */
+static int
+ble_hci_emspi_cmdevt_tx(uint8_t *cmd_buf, uint8_t pkt_type)
+{
+ struct ble_hci_emspi_pkt *pkt;
+ os_sr_t sr;
+
+ pkt = os_memblock_get(&ble_hci_emspi_pkt_pool);
+ if (pkt == NULL) {
+ ble_hci_trans_buf_free(cmd_buf);
+ return BLE_ERR_MEM_CAPACITY;
+ }
+
+ pkt->type = pkt_type;
+ pkt->data = cmd_buf;
+
+ OS_ENTER_CRITICAL(sr);
+ STAILQ_INSERT_TAIL(&ble_hci_emspi_tx_q, pkt, next);
+ OS_EXIT_CRITICAL(sr);
+
+ os_eventq_put(&ble_hci_emspi_evq, &ble_hci_emspi_ev_txrx);
+
+ return 0;
+}
+
+static int
+ble_hci_emspi_tx_flat(const uint8_t *data, int len)
+{
+ int rc;
+
+ rc = ble_hci_emspi_tx(data, len);
+ return rc;
+}
+
+static int
+ble_hci_emspi_tx_pkt_type(uint8_t pkt_type)
+{
+ return ble_hci_emspi_tx_flat(&pkt_type, 1);
+}
+
+static int
+ble_hci_emspi_tx_cmd(const uint8_t *data)
+{
+ int len;
+ int rc;
+
+ rc = ble_hci_emspi_tx_pkt_type(BLE_HCI_EMSPI_PKT_CMD);
+ if (rc != 0) {
+ return rc;
+ }
+
+ len = data[2] + sizeof(struct ble_hci_cmd);
+ rc = ble_hci_emspi_tx_flat(data, len);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
+}
+
+static int
+ble_hci_emspi_tx_acl(struct os_mbuf *om)
+{
+ struct os_mbuf *cur;
+ int rc;
+
+ rc = ble_hci_emspi_tx_pkt_type(BLE_HCI_EMSPI_PKT_ACL);
+ if (rc != 0) {
+ return rc;
+ }
+
+ cur = om;
+ while (cur != NULL) {
+ rc = ble_hci_emspi_tx(cur->om_data, cur->om_len);
+ if (rc != 0) {
+ break;
+ }
+
+ cur = SLIST_NEXT(cur, om_next);
+ }
+
+ return rc;
+}
+
+static struct ble_hci_emspi_pkt *
+ble_hci_emspi_pull_next_tx(void)
+{
+ struct ble_hci_emspi_pkt *pkt;
+ os_sr_t sr;
+
+ OS_ENTER_CRITICAL(sr);
+ pkt = STAILQ_FIRST(&ble_hci_emspi_tx_q);
+ if (pkt != NULL) {
+ STAILQ_REMOVE(&ble_hci_emspi_tx_q, pkt, ble_hci_emspi_pkt, next);
+ }
+ OS_EXIT_CRITICAL(sr);
+
+ return pkt;
+}
+
+static int
+ble_hci_emspi_tx_pkt(void)
+{
+ struct ble_hci_emspi_pkt *pkt;
+ int rc;
+
+ pkt = ble_hci_emspi_pull_next_tx();
+ if (pkt == NULL) {
+ return -1;
+ }
+
+ switch (pkt->type) {
+ case BLE_HCI_EMSPI_PKT_CMD:
+ rc = ble_hci_emspi_tx_cmd(pkt->data);
+ ble_hci_trans_buf_free(pkt->data);
+ break;
+
+ case BLE_HCI_EMSPI_PKT_ACL:
+ rc = ble_hci_emspi_tx_acl(pkt->data);
+ os_mbuf_free_chain(pkt->data);
+ break;
+
+ default:
+ rc = -1;
+ break;
+ }
+
+ os_memblock_put(&ble_hci_emspi_pkt_pool, pkt);
+
+ return rc;
+}
+
+static int
+ble_hci_emspi_rx_evt(void)
+{
+ uint8_t *data;
+ uint8_t len;
+ int rc;
+
+ /* XXX: we should not assert if host cannot allocate an event. Need
+ * to determine what to do here.
+ */
+ data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
+ assert(data != NULL);
+
+ rc = ble_hci_emspi_rx(data, sizeof(struct ble_hci_ev));
+ if (rc != 0) {
+ goto err;
+ }
+
+ len = data[1];
+ if (len > 0) {
+ rc = ble_hci_emspi_rx(data + sizeof(struct ble_hci_ev), len);
+ if (rc != 0) {
+ goto err;
+ }
+ }
+
+ assert(ble_hci_emspi_rx_cmd_cb != NULL);
+ ble_hci_emspi_rx_cmd_cb(data, ble_hci_emspi_rx_cmd_arg);
+ if (rc != 0) {
+ goto err;
+ }
+
+ return 0;
+
+err:
+ ble_hci_trans_buf_free(data);
+ return rc;
+}
+
+static int
+ble_hci_emspi_rx_acl(void)
+{
+ struct os_mbuf *om;
+ uint16_t len;
+ int rc;
+
+ /* XXX: we should not assert if host cannot allocate an mbuf. Need to
+ * determine what to do here.
+ */
+ om = ble_hci_trans_acl_buf_alloc();
+ assert(om != NULL);
+
+ rc = ble_hci_emspi_rx(om->om_data, BLE_HCI_DATA_HDR_SZ);
+ if (rc != 0) {
+ goto err;
+ }
+
+ len = get_le16(om->om_data + 2);
+ if (len > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) {
+ /*
+ * Data portion cannot exceed data length of acl buffer. If it does
+ * this is considered to be a loss of sync.
+ */
+ rc = BLE_ERR_UNSPECIFIED;
+ goto err;
+ }
+
+ if (len > 0) {
+ rc = ble_hci_emspi_rx(om->om_data + BLE_HCI_DATA_HDR_SZ, len);
+ if (rc != 0) {
+ goto err;
+ }
+ }
+
+ OS_MBUF_PKTLEN(om) = BLE_HCI_DATA_HDR_SZ + len;
+ om->om_len = BLE_HCI_DATA_HDR_SZ + len;
+
+ assert(ble_hci_emspi_rx_cmd_cb != NULL);
+ rc = ble_hci_emspi_rx_acl_cb(om, ble_hci_emspi_rx_acl_arg);
+ if (rc != 0) {
+ goto err;
+ }
+
+ return 0;
+
+err:
+ os_mbuf_free_chain(om);
+ return rc;
+}
+
+/**
+ * @return The type of packet to follow success;
+ * -1 if there is no valid packet to receive.
+ */
+static int
+ble_hci_emspi_rx_pkt(void)
+{
+ uint8_t pkt_type;
+ int rc;
+
+ /* XXX: This is awkward; should read the full packet in "one go". */
+ rc = ble_hci_emspi_rx(&pkt_type, 1);
+ if (rc != 0) {
+ return rc;
+ }
+
+ switch (pkt_type) {
+ case BLE_HCI_EMSPI_PKT_EVT:
+ return ble_hci_emspi_rx_evt();
+
+ case BLE_HCI_EMSPI_PKT_ACL:
+ return ble_hci_emspi_rx_acl();
+
+ default:
+ /* XXX */
+ return -1;
+ }
+}
+
+static void
+ble_hci_emspi_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_emspi_rx_cmd_cb = cmd_cb;
+ ble_hci_emspi_rx_cmd_arg = cmd_arg;
+ ble_hci_emspi_rx_acl_cb = acl_cb;
+ ble_hci_emspi_rx_acl_arg = acl_arg;
+}
+
+static void
+ble_hci_emspi_free_pkt(uint8_t type, uint8_t *cmdevt, struct os_mbuf *acl)
+{
+ switch (type) {
+ case BLE_HCI_EMSPI_PKT_NONE:
+ break;
+
+ case BLE_HCI_EMSPI_PKT_CMD:
+ case BLE_HCI_EMSPI_PKT_EVT:
+ ble_hci_trans_buf_free(cmdevt);
+ break;
+
+ case BLE_HCI_EMSPI_PKT_ACL:
+ os_mbuf_free_chain(acl);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+}
+
+/**
+ * Unsupported. This is a host-only transport.
+ */
+int
+ble_hci_trans_ll_evt_tx(uint8_t *cmd)
+{
+ return BLE_ERR_UNSUPPORTED;
+}
+
+/**
+ * Unsupported. This is a host-only transport.
+ */
+int
+ble_hci_trans_ll_acl_tx(struct os_mbuf *om)
+{
+ return BLE_ERR_UNSUPPORTED;
+}
+
+/**
+ * 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_emspi_cmdevt_tx(cmd, BLE_HCI_EMSPI_PKT_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_emspi_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_emspi_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)
+{
+ /* Unsupported. */
+ assert(0);
+}
+
+/**
+ * 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_emspi_cmd_pool);
+ break;
+ case BLE_HCI_TRANS_BUF_EVT_HI:
+ buf = os_memblock_get(&ble_hci_emspi_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_emspi_evt_lo_pool);
+ }
+ break;
+
+ case BLE_HCI_TRANS_BUF_EVT_LO:
+ buf = os_memblock_get(&ble_hci_emspi_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;
+
+ if (buf != NULL) {
+ if (os_memblock_from(&ble_hci_emspi_evt_hi_pool, buf)) {
+ rc = os_memblock_put(&ble_hci_emspi_evt_hi_pool, buf);
+ assert(rc == 0);
+ } else if (os_memblock_from(&ble_hci_emspi_evt_lo_pool, buf)) {
+ rc = os_memblock_put(&ble_hci_emspi_evt_lo_pool, buf);
+ assert(rc == 0);
+ } else {
+ assert(os_memblock_from(&ble_hci_emspi_cmd_pool, buf));
+ rc = os_memblock_put(&ble_hci_emspi_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_emspi_acl_pool.mpe_put_cb = cb;
+ ble_hci_emspi_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_emspi_pkt *pkt;
+
+ hal_gpio_write(MYNEWT_VAL(BLE_HCI_EMSPI_RESET_PIN), 1);
+
+ while ((pkt = STAILQ_FIRST(&ble_hci_emspi_tx_q)) != NULL) {
+ STAILQ_REMOVE(&ble_hci_emspi_tx_q, pkt, ble_hci_emspi_pkt, next);
+ ble_hci_emspi_free_pkt(pkt->type, pkt->data, pkt->data);
+ os_memblock_put(&ble_hci_emspi_pkt_pool, pkt);
+ }
+
+ return 0;
+}
+
+static void
+ble_hci_emspi_event_txrx(struct os_event *ev)
+{
+ int rc;
+
+ rc = ble_hci_emspi_rx_pkt();
+
+ do {
+ rc = ble_hci_emspi_tx_pkt();
+ } while (rc == 0);
+}
+
+static void
+ble_hci_emspi_loop(void *unused)
+{
+ while (1) {
+ os_eventq_run(&ble_hci_emspi_evq);
+ }
+}
+
+static void
+ble_hci_emspi_init_hw(void)
+{
+ struct hal_spi_settings spi_cfg;
+ int rc;
+
+ rc = hal_gpio_init_out(MYNEWT_VAL(BLE_HCI_EMSPI_RESET_PIN), 0);
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = hal_gpio_init_out(MYNEWT_VAL(BLE_HCI_EMSPI_SS_PIN), 1);
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ spi_cfg.data_order = HAL_SPI_MSB_FIRST;
+ spi_cfg.data_mode = HAL_SPI_MODE0;
+ spi_cfg.baudrate = MYNEWT_VAL(BLE_HCI_EMSPI_BAUD);
+ spi_cfg.word_size = HAL_SPI_WORD_SIZE_8BIT;
+
+ rc = hal_spi_config(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM), &spi_cfg);
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = hal_gpio_irq_init(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN),
+ ble_hci_emspi_rdy_isr, NULL,
+ HAL_GPIO_TRIG_RISING, HAL_GPIO_PULL_DOWN);
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = hal_spi_enable(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM));
+ assert(rc == 0);
+
+ hal_gpio_write(MYNEWT_VAL(BLE_HCI_EMSPI_RESET_PIN), 1);
+}
+
+/**
+ * Initializes the UART HCI transport module.
+ *
+ * @return 0 on success;
+ * A BLE_ERR_[...] error code on failure.
+ */
+void
+ble_hci_emspi_init(void)
+{
+ int rc;
+
+ /* Ensure this function only gets called by sysinit. */
+ SYSINIT_ASSERT_ACTIVE();
+
+ rc = os_mempool_ext_init(&ble_hci_emspi_acl_pool,
+ MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ ACL_BLOCK_SIZE,
+ ble_hci_emspi_acl_buf,
+ "ble_hci_emspi_acl_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mbuf_pool_init(&ble_hci_emspi_acl_mbuf_pool,
+ &ble_hci_emspi_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_emspi_cmd_pool,
+ 1,
+ BLE_HCI_TRANS_CMD_SZ,
+ ble_hci_emspi_cmd_buf,
+ "ble_hci_emspi_cmd_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&ble_hci_emspi_evt_hi_pool,
+ MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ ble_hci_emspi_evt_hi_buf,
+ "ble_hci_emspi_evt_hi_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&ble_hci_emspi_evt_lo_pool,
+ MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ ble_hci_emspi_evt_lo_buf,
+ "ble_hci_emspi_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_emspi_pkt_pool,
+ BLE_HCI_EMSPI_PKT_EVT_COUNT + 1 +
+ MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT),
+ sizeof (struct ble_hci_emspi_pkt),
+ ble_hci_emspi_pkt_buf,
+ "ble_hci_emspi_pkt_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ STAILQ_INIT(&ble_hci_emspi_tx_q);
+
+ ble_hci_emspi_init_hw();
+
+ /* Initialize the LL task */
+ os_eventq_init(&ble_hci_emspi_evq);
+ rc = os_task_init(&ble_hci_emspi_task, "ble_hci_emspi", ble_hci_emspi_loop,
+ NULL, MYNEWT_VAL(BLE_HCI_EMSPI_PRIO), OS_WAIT_FOREVER,
+ ble_hci_emspi_stack,
+ MYNEWT_VAL(BLE_HCI_EMSPI_STACK_SIZE));
+ SYSINIT_PANIC_ASSERT(rc == 0);
+}
diff --git a/src/libs/mynewt-nimble/nimble/transport/emspi/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/emspi/syscfg.yml
new file mode 100644
index 00000000..4751271b
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/emspi/syscfg.yml
@@ -0,0 +1,99 @@
+# 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_EMSPI:
+ description: 'Indicates that the emspi host HCI transport is present.'
+ value: 1
+ restrictions:
+ # XXX: This package only builds with the apollo2 MCU.
+ # MCU-dependencies need to be removed.
+ - MCU_APOLLO2
+
+ # This is a host-only transport.
+ - BLE_HOST
+
+ BLE_HCI_EVT_HI_BUF_COUNT:
+ description: 'Number of high-priority event buffers.'
+ value: 2
+
+ BLE_HCI_EVT_LO_BUF_COUNT:
+ description: 'Number of low-priority event buffers.'
+ value: 8
+
+ BLE_HCI_EVT_BUF_SIZE:
+ description: 'Size of each event buffer, in bytes.'
+ value: 70
+
+ BLE_ACL_BUF_COUNT:
+ description: 'The number of ACL data buffers'
+ value: 4
+
+ 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_EMSPI_SPI_NUM:
+ description: The index of the SPI device to use for HCI.
+ value: 5
+
+ BLE_HCI_EMSPI_BAUD:
+ description: The SPI baud rate.
+ value: 8000000
+
+ BLE_HCI_EMSPI_RESET_PIN:
+ description: The GPIO pin that resets the EM controller.
+ value: 42
+
+ BLE_HCI_EMSPI_SS_PIN:
+ description: The GPIO pin to use for SPI slave select.
+ value: 45
+
+ BLE_HCI_EMSPI_RDY_PIN:
+ description: >
+ The GPIO pin that the EM controller uses to indicate data ready.
+ value: 26
+
+ BLE_HCI_EMSPI_PRIO:
+ description: The priority of the emspi task.
+ type: task_priority
+ value: 5
+
+ BLE_HCI_EMSPI_STACK_SIZE:
+ description: 'The size of the emspi task (units: 4-byte words).'
+ value: 256
+
+ BLE_HCI_EMSPI_SYSINIT_STAGE:
+ description: >
+ Sysinit stage for the EMSPI BLE transport.
+ value: 100
+
+syscfg.vals.BLE_EXT_ADV:
+ BLE_HCI_EVT_BUF_SIZE: 257
diff --git a/src/libs/mynewt-nimble/nimble/transport/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/pkg.yml
new file mode 100644
index 00000000..2bc4ac29
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/pkg.yml
@@ -0,0 +1,45 @@
+#
+# 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
+pkg.description: Meta-package for NimBLE HCI transport
+pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+
+pkg.deps.'BLE_HCI_TRANSPORT == "builtin"':
+ - nimble/transport/ram
+ - nimble/controller
+
+pkg.deps.'BLE_HCI_TRANSPORT == "emspi"':
+ - nimble/transport/emspi
+
+pkg.deps.'BLE_HCI_TRANSPORT == "ram"':
+ - nimble/transport/ram
+
+pkg.deps.'BLE_HCI_TRANSPORT == "socket"':
+ - nimble/transport/socket
+
+pkg.deps.'BLE_HCI_TRANSPORT == "uart"':
+ - nimble/transport/uart
+
+pkg.deps.'BLE_HCI_TRANSPORT == "da1469x"':
+ - nimble/transport/da1469x
diff --git a/src/libs/mynewt-nimble/nimble/transport/ram/include/transport/ram/ble_hci_ram.h b/src/libs/mynewt-nimble/nimble/transport/ram/include/transport/ram/ble_hci_ram.h
new file mode 100644
index 00000000..3c37e329
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/ram/include/transport/ram/ble_hci_ram.h
@@ -0,0 +1,35 @@
+/*
+ * 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_RAM_
+#define H_BLE_HCI_RAM_
+
+#include "nimble/ble_hci_trans.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void ble_hci_ram_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/mynewt-nimble/nimble/transport/ram/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/ram/pkg.yml
new file mode 100644
index 00000000..bb8397bf
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/ram/pkg.yml
@@ -0,0 +1,36 @@
+#
+# 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/ram
+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/kernel/os"
+ - nimble
+
+pkg.apis:
+ - ble_transport
+
+pkg.init:
+ ble_hci_ram_init: 'MYNEWT_VAL(BLE_TRANS_RAM_SYSINIT_STAGE)'
diff --git a/src/libs/mynewt-nimble/nimble/transport/ram/src/ble_hci_ram.c b/src/libs/mynewt-nimble/nimble/transport/ram/src/ble_hci_ram.c
new file mode 100644
index 00000000..3f10e9df
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/ram/src/ble_hci_ram.c
@@ -0,0 +1,238 @@
+/*
+ * 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 <errno.h>
+#include <stddef.h>
+#include "syscfg/syscfg.h"
+#include "sysinit/sysinit.h"
+#include "os/os.h"
+#include "mem/mem.h"
+#include "nimble/ble.h"
+#include "nimble/ble_hci_trans.h"
+#include "transport/ram/ble_hci_ram.h"
+
+static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_hs_cb;
+static void *ble_hci_ram_rx_cmd_hs_arg;
+
+static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_ll_cb;
+static void *ble_hci_ram_rx_cmd_ll_arg;
+
+static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_hs_cb;
+static void *ble_hci_ram_rx_acl_hs_arg;
+
+static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_ll_cb;
+static void *ble_hci_ram_rx_acl_ll_arg;
+
+static struct os_mempool ble_hci_ram_cmd_pool;
+static os_membuf_t ble_hci_ram_cmd_buf[
+ OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ)
+];
+
+static struct os_mempool ble_hci_ram_evt_hi_pool;
+static os_membuf_t ble_hci_ram_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_ram_evt_lo_pool;
+static os_membuf_t ble_hci_ram_evt_lo_buf[
+ OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
+];
+
+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_ram_rx_cmd_hs_cb = cmd_cb;
+ ble_hci_ram_rx_cmd_hs_arg = cmd_arg;
+ ble_hci_ram_rx_acl_hs_cb = acl_cb;
+ ble_hci_ram_rx_acl_hs_arg = acl_arg;
+}
+
+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_ram_rx_cmd_ll_cb = cmd_cb;
+ ble_hci_ram_rx_cmd_ll_arg = cmd_arg;
+ ble_hci_ram_rx_acl_ll_cb = acl_cb;
+ ble_hci_ram_rx_acl_ll_arg = acl_arg;
+}
+
+int
+ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
+{
+ int rc;
+
+ assert(ble_hci_ram_rx_cmd_ll_cb != NULL);
+
+ rc = ble_hci_ram_rx_cmd_ll_cb(cmd, ble_hci_ram_rx_cmd_ll_arg);
+ return rc;
+}
+
+int
+ble_hci_trans_ll_evt_tx(uint8_t *hci_ev)
+{
+ int rc;
+
+ assert(ble_hci_ram_rx_cmd_hs_cb != NULL);
+
+ rc = ble_hci_ram_rx_cmd_hs_cb(hci_ev, ble_hci_ram_rx_cmd_hs_arg);
+ return rc;
+}
+
+int
+ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
+{
+ int rc;
+
+ assert(ble_hci_ram_rx_acl_ll_cb != NULL);
+
+ rc = ble_hci_ram_rx_acl_ll_cb(om, ble_hci_ram_rx_acl_ll_arg);
+ return rc;
+}
+
+int
+ble_hci_trans_ll_acl_tx(struct os_mbuf *om)
+{
+ int rc;
+
+ assert(ble_hci_ram_rx_acl_hs_cb != NULL);
+
+ rc = ble_hci_ram_rx_acl_hs_cb(om, ble_hci_ram_rx_acl_hs_arg);
+ return rc;
+}
+
+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_ram_cmd_pool);
+ break;
+
+ case BLE_HCI_TRANS_BUF_EVT_HI:
+ buf = os_memblock_get(&ble_hci_ram_evt_hi_pool);
+ if (buf == NULL) {
+ /* If no high-priority event buffers remain, try to grab a
+ * low-priority one.
+ */
+ buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
+ }
+ break;
+
+ case BLE_HCI_TRANS_BUF_EVT_LO:
+ buf = os_memblock_get(&ble_hci_ram_evt_lo_pool);
+ break;
+
+ default:
+ assert(0);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+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_ram_evt_hi_pool, buf)) {
+ rc = os_memblock_put(&ble_hci_ram_evt_hi_pool, buf);
+ assert(rc == 0);
+ } else if (os_memblock_from(&ble_hci_ram_evt_lo_pool, buf)) {
+ rc = os_memblock_put(&ble_hci_ram_evt_lo_pool, buf);
+ assert(rc == 0);
+ } else {
+ assert(os_memblock_from(&ble_hci_ram_cmd_pool, buf));
+ rc = os_memblock_put(&ble_hci_ram_cmd_pool, buf);
+ assert(rc == 0);
+ }
+}
+
+/**
+ * Unsupported; the RAM transport does not have a dedicated ACL data packet
+ * pool.
+ */
+int
+ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
+{
+ return BLE_ERR_UNSUPPORTED;
+}
+
+int
+ble_hci_trans_reset(void)
+{
+ /* No work to do. All allocated buffers are owned by the host or
+ * controller, and they will get freed by their owners.
+ */
+ return 0;
+}
+
+void
+ble_hci_ram_init(void)
+{
+ int rc;
+
+ /* Ensure this function only gets called by sysinit. */
+ SYSINIT_ASSERT_ACTIVE();
+
+ /*
+ * 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_ram_cmd_pool,
+ 1,
+ BLE_HCI_TRANS_CMD_SZ,
+ ble_hci_ram_cmd_buf,
+ "ble_hci_ram_cmd_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&ble_hci_ram_evt_hi_pool,
+ MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ ble_hci_ram_evt_hi_buf,
+ "ble_hci_ram_evt_hi_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&ble_hci_ram_evt_lo_pool,
+ MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ ble_hci_ram_evt_lo_buf,
+ "ble_hci_ram_evt_lo_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+}
diff --git a/src/libs/mynewt-nimble/nimble/transport/ram/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/ram/syscfg.yml
new file mode 100644
index 00000000..3b822fcc
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/ram/syscfg.yml
@@ -0,0 +1,48 @@
+# 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_HI_BUF_COUNT:
+ description: 'Number of high-priority event buffers.'
+ value: 2
+
+ BLE_HCI_EVT_LO_BUF_COUNT:
+ description: 'Number of low-priority event buffers.'
+ value: 8
+
+ BLE_HCI_EVT_BUF_SIZE:
+ description: 'Size of each event buffer, in bytes.'
+ value: 70
+
+ BLE_ACL_BUF_COUNT:
+ description: 'The number of ACL data buffers'
+ value: 4
+
+ 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_TRANS_RAM_SYSINIT_STAGE:
+ description: >
+ Sysinit stage for the RAM BLE transport.
+ value: 100
+
+syscfg.vals.BLE_EXT_ADV:
+ BLE_HCI_EVT_BUF_SIZE: 257
diff --git a/src/libs/mynewt-nimble/nimble/transport/socket/include/socket/ble_hci_socket.h b/src/libs/mynewt-nimble/nimble/transport/socket/include/socket/ble_hci_socket.h
new file mode 100644
index 00000000..d17074f5
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/socket/include/socket/ble_hci_socket.h
@@ -0,0 +1,34 @@
+/*
+ * 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 _BLE_HCI_SOCKET_H_
+#define _BLE_HCI_SOCKET_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct os_eventq;
+void ble_hci_sock_set_evq(struct os_eventq *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/libs/mynewt-nimble/nimble/transport/socket/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/socket/pkg.yml
new file mode 100644
index 00000000..fb4144d3
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/socket/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/socket
+pkg.description: Provides HCI transport over socket interface
+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_sock_init: 'MYNEWT_VAL(BLE_SOCK_CLI_SYSINIT_STAGE)'
diff --git a/src/libs/mynewt-nimble/nimble/transport/socket/src/ble_hci_socket.c b/src/libs/mynewt-nimble/nimble/transport/socket/src/ble_hci_socket.c
new file mode 100644
index 00000000..8bf56f39
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/socket/src/ble_hci_socket.c
@@ -0,0 +1,886 @@
+/*
+ * 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.
+ */
+
+/*
+ * Provides HCI transport over sockets. Either over
+ * TCP sockets, or Linux bluetooth socket.
+ *
+ * E.g. to connect to TCP target, start in another window
+ * socat -x PIPE:/dev/ttyACM1 TCP4-LISTEN:14433,fork,reuseaddr
+ * When building this package, set BLE_SOCK_USE_TCP=1 and
+ * BLE_SOCK_TCP_PORT controls the target port this transport
+ * connects to.
+ *
+ * To use Linux Bluetooth sockets, create an interface:
+ * sudo hciattach -r -n /dev/ttyUSB0 any 57600
+ * And build this package with BLE_SOCK_USE_LINUX_BLUE=1,
+ * BLE_SOCK_LINUX_DEV=<interface index of the target interface>
+ *
+ */
+#include "syscfg/syscfg.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#if MYNEWT_VAL(BLE_SOCK_USE_TCP)
+#include <sys/errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE)
+#include <sys/errno.h>
+#define BTPROTO_HCI 1
+#define HCI_CHANNEL_RAW 0
+#define HCI_CHANNEL_USER 1
+#define HCIDEVUP _IOW('H', 201, int)
+#define HCIDEVDOWN _IOW('H', 202, int)
+#define HCIDEVRESET _IOW('H', 203, int)
+#define HCIGETDEVLIST _IOR('H', 210, int)
+
+struct sockaddr_hci {
+ sa_family_t hci_family;
+ unsigned short hci_dev;
+ unsigned short hci_channel;
+};
+#endif
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include "sysinit/sysinit.h"
+#include "os/os.h"
+#include "mem/mem.h"
+
+#include "stats/stats.h"
+
+/* BLE */
+#include "nimble/ble.h"
+#include "nimble/nimble_opt.h"
+#include "nimble/hci_common.h"
+#include "nimble/nimble_npl.h"
+#include "nimble/ble_hci_trans.h"
+#include "socket/ble_hci_socket.h"
+
+/***
+ * 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.
+ */
+
+STATS_SECT_START(hci_sock_stats)
+ STATS_SECT_ENTRY(imsg)
+ STATS_SECT_ENTRY(icmd)
+ STATS_SECT_ENTRY(ievt)
+ STATS_SECT_ENTRY(iacl)
+ STATS_SECT_ENTRY(ibytes)
+ STATS_SECT_ENTRY(ierr)
+ STATS_SECT_ENTRY(imem)
+ STATS_SECT_ENTRY(omsg)
+ STATS_SECT_ENTRY(oacl)
+ STATS_SECT_ENTRY(ocmd)
+ STATS_SECT_ENTRY(oevt)
+ STATS_SECT_ENTRY(obytes)
+ STATS_SECT_ENTRY(oerr)
+STATS_SECT_END
+
+STATS_SECT_DECL(hci_sock_stats) hci_sock_stats;
+STATS_NAME_START(hci_sock_stats)
+ STATS_NAME(hci_sock_stats, imsg)
+ STATS_NAME(hci_sock_stats, icmd)
+ STATS_NAME(hci_sock_stats, ievt)
+ STATS_NAME(hci_sock_stats, iacl)
+ STATS_NAME(hci_sock_stats, ibytes)
+ STATS_NAME(hci_sock_stats, ierr)
+ STATS_NAME(hci_sock_stats, imem)
+ STATS_NAME(hci_sock_stats, omsg)
+ STATS_NAME(hci_sock_stats, oacl)
+ STATS_NAME(hci_sock_stats, ocmd)
+ STATS_NAME(hci_sock_stats, oevt)
+ STATS_NAME(hci_sock_stats, obytes)
+ STATS_NAME(hci_sock_stats, oerr)
+STATS_NAME_END(hci_sock_stats)
+
+/***
+ * 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
+
+#if MYNEWT
+
+#define BLE_SOCK_STACK_SIZE \
+ OS_STACK_ALIGN(MYNEWT_VAL(BLE_SOCK_STACK_SIZE))
+
+struct os_task ble_sock_task;
+
+#endif
+
+static struct os_mempool ble_hci_sock_evt_hi_pool;
+static os_membuf_t ble_hci_sock_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_sock_evt_lo_pool;
+static os_membuf_t ble_hci_sock_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_sock_cmd_pool;
+static os_membuf_t ble_hci_sock_cmd_buf[
+ OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ)
+];
+
+static struct os_mempool ble_hci_sock_acl_pool;
+static struct os_mbuf_pool ble_hci_sock_acl_mbuf_pool;
+
+#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \
+ + BLE_MBUF_MEMBLOCK_OVERHEAD \
+ + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)
+/*
+ * 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.
+ */
+
+static os_membuf_t ble_hci_sock_acl_buf[
+ OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ ACL_BLOCK_SIZE)
+];
+
+static ble_hci_trans_rx_cmd_fn *ble_hci_sock_rx_cmd_cb;
+static void *ble_hci_sock_rx_cmd_arg;
+static ble_hci_trans_rx_acl_fn *ble_hci_sock_rx_acl_cb;
+static void *ble_hci_sock_rx_acl_arg;
+
+static struct ble_hci_sock_state {
+ int sock;
+ struct ble_npl_eventq evq;
+ struct ble_npl_event ev;
+ struct ble_npl_callout timer;
+
+ uint16_t rx_off;
+ uint8_t rx_data[512];
+} ble_hci_sock_state;
+
+#if MYNEWT_VAL(BLE_SOCK_USE_TCP)
+static int s_ble_hci_device = MYNEWT_VAL(BLE_SOCK_TCP_PORT);
+#elif MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE)
+static int s_ble_hci_device = MYNEWT_VAL(BLE_SOCK_LINUX_DEV);
+#endif
+
+/**
+ * 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;
+
+ /*
+ * XXX: note that for host only there would be no need to allocate
+ * a user header. Address this later.
+ */
+ m = os_mbuf_get_pkthdr(&ble_hci_sock_acl_mbuf_pool,
+ sizeof(struct ble_mbuf_hdr));
+ return m;
+}
+
+static int
+ble_hci_sock_acl_tx(struct os_mbuf *om)
+{
+ struct msghdr msg;
+ struct iovec iov[8];
+ int i;
+ struct os_mbuf *m;
+ uint8_t ch;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(iov, 0, sizeof(iov));
+
+ msg.msg_iov = iov;
+
+ ch = BLE_HCI_UART_H4_ACL;
+ iov[0].iov_len = 1;
+ iov[0].iov_base = &ch;
+ i = 1;
+ for (m = om; m; m = SLIST_NEXT(m, om_next)) {
+ iov[i].iov_base = m->om_data;
+ iov[i].iov_len = m->om_len;
+ i++;
+ }
+ msg.msg_iovlen = i;
+
+ STATS_INC(hci_sock_stats, omsg);
+ STATS_INC(hci_sock_stats, oacl);
+ STATS_INCN(hci_sock_stats, obytes, OS_MBUF_PKTLEN(om) + 1);
+ i = sendmsg(ble_hci_sock_state.sock, &msg, 0);
+ os_mbuf_free_chain(om);
+ if (i != OS_MBUF_PKTLEN(om) + 1) {
+ if (i < 0) {
+ dprintf(1, "sendmsg() failed : %d\n", errno);
+ } else {
+ dprintf(1, "sendmsg() partial write: %d\n", i);
+ }
+ STATS_INC(hci_sock_stats, oerr);
+ return BLE_ERR_MEM_CAPACITY;
+ }
+ return 0;
+}
+
+static int
+ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type)
+{
+ struct msghdr msg;
+ struct iovec iov[8];
+ int len;
+ int i;
+ uint8_t ch;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(iov, 0, sizeof(iov));
+
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+
+ ch = h4_type;
+ iov[0].iov_len = 1;
+ iov[0].iov_base = &ch;
+ iov[1].iov_base = hci_ev;
+ if (h4_type == BLE_HCI_UART_H4_CMD) {
+ len = sizeof(struct ble_hci_cmd) + hci_ev[2];
+ STATS_INC(hci_sock_stats, ocmd);
+ } else if (h4_type == BLE_HCI_UART_H4_EVT) {
+ len = sizeof(struct ble_hci_ev) + hci_ev[1];
+ STATS_INC(hci_sock_stats, oevt);
+ } else {
+ assert(0);
+ }
+ iov[1].iov_len = len;
+
+ STATS_INC(hci_sock_stats, omsg);
+ STATS_INCN(hci_sock_stats, obytes, len + 1);
+
+ i = sendmsg(ble_hci_sock_state.sock, &msg, 0);
+ ble_hci_trans_buf_free(hci_ev);
+ if (i != len + 1) {
+ if (i < 0) {
+ dprintf(1, "sendmsg() failed : %d\n", errno);
+ } else {
+ dprintf(1, "sendmsg() partial write: %d\n", i);
+ }
+ STATS_INC(hci_sock_stats, oerr);
+ return BLE_ERR_MEM_CAPACITY;
+ }
+
+ return 0;
+}
+
+static int
+ble_hci_sock_rx_msg(void)
+{
+ struct ble_hci_sock_state *bhss;
+ int len;
+ struct os_mbuf *m;
+ uint8_t *data;
+ int sr;
+ int rc;
+
+ bhss = &ble_hci_sock_state;
+ if (bhss->sock < 0) {
+ return -1;
+ }
+ len = read(bhss->sock, bhss->rx_data + bhss->rx_off,
+ sizeof(bhss->rx_data) - bhss->rx_off);
+ if (len < 0) {
+ return -2;
+ }
+ if (len == 0) {
+ return -1;
+ }
+ bhss->rx_off += len;
+ STATS_INCN(hci_sock_stats, ibytes, len);
+
+ while (bhss->rx_off > 0) {
+ switch (bhss->rx_data[0]) {
+#if MYNEWT_VAL(BLE_CONTROLLER)
+ case BLE_HCI_UART_H4_CMD:
+ if (bhss->rx_off < sizeof(struct ble_hci_cmd)) {
+ return -1;
+ }
+ len = 1 + sizeof(struct ble_hci_cmd) + bhss->rx_data[3];
+ if (bhss->rx_off < len) {
+ return -1;
+ }
+ STATS_INC(hci_sock_stats, imsg);
+ STATS_INC(hci_sock_stats, icmd);
+ data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
+ if (!data) {
+ STATS_INC(hci_sock_stats, ierr);
+ break;
+ }
+ memcpy(data, &bhss->rx_data[1], len - 1);
+ OS_ENTER_CRITICAL(sr);
+ rc = ble_hci_sock_rx_cmd_cb(data, ble_hci_sock_rx_cmd_arg);
+ OS_EXIT_CRITICAL(sr);
+ if (rc) {
+ ble_hci_trans_buf_free(data);
+ STATS_INC(hci_sock_stats, ierr);
+ break;
+ }
+ break;
+#endif
+#if MYNEWT_VAL(BLE_HOST)
+ case BLE_HCI_UART_H4_EVT:
+ if (bhss->rx_off < sizeof(struct ble_hci_ev)) {
+ return -1;
+ }
+ len = 1 + sizeof(struct ble_hci_ev) + bhss->rx_data[2];
+ if (bhss->rx_off < len) {
+ return -1;
+ }
+ STATS_INC(hci_sock_stats, imsg);
+ STATS_INC(hci_sock_stats, ievt);
+ data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
+ if (!data) {
+ STATS_INC(hci_sock_stats, ierr);
+ break;
+ }
+ memcpy(data, &bhss->rx_data[1], len - 1);
+ OS_ENTER_CRITICAL(sr);
+ rc = ble_hci_sock_rx_cmd_cb(data, ble_hci_sock_rx_cmd_arg);
+ OS_EXIT_CRITICAL(sr);
+ if (rc) {
+ ble_hci_trans_buf_free(data);
+ STATS_INC(hci_sock_stats, ierr);
+ return 0;
+ }
+ break;
+#endif
+ case BLE_HCI_UART_H4_ACL:
+ if (bhss->rx_off < BLE_HCI_DATA_HDR_SZ) {
+ return -1;
+ }
+ len = 1 + BLE_HCI_DATA_HDR_SZ + (bhss->rx_data[4] << 8) +
+ bhss->rx_data[3];
+ if (bhss->rx_off < len) {
+ return -1;
+ }
+ STATS_INC(hci_sock_stats, imsg);
+ STATS_INC(hci_sock_stats, iacl);
+ m = ble_hci_trans_acl_buf_alloc();
+ if (!m) {
+ STATS_INC(hci_sock_stats, imem);
+ break;
+ }
+ if (os_mbuf_append(m, &bhss->rx_data[1], len - 1)) {
+ STATS_INC(hci_sock_stats, imem);
+ os_mbuf_free_chain(m);
+ break;
+ }
+ OS_ENTER_CRITICAL(sr);
+ ble_hci_sock_rx_acl_cb(m, ble_hci_sock_rx_acl_arg);
+ OS_EXIT_CRITICAL(sr);
+ break;
+ default:
+ STATS_INC(hci_sock_stats, ierr);
+ break;
+ }
+ memmove(bhss->rx_data, &bhss->rx_data[len], bhss->rx_off - len);
+ bhss->rx_off -= len;
+ }
+ return 0;
+}
+
+static void
+ble_hci_sock_rx_ev(struct ble_npl_event *ev)
+{
+ int rc;
+ ble_npl_time_t timeout;
+
+ rc = ble_hci_sock_rx_msg();
+ if (rc == 0) {
+ ble_npl_eventq_put(&ble_hci_sock_state.evq, &ble_hci_sock_state.ev);
+ } else {
+ rc = ble_npl_time_ms_to_ticks(10, &timeout);
+ ble_npl_callout_reset(&ble_hci_sock_state.timer, timeout);
+ }
+}
+
+#if MYNEWT_VAL(BLE_SOCK_USE_TCP)
+static int
+ble_hci_sock_config(void)
+{
+ struct ble_hci_sock_state *bhss = &ble_hci_sock_state;
+ struct sockaddr_in sin;
+ ble_npl_time_t timeout;
+ int s;
+ int rc;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(s_ble_hci_device);
+ sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+#ifdef MN_OSX
+ sin.sin_len = sizeof(sin);
+#endif
+
+#if 0
+ if (bhss->sock >= 0) {
+ close(bhss->sock);
+ bhss->sock = -1;
+ }
+#endif
+ if (bhss->sock < 0) {
+ s = socket(PF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ goto err;
+ }
+
+ rc = connect(s, (struct sockaddr *)&sin, sizeof(sin));
+ if (rc) {
+ dprintf(1, "connect() failed: %d\n", errno);
+ goto err;
+ }
+
+ rc = 1;
+
+ rc = ioctl(s, FIONBIO, (char *)&rc);
+ if (rc) {
+ goto err;
+ }
+ bhss->sock = s;
+ }
+ rc = ble_npl_time_ms_to_ticks(10, &timeout);
+ if (rc) {
+ goto err;
+ }
+ ble_npl_callout_reset(&ble_hci_sock_state.timer, timeout);
+
+ return 0;
+err:
+ if (s >= 0) {
+ close(s);
+ }
+ return BLE_ERR_HW_FAIL;
+}
+#endif
+
+#if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE)
+static int
+ble_hci_sock_config(void)
+{
+ struct sockaddr_hci shci;
+ int s;
+ int rc;
+ ble_npl_time_t timeout;
+
+ memset(&shci, 0, sizeof(shci));
+ shci.hci_family = AF_BLUETOOTH;
+ shci.hci_dev = s_ble_hci_device;
+ shci.hci_channel = HCI_CHANNEL_USER;
+
+ if (ble_hci_sock_state.sock >= 0) {
+ close(ble_hci_sock_state.sock);
+ ble_hci_sock_state.sock = -1;
+ }
+
+ s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+ if (s < 0) {
+ dprintf(1, "socket() failed %d\n", errno);
+ goto err;
+ }
+
+ /*
+ * HCI User Channel requires exclusive access to the device.
+ * The device has to be down at the time of binding.
+ */
+ ioctl(s, HCIDEVDOWN, shci.hci_dev);
+
+ rc = bind(s, (struct sockaddr *)&shci, sizeof(shci));
+ if (rc) {
+ dprintf(1, "bind() failed %d hci%d\n", errno, shci.hci_dev);
+ goto err;
+ }
+
+ rc = 1;
+
+ rc = ioctl(s, FIONBIO, (char *)&rc);
+ if (rc) {
+ goto err;
+ }
+ ble_hci_sock_state.sock = s;
+
+ rc = ble_npl_time_ms_to_ticks(10, &timeout);
+ if (rc) {
+ goto err;
+ }
+ ble_npl_callout_reset(&ble_hci_sock_state.timer, timeout);
+
+ return 0;
+err:
+ if (s >= 0) {
+ close(s);
+ }
+ return BLE_ERR_HW_FAIL;
+}
+#endif
+/**
+ * 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)
+{
+ return ble_hci_sock_cmdevt_tx(cmd, BLE_HCI_UART_H4_EVT);
+}
+
+/**
+ * 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)
+{
+ return ble_hci_sock_acl_tx(om);
+}
+
+/**
+ * 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)
+{
+ return ble_hci_sock_cmdevt_tx(cmd, BLE_HCI_UART_H4_CMD);
+}
+
+/**
+ * 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)
+{
+ return ble_hci_sock_acl_tx(om);
+}
+
+/**
+ * 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_sock_rx_cmd_cb = cmd_cb;
+ ble_hci_sock_rx_cmd_arg = cmd_arg;
+ ble_hci_sock_rx_acl_cb = acl_cb;
+ ble_hci_sock_rx_acl_arg = 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_sock_rx_cmd_cb = cmd_cb;
+ ble_hci_sock_rx_cmd_arg = cmd_arg;
+ ble_hci_sock_rx_acl_cb = acl_cb;
+ ble_hci_sock_rx_acl_arg = 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_sock_cmd_pool);
+ break;
+ case BLE_HCI_TRANS_BUF_EVT_HI:
+ buf = os_memblock_get(&ble_hci_sock_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_sock_evt_lo_pool);
+ }
+ break;
+
+ case BLE_HCI_TRANS_BUF_EVT_LO:
+ buf = os_memblock_get(&ble_hci_sock_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_sock_evt_hi_pool, buf)) {
+ rc = os_memblock_put(&ble_hci_sock_evt_hi_pool, buf);
+ assert(rc == 0);
+ } else if (os_memblock_from(&ble_hci_sock_evt_lo_pool, buf)) {
+ rc = os_memblock_put(&ble_hci_sock_evt_lo_pool, buf);
+ assert(rc == 0);
+ } else {
+ assert(os_memblock_from(&ble_hci_sock_cmd_pool, buf));
+ rc = os_memblock_put(&ble_hci_sock_cmd_pool, buf);
+ assert(rc == 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)
+{
+ int rc;
+
+ ble_npl_callout_stop(&ble_hci_sock_state.timer);
+
+ /* Reopen the UART. */
+ rc = ble_hci_sock_config();
+ if (rc != 0) {
+ dprintf(1, "Failure restarting socket HCI\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+void
+ble_hci_sock_ack_handler(void *arg)
+{
+ struct ble_npl_event *ev;
+
+ while (1) {
+ ev = ble_npl_eventq_get(&ble_hci_sock_state.evq, BLE_NPL_TIME_FOREVER);
+ ble_npl_event_run(ev);
+ }
+}
+
+static void
+ble_hci_sock_init_task(void)
+{
+ ble_npl_eventq_init(&ble_hci_sock_state.evq);
+ ble_npl_callout_stop(&ble_hci_sock_state.timer);
+ ble_npl_callout_init(&ble_hci_sock_state.timer, &ble_hci_sock_state.evq,
+ ble_hci_sock_rx_ev, NULL);
+
+#if MYNEWT
+ {
+ os_stack_t *pstack;
+
+ pstack = malloc(sizeof(os_stack_t)*BLE_SOCK_STACK_SIZE);
+ assert(pstack);
+ os_task_init(&ble_sock_task, "hci_sock", ble_hci_sock_ack_handler, NULL,
+ MYNEWT_VAL(BLE_SOCK_TASK_PRIO), BLE_NPL_TIME_FOREVER, pstack,
+ BLE_SOCK_STACK_SIZE);
+ }
+#else
+/*
+ * For non-Mynewt OS it is required that OS creates task for HCI SOCKET
+ * to run ble_hci_sock_ack_handler.
+ */
+
+#endif
+
+}
+
+void
+ble_hci_sock_set_device(int dev)
+{
+ s_ble_hci_device = dev;
+}
+
+/**
+ * Initializes the UART HCI transport module.
+ *
+ * @return 0 on success;
+ * A BLE_ERR_[...] error code on failure.
+ */
+void
+ble_hci_sock_init(void)
+{
+ int rc;
+
+ /* Ensure this function only gets called by sysinit. */
+ SYSINIT_ASSERT_ACTIVE();
+
+ memset(&ble_hci_sock_state, 0, sizeof(ble_hci_sock_state));
+ ble_hci_sock_state.sock = -1;
+
+ ble_hci_sock_init_task();
+ ble_npl_event_init(&ble_hci_sock_state.ev, ble_hci_sock_rx_ev, NULL);
+
+ rc = os_mempool_init(&ble_hci_sock_acl_pool,
+ MYNEWT_VAL(BLE_ACL_BUF_COUNT),
+ ACL_BLOCK_SIZE,
+ ble_hci_sock_acl_buf,
+ "ble_hci_sock_acl_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mbuf_pool_init(&ble_hci_sock_acl_mbuf_pool,
+ &ble_hci_sock_acl_pool,
+ 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_sock_cmd_pool,
+ 1,
+ BLE_HCI_TRANS_CMD_SZ,
+ &ble_hci_sock_cmd_buf,
+ "ble_hci_sock_cmd_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&ble_hci_sock_evt_hi_pool,
+ MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ &ble_hci_sock_evt_hi_buf,
+ "ble_hci_sock_evt_hi_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = os_mempool_init(&ble_hci_sock_evt_lo_pool,
+ MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
+ MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
+ ble_hci_sock_evt_lo_buf,
+ "ble_hci_sock_evt_lo_pool");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+
+ rc = ble_hci_sock_config();
+ SYSINIT_PANIC_ASSERT_MSG(rc == 0, "Failure configuring socket HCI");
+
+ rc = stats_init_and_reg(STATS_HDR(hci_sock_stats),
+ STATS_SIZE_INIT_PARMS(hci_sock_stats, STATS_SIZE_32),
+ STATS_NAME_INIT_PARMS(hci_sock_stats), "hci_socket");
+ SYSINIT_PANIC_ASSERT(rc == 0);
+}
diff --git a/src/libs/mynewt-nimble/nimble/transport/socket/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/socket/syscfg.yml
new file mode 100644
index 00000000..2050f646
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/socket/syscfg.yml
@@ -0,0 +1,79 @@
+# 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: 24
+ 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_SOCK_USE_TCP:
+ description: 'Use TCP socket, connects to BLE_SOCK_TCP_PORT'
+ value: 1
+
+ BLE_SOCK_TCP_PORT:
+ description: 'ipv4 tcp port to connect to'
+ value: 14433
+
+ BLE_SOCK_USE_LINUX_BLUE:
+ description: 'Use Linux bluetooth raw socket'
+ value: 0
+
+ BLE_SOCK_LINUX_DEV:
+ description: 'linux kernel device'
+ value: 0
+
+ BLE_SOCK_TASK_PRIO:
+ description: 'Priority of the HCI socket task.'
+ type: task_priority
+ value: 9
+
+ BLE_SOCK_STACK_SIZE:
+ description: 'Size of the HCI socket stack (units=words).'
+ value: 80
+
+ BLE_SOCK_CLI_SYSINIT_STAGE:
+ description: >
+ Sysinit stage for the socket BLE transport.
+ value: 500
+
+syscfg.vals.BLE_EXT_ADV:
+ BLE_HCI_EVT_BUF_SIZE: 257
diff --git a/src/libs/mynewt-nimble/nimble/transport/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/syscfg.yml
new file mode 100644
index 00000000..137d6e94
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/transport/syscfg.yml
@@ -0,0 +1,68 @@
+# 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_TRANSPORT:
+ description: >
+ Selects HCI transport to be included in build.
+ This has virtually the same effect as including package dependency
+ manually, but it allows to easily override HCI transport package in
+ application or target settings.
+ value: builtin
+ restrictions: $notnull
+ choices:
+ - builtin # Built-in NimBLE controller and RAM transport
+ - custom # Custom transport, has to be included manually by user
+ - ram # RAM transport
+ - uart # UART HCI H4 transport
+ - socket # Socket transport (for native builds)
+ - emspi # SPI transport for EM Microelectionic controllers
+ - da1469x # Dialog DA1469x integrated controller
+
+# Deprecated settings
+ BLE_HCI_TRANSPORT_NIMBLE_BUILTIN:
+ description: Use BLE_HCI_TRANSPORT instead.
+ value: 0
+ deprecated: 1
+ BLE_HCI_TRANSPORT_EMSPI:
+ description: Use BLE_HCI_TRANSPORT instead.
+ value: 0
+ deprecated: 1
+ BLE_HCI_TRANSPORT_RAM:
+ description: Use BLE_HCI_TRANSPORT instead.
+ value: 0
+ deprecated: 1
+ BLE_HCI_TRANSPORT_SOCKET:
+ description: Use BLE_HCI_TRANSPORT instead.
+ value: 0
+ deprecated: 1
+ BLE_HCI_TRANSPORT_UART:
+ description: Use BLE_HCI_TRANSPORT instead.
+ value: 0
+ deprecated: 1
+
+syscfg.vals.BLE_HCI_TRANSPORT_NIMBLE_BUILTIN:
+ BLE_HCI_TRANSPORT: builtin
+syscfg.vals.BLE_HCI_TRANSPORT_RAM:
+ BLE_HCI_TRANSPORT: ram
+syscfg.vals.BLE_HCI_TRANSPORT_UART:
+ BLE_HCI_TRANSPORT: uart
+syscfg.vals.BLE_HCI_TRANSPORT_SOCKET:
+ BLE_HCI_TRANSPORT: socket
+syscfg.vals.BLE_HCI_TRANSPORT_EMSPI:
+ BLE_HCI_TRANSPORT: emspi
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