From d90b7274fa8bbfa09f79660b45b550d91f7b0125 Mon Sep 17 00:00:00 2001 From: Jean-François Milants Date: Tue, 2 Feb 2021 22:09:00 +0100 Subject: Update to nimble 1.3 master branch commit 82153e744833821e20e9a8b0d61c38b2b0dbcfe1 WARNING : heartbeat task is disabled! --- .../mynewt-nimble/nimble/transport/usb/pkg.yml | 39 ++ .../nimble/transport/usb/src/ble_hci_usb.c | 410 +++++++++++++++++++++ .../mynewt-nimble/nimble/transport/usb/syscfg.yml | 57 +++ 3 files changed, 506 insertions(+) create mode 100644 src/libs/mynewt-nimble/nimble/transport/usb/pkg.yml create mode 100644 src/libs/mynewt-nimble/nimble/transport/usb/src/ble_hci_usb.c create mode 100644 src/libs/mynewt-nimble/nimble/transport/usb/syscfg.yml (limited to 'src/libs/mynewt-nimble/nimble/transport/usb') diff --git a/src/libs/mynewt-nimble/nimble/transport/usb/pkg.yml b/src/libs/mynewt-nimble/nimble/transport/usb/pkg.yml new file mode 100644 index 00000000..49317c97 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/usb/pkg.yml @@ -0,0 +1,39 @@ +# +# 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/usb +pkg.description: Provides HCI transport over USB interface +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - usb + +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_usb_init: 'MYNEWT_VAL(BLE_TRANS_USB_SYSINIT_STAGE)' diff --git a/src/libs/mynewt-nimble/nimble/transport/usb/src/ble_hci_usb.c b/src/libs/mynewt-nimble/nimble/transport/usb/src/ble_hci_usb.c new file mode 100644 index 00000000..55c91f22 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/usb/src/ble_hci_usb.c @@ -0,0 +1,410 @@ +/* + * 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 +#include +#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 "nimble/hci_common.h" + +#include + +/* + * 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) + +struct usb_ble_hci_pool_cmd { + uint8_t cmd[BLE_HCI_TRANS_CMD_SZ]; + bool allocated; +}; + +/* (Pseudo)pool for HCI commands */ +static struct usb_ble_hci_pool_cmd usb_ble_hci_pool_cmd; + +static ble_hci_trans_rx_cmd_fn *ble_hci_usb_rx_cmd_ll_cb; +static void *ble_hci_usb_rx_cmd_ll_arg; + +static ble_hci_trans_rx_acl_fn *ble_hci_usb_rx_acl_ll_cb; +static void *ble_hci_usb_rx_acl_ll_arg; + +static struct os_mempool ble_hci_usb_evt_hi_pool; +static os_membuf_t ble_hci_usb_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_usb_evt_lo_pool; +static os_membuf_t ble_hci_usb_evt_lo_buf[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) +]; + +static uint8_t ble_hci_pool_acl_mempool_buf[ + OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_ACL_BUF_COUNT), + ACL_BLOCK_SIZE)]; +static struct os_mempool ble_hci_pool_acl_mempool; +static struct os_mbuf_pool ble_hci_pool_acl_mbuf_pool; + +static struct os_mbuf *incoming_acl_data; + +static struct os_mbuf * +ble_hci_trans_acl_buf_alloc(void) +{ + struct os_mbuf *m; + + m = os_mbuf_get_pkthdr(&ble_hci_pool_acl_mbuf_pool, + sizeof(struct ble_mbuf_hdr)); + return m; +} + +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_usb_rx_cmd_ll_cb = cmd_cb; + ble_hci_usb_rx_cmd_ll_arg = cmd_arg; + ble_hci_usb_rx_acl_ll_cb = acl_cb; + ble_hci_usb_rx_acl_ll_arg = acl_arg; +} + +#define BLE_HCI_USB_EVT_COUNT \ + (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT)) + +/** + * A packet to be sent over the USB. This can be a command, an event, or ACL + * data. + */ +struct ble_hci_pkt { + STAILQ_ENTRY(ble_hci_pkt) next; + void *data; +}; + +static struct os_mempool ble_hci_pkt_pool; +static os_membuf_t ble_hci_pkt_buf[ + OS_MEMPOOL_SIZE(BLE_HCI_USB_EVT_COUNT + 1 + + MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), + sizeof(struct ble_hci_pkt))]; + +struct tx_queue { + STAILQ_HEAD(, ble_hci_pkt) queue; +}; + +static struct tx_queue ble_hci_tx_acl_queue = {STAILQ_HEAD_INITIALIZER(ble_hci_tx_acl_queue.queue)}; +static struct tx_queue ble_hci_tx_evt_queue = { STAILQ_HEAD_INITIALIZER(ble_hci_tx_evt_queue.queue) }; + +/* + * TinyUSB callbacks. + */ +void +tud_bt_acl_data_sent_cb(uint16_t sent_bytes) +{ + struct os_mbuf *om; + struct ble_hci_pkt *curr_acl; + struct ble_hci_pkt *next_acl; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + curr_acl = STAILQ_FIRST(&ble_hci_tx_acl_queue.queue); + OS_EXIT_CRITICAL(sr); + + assert(curr_acl != NULL); + om = curr_acl->data; + assert(om != NULL && om->om_len >= sent_bytes); + os_mbuf_adj(om, sent_bytes); + + while (om != NULL && om->om_len == 0) { + curr_acl->data = SLIST_NEXT(om, om_next); + os_mbuf_free(om); + om = curr_acl->data; + } + + if (om == NULL) { + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&ble_hci_tx_acl_queue.queue, next); + next_acl = STAILQ_FIRST(&ble_hci_tx_acl_queue.queue); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&ble_hci_pkt_pool, curr_acl); + if (next_acl != NULL) { + om = next_acl->data; + } + } + + if (om != NULL) { + tud_bt_acl_data_send(om->om_data, om->om_len); + } +} + +void +tud_bt_event_sent_cb(uint16_t sent_bytes) +{ + struct ble_hci_pkt *curr_evt; + struct ble_hci_pkt *next_evt; + uint8_t *hci_ev; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + curr_evt = STAILQ_FIRST(&ble_hci_tx_evt_queue.queue); + OS_EXIT_CRITICAL(sr); + assert(curr_evt != NULL); + hci_ev = curr_evt->data; + + assert(hci_ev != NULL && hci_ev[1] + sizeof(struct ble_hci_ev) == sent_bytes); + + ble_hci_trans_buf_free(hci_ev); + + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&ble_hci_tx_evt_queue.queue, next); + next_evt = STAILQ_FIRST(&ble_hci_tx_evt_queue.queue); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&ble_hci_pkt_pool, curr_evt); + + if (next_evt != NULL) { + hci_ev = next_evt->data; + tud_bt_event_send(hci_ev, hci_ev[1] + sizeof(struct ble_hci_ev)); + } +} + +void +tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len) +{ + uint8_t *data; + uint32_t len; + struct os_mbuf *om = incoming_acl_data; + int rc; + + if (om == NULL) { + om = ble_hci_trans_acl_buf_alloc(); + assert(om != NULL); + } + assert(om->om_len + data_len <= MYNEWT_VAL(BLE_ACL_BUF_SIZE) + BLE_HCI_DATA_HDR_SZ); + + os_mbuf_append(om, acl_data, data_len); + incoming_acl_data = om; + if (om->om_len > BLE_HCI_DATA_HDR_SZ) { + data = incoming_acl_data->om_data; + len = data[2] + (data[3] << 8) + BLE_HCI_DATA_HDR_SZ; + if (len >= incoming_acl_data->om_len) { + incoming_acl_data = NULL; + rc = ble_hci_usb_rx_acl_ll_cb(om, ble_hci_usb_rx_acl_ll_arg); + (void)rc; + } + } +} + +void +tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len) +{ + uint8_t *buf; + int rc = -1; + + assert(ble_hci_usb_rx_cmd_ll_cb); + if (ble_hci_usb_rx_cmd_ll_cb) { + buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + assert(buf != NULL); + memcpy(buf, hci_cmd, cmd_len); + + rc = ble_hci_usb_rx_cmd_ll_cb(buf, ble_hci_usb_rx_cmd_ll_arg); + } + + if (rc != 0) { + ble_hci_trans_buf_free(buf); + } +} + +static int +ble_hci_trans_ll_tx(struct tx_queue *queue, struct os_mbuf *om) +{ + struct ble_hci_pkt *pkt; + os_sr_t sr; + bool first; + + /* 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_pkt_pool); + if (pkt == NULL) { + os_mbuf_free_chain(om); + return BLE_ERR_MEM_CAPACITY; + } + + pkt->data = om; + OS_ENTER_CRITICAL(sr); + first = STAILQ_EMPTY(&queue->queue); + STAILQ_INSERT_TAIL(&queue->queue, pkt, next); + OS_EXIT_CRITICAL(sr); + if (first) { + tud_bt_acl_data_send(om->om_data, om->om_len); + } + + return 0; +} + +int +ble_hci_trans_ll_acl_tx(struct os_mbuf *om) +{ + return ble_hci_trans_ll_tx(&ble_hci_tx_acl_queue, om); +} + +int +ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) +{ + struct ble_hci_pkt *pkt; + os_sr_t sr; + bool first; + + assert(hci_ev != NULL); + + pkt = os_memblock_get(&ble_hci_pkt_pool); + if (pkt == NULL) { + ble_hci_trans_buf_free(hci_ev); + return BLE_ERR_MEM_CAPACITY; + } + + pkt->data = hci_ev; + OS_ENTER_CRITICAL(sr); + first = STAILQ_EMPTY(&ble_hci_tx_evt_queue.queue); + STAILQ_INSERT_TAIL(&ble_hci_tx_evt_queue.queue, pkt, next); + OS_EXIT_CRITICAL(sr); + if (first) { + tud_bt_event_send(hci_ev, hci_ev[1] + sizeof(struct ble_hci_ev)); + } + + return 0; +} + +uint8_t * +ble_hci_trans_buf_alloc(int type) +{ + uint8_t *buf; + + switch (type) { + case BLE_HCI_TRANS_BUF_CMD: + assert(!usb_ble_hci_pool_cmd.allocated); + usb_ble_hci_pool_cmd.allocated = 1; + buf = usb_ble_hci_pool_cmd.cmd; + break; + + case BLE_HCI_TRANS_BUF_EVT_HI: + buf = os_memblock_get(&ble_hci_usb_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_usb_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_usb_evt_hi_pool, buf)) { + rc = os_memblock_put(&ble_hci_usb_evt_hi_pool, buf); + assert(rc == 0); + } else if (os_memblock_from(&ble_hci_usb_evt_lo_pool, buf)) { + rc = os_memblock_put(&ble_hci_usb_evt_lo_pool, buf); + assert(rc == 0); + } else { + assert(usb_ble_hci_pool_cmd.allocated); + usb_ble_hci_pool_cmd.allocated = 0; + } + (void)rc; +} + +int +ble_hci_trans_reset(void) +{ + return 0; +} + +void +ble_hci_usb_init(void) +{ + int rc; + + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + + rc = mem_init_mbuf_pool(ble_hci_pool_acl_mempool_buf, &ble_hci_pool_acl_mempool, &ble_hci_pool_acl_mbuf_pool, + MYNEWT_VAL(BLE_ACL_BUF_COUNT), ACL_BLOCK_SIZE, "ble_hci_acl"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_hci_usb_evt_hi_pool, + MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + ble_hci_usb_evt_hi_buf, + "ble_hci_usb_evt_hi_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_hci_usb_evt_lo_pool, + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), + MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), + ble_hci_usb_evt_lo_buf, + "ble_hci_usb_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_pkt_pool, + BLE_HCI_USB_EVT_COUNT + 1 + + MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), + sizeof (struct ble_hci_pkt), + ble_hci_pkt_buf, + "ble_hci_usb_pkt_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); +} diff --git a/src/libs/mynewt-nimble/nimble/transport/usb/syscfg.yml b/src/libs/mynewt-nimble/nimble/transport/usb/syscfg.yml new file mode 100644 index 00000000..ebc261a2 --- /dev/null +++ b/src/libs/mynewt-nimble/nimble/transport/usb/syscfg.yml @@ -0,0 +1,57 @@ +# 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_TRANS_USB_SYSINIT_STAGE: + description: > + Sysinit stage for the USB BLE transport. + value: 500 + +syscfg.vals.BLE_EXT_ADV: + BLE_HCI_EVT_BUF_SIZE: 257 + +syscfg.restrictions: + - '!BLE_HOST' -- cgit v1.2.3