From 76f90e212a1ea770db2fdca9d6d85b532da72350 Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Thu, 26 Sep 2024 16:16:59 +0200 Subject: [PATCH] nimble/transport: Add support for IPC ICBMsg transport Tested with nRF5340. --- nimble/controller/src/ble_ll.c | 2 + nimble/controller/syscfg.yml | 8 + .../include/nimble/transport/hci_ipc.h | 21 ++ nimble/transport/common/hci_ipc/src/hci_ipc.c | 33 ++- nimble/transport/common/hci_ipc/syscfg.yml | 24 ++ nimble/transport/ipc_icbmsg/pkg.yml | 36 +++ .../transport/ipc_icbmsg/src/icbmsg_ble_hci.c | 205 ++++++++++++++++++ nimble/transport/ipc_icbmsg/syscfg.yml | 20 ++ nimble/transport/nrf5340/pkg.yml | 2 +- nimble/transport/pkg.yml | 2 + nimble/transport/syscfg.yml | 2 + 11 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 nimble/transport/common/hci_ipc/syscfg.yml create mode 100644 nimble/transport/ipc_icbmsg/pkg.yml create mode 100644 nimble/transport/ipc_icbmsg/src/icbmsg_ble_hci.c create mode 100644 nimble/transport/ipc_icbmsg/syscfg.yml diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c index 7e87891ab5..69bb758641 100644 --- a/nimble/controller/src/ble_ll.c +++ b/nimble/controller/src/ble_ll.c @@ -2006,7 +2006,9 @@ void ble_transport_ll_init(void) { /* Tell the host that we are ready to receive packets */ +#if MYNEWT_VAL(BLE_LL_HCI_NOOP_AFTER_INIT) ble_ll_hci_send_noop(); +#endif } int diff --git a/nimble/controller/syscfg.yml b/nimble/controller/syscfg.yml index e77a1de44b..cf86699473 100644 --- a/nimble/controller/syscfg.yml +++ b/nimble/controller/syscfg.yml @@ -226,6 +226,11 @@ syscfg.defs: Enables LLCP tracing using HCI vendor-specific events. value: '0' + BLE_LL_HCI_NOOP_AFTER_INIT: + description: > + Enables sending the NO-OP opcode HCI event after LL init. + value: '1' + # Configuration for LL supported features. # # There are a total 8 features that the LL can support. These can be found @@ -643,6 +648,9 @@ syscfg.vals.BLE_LL_ISO_BROADCASTER: syscfg.vals.'!BLE_HOST && !BABBLESIM': BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 +syscfg.vals.'BLE_TRANSPORT_HS=="ipc_icbmsg"': + BLE_LL_HCI_NOOP_AFTER_INIT: 0 + syscfg.restrictions: - BLE_TRANSPORT_LL == "native" - BLE_LL_PUBLIC_DEV_ADDR <= 0xffffffffffff diff --git a/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h b/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h index 551fb93d4c..1bbff12773 100644 --- a/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h +++ b/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h @@ -21,13 +21,26 @@ #define _HCI_IPC_H_ #include +#include +#if MYNEWT_VAL(IPC_ICBMSG) +#include "nimble/hci_common.h" +#define HCI_IPC_TYPE_CMD 0x01 +#define HCI_IPC_TYPE_ACL 0x02 +/* #define HCI_IPC_TYPE_SCO 0x03 */ +#define HCI_IPC_TYPE_EVT 0x04 +#define HCI_IPC_TYPE_ISO 0x05 +/* These two are not used actually */ +#define HCI_IPC_TYPE_EVT_DISCARDABLE 0x06 +#define HCI_IPC_TYPE_EVT_IN_CMD 0x07 +#else #define HCI_IPC_TYPE_CMD 0x01 #define HCI_IPC_TYPE_ACL 0x02 #define HCI_IPC_TYPE_EVT 0x04 #define HCI_IPC_TYPE_EVT_DISCARDABLE 0x05 #define HCI_IPC_TYPE_EVT_IN_CMD 0x06 #define HCI_IPC_TYPE_ISO 0x07 +#endif struct __attribute__((packed)) hci_ipc_hdr { uint8_t type; @@ -55,15 +68,20 @@ struct hci_ipc_shm { void hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm); int hci_ipc_rx(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len); +#if !MYNEWT_VAL(IPC_ICBMSG) extern void hci_ipc_atomic_put(volatile uint16_t *num); extern uint16_t hci_ipc_atomic_get(volatile uint16_t *num); /* Just to optimize static inlines below, do not use directly! */ extern volatile struct hci_ipc_shm *g_ipc_shm; +#endif static inline int hci_ipc_get(uint8_t type) { +#if MYNEWT_VAL(IPC_ICBMSG) + return 1; +#else volatile struct hci_ipc_shm *shm = g_ipc_shm; switch (type) { @@ -76,11 +94,13 @@ hci_ipc_get(uint8_t type) } return 0; +#endif } static inline void hci_ipc_put(uint8_t type) { +#if !MYNEWT_VAL(IPC_ICBMSG) volatile struct hci_ipc_shm *shm = g_ipc_shm; switch (type) { @@ -94,6 +114,7 @@ hci_ipc_put(uint8_t type) hci_ipc_atomic_put(&shm->n2a_num_evt_disc); break; } +#endif } #endif /* _HCI_IPC_H_ */ diff --git a/nimble/transport/common/hci_ipc/src/hci_ipc.c b/nimble/transport/common/hci_ipc/src/hci_ipc.c index f1ebbd8953..faea9dce8a 100644 --- a/nimble/transport/common/hci_ipc/src/hci_ipc.c +++ b/nimble/transport/common/hci_ipc/src/hci_ipc.c @@ -87,7 +87,11 @@ hci_ipc_alloc(struct hci_ipc_sm *sm) static bool hci_ipc_has_hdr(struct hci_ipc_sm *sm) { +#if MYNEWT_VAL(IPC_ICBMSG) + return sm->hdr_len == sizeof(sm->hdr.type); +#else return sm->hdr_len == sizeof(sm->hdr); +#endif } static void @@ -137,9 +141,33 @@ hci_ipc_frame(struct hci_ipc_sm *sm) sm->buf = NULL; } +#if MYNEWT_VAL(IPC_ICBMSG) +static uint16_t +hci_ipc_get_pkt_size(const uint8_t *buf, uint8_t type) +{ + switch (type) { + case HCI_IPC_TYPE_ACL: + return sizeof(struct hci_data_hdr) + get_le16(&((struct hci_data_hdr *)buf)->hdh_len); + case HCI_IPC_TYPE_EVT: + return sizeof(struct ble_hci_ev) + ((struct ble_hci_ev *)buf)->length; + case HCI_IPC_TYPE_CMD: + return sizeof(struct ble_hci_cmd) + ((struct ble_hci_cmd *)buf)->length; + case HCI_IPC_TYPE_ISO: + return sizeof(struct ble_hci_iso) + get_le16(&((struct ble_hci_iso *)buf)->length); + } + + return 0; +} +#endif + static uint16_t hci_ipc_copy_to_hdr(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len) { +#if MYNEWT_VAL(IPC_ICBMSG) + len = 1; + sm->hdr.type = buf[0]; + sm->hdr.length = hci_ipc_get_pkt_size(buf + 1, sm->hdr.type); +#else uint16_t rem_hdr_len; uint8_t *p; @@ -152,6 +180,7 @@ hci_ipc_copy_to_hdr(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len) p = (void *)&sm->hdr; memcpy(p + sm->hdr_len, buf, len); +#endif sm->hdr_len += len; @@ -225,10 +254,11 @@ hci_ipc_rx(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len) void hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm) { + memset(sm, 0, sizeof(*sm)); +#if !MYNEWT_VAL(IPC_ICBMSG) assert(g_ipc_shm == NULL); g_ipc_shm = shm; - memset(sm, 0, sizeof(*sm)); #if MYNEWT_VAL(BLE_CONTROLLER) while (shm->n2a_num_evt_disc == 0) { @@ -239,4 +269,5 @@ hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm) shm->n2a_num_evt = MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT); shm->n2a_num_evt_disc = MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT); #endif +#endif } diff --git a/nimble/transport/common/hci_ipc/syscfg.yml b/nimble/transport/common/hci_ipc/syscfg.yml new file mode 100644 index 0000000000..400027437e --- /dev/null +++ b/nimble/transport/common/hci_ipc/syscfg.yml @@ -0,0 +1,24 @@ +# 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: + IPC_ICBMSG: + description: 'Enables controller support for the Central role.' + value: 0 + +syscfg.vals.'BLE_TRANSPORT_LL=="ipc_icbmsg" || BLE_TRANSPORT_HS=="ipc_icbmsg"': + IPC_ICBMSG: 1 diff --git a/nimble/transport/ipc_icbmsg/pkg.yml b/nimble/transport/ipc_icbmsg/pkg.yml new file mode 100644 index 0000000000..9a1f8a3575 --- /dev/null +++ b/nimble/transport/ipc_icbmsg/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/ipc_icbmsg +pkg.description: HCI transport via IPC with ICBMsg backend +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - ipc_icbmsg + +pkg.deps: + - nimble + - nimble/transport/common/hci_ipc + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/hw/drivers/ipc_icbmsg" + +pkg.apis: + - ble_transport diff --git a/nimble/transport/ipc_icbmsg/src/icbmsg_ble_hci.c b/nimble/transport/ipc_icbmsg/src/icbmsg_ble_hci.c new file mode 100644 index 0000000000..30875b2f07 --- /dev/null +++ b/nimble/transport/ipc_icbmsg/src/icbmsg_ble_hci.c @@ -0,0 +1,205 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#define BLE_HCI_IPC_ID (0) + +static struct hci_ipc_sm g_hci_ipc_sm; + +static void ble_hci_trans_rx(const void *data, size_t len, void *user_data); +static struct ipc_ept_cfg hci_ept_cfg = { + .name = "nrf_bt_hci", + .cb = { + .received = ble_hci_trans_rx, + }, + .tx_channel = 1, + .rx_channel = 0, +}; +static uint8_t hci_ept_local_addr; + +static int +icbmsg_ble_hci_send_mbuf(uint8_t type, struct os_mbuf *om) +{ + int rc; + struct os_mbuf *x; + struct ipc_icmsg_buf buf; + + rc = ipc_icbmsg_alloc_tx_buf(BLE_HCI_IPC_ID, &buf, + 1 + OS_MBUF_PKTHDR(om)->omp_len); + assert(rc == 0); + if (rc != 0) { + return BLE_ERR_MEM_CAPACITY; + } + + buf.data[0] = type; + buf.len = 1; + + x = om; + while (x) { + memcpy(buf.data + buf.len, x->om_data, x->om_len); + buf.len += x->om_len; + x = SLIST_NEXT(x, om_next); + } + + rc = ipc_icbmsg_send_buf(BLE_HCI_IPC_ID, hci_ept_local_addr, &buf); + + os_mbuf_free_chain(om); + + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; +} + +static int +icbmsg_ble_hci_acl_tx(struct os_mbuf *om) +{ + return icbmsg_ble_hci_send_mbuf(HCI_IPC_TYPE_ACL, om); +} + +#if !MYNEWT_VAL(BLE_CONTROLLER) +static int +icbmsg_ble_hci_iso_tx(struct os_mbuf *om) +{ + return icbmsg_ble_hci_send_mbuf(HCI_IPC_TYPE_ISO, om); +} +#endif + +static void +ble_hci_trans_rx(const void *data, size_t len, void *user_data) +{ + hci_ipc_rx(&g_hci_ipc_sm, data, len); +} + +static void +icbmsg_ble_hci_init(void) +{ + os_sr_t sr; + + SYSINIT_ASSERT_ACTIVE(); + + OS_ENTER_CRITICAL(sr); + hci_ept_local_addr = ipc_icmsg_register_ept(BLE_HCI_IPC_ID, &hci_ept_cfg); + OS_EXIT_CRITICAL(sr); + + while (!ipc_icsmsg_ept_ready(BLE_HCI_IPC_ID, hci_ept_local_addr)); +} + +#if MYNEWT_VAL(BLE_CONTROLLER) +int +ble_transport_to_hs_evt_impl(void *ev_buf) +{ + int rc; + uint8_t *hci_ev = ev_buf; + struct ipc_icmsg_buf buf; + uint16_t length; + uint8_t type = HCI_IPC_TYPE_EVT; + + /* struct ble_hci_ev */ + length = 2 + hci_ev[1]; + + rc = ipc_icbmsg_alloc_tx_buf(BLE_HCI_IPC_ID, &buf, + 1 + length); + assert(rc == 0); + if (rc != 0) { + return BLE_ERR_MEM_CAPACITY; + } + + buf.data[0] = type; + buf.len = 1; + + memcpy(buf.data + buf.len, hci_ev, length); + buf.len += length; + + rc = ipc_icbmsg_send_buf(BLE_HCI_IPC_ID, hci_ept_local_addr, &buf); + + ble_transport_ipc_free(ev_buf); + + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; +} + +int +ble_transport_to_hs_acl_impl(struct os_mbuf *om) +{ + return icbmsg_ble_hci_acl_tx(om); +} + +void +ble_transport_hs_init(void) +{ + hci_ipc_init(NULL, &g_hci_ipc_sm); + icbmsg_ble_hci_init(); +} +#endif /* BLE_CONTROLLER */ + +#if !MYNEWT_VAL(BLE_CONTROLLER) +int +ble_transport_to_ll_cmd_impl(void *ev_buf) +{ + int rc; + uint8_t *cmd = ev_buf; + struct ipc_icmsg_buf buf; + uint16_t length; + uint8_t type = HCI_IPC_TYPE_CMD; + + /* struct ble_hci_cmd */ + length = 3 + cmd[2]; + + rc = ipc_icbmsg_alloc_tx_buf(BLE_HCI_IPC_ID, &buf, + 1 + length); + assert(rc == 0); + if (rc != 0) { + return BLE_ERR_MEM_CAPACITY; + } + + buf.data[0] = type; + buf.len = 1; + + memcpy(buf.data + buf.len, cmd, length); + buf.len += length; + + ble_transport_ipc_free(ev_buf); + + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; +} + +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) +{ + return icbmsg_ble_hci_acl_tx(om); +} + +int +ble_transport_to_ll_iso_impl(struct os_mbuf *om) +{ + return icbmsg_ble_hci_iso_tx(om); +} + +void +ble_transport_ll_init(void) +{ + hci_ipc_init(NULL, &g_hci_ipc_sm); + icbmsg_ble_hci_init(); +} +#endif /* !BLE_CONTROLLER */ diff --git a/nimble/transport/ipc_icbmsg/syscfg.yml b/nimble/transport/ipc_icbmsg/syscfg.yml new file mode 100644 index 0000000000..a784a79299 --- /dev/null +++ b/nimble/transport/ipc_icbmsg/syscfg.yml @@ -0,0 +1,20 @@ +# 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.vals.BLE_MONITOR: + BLE_TRANSPORT_RX_TASK_STACK_SIZE: 120 + BLE_TRANSPORT_RX_TASK_PRIO: 1 diff --git a/nimble/transport/nrf5340/pkg.yml b/nimble/transport/nrf5340/pkg.yml index be44d0f8d1..ca886b5941 100644 --- a/nimble/transport/nrf5340/pkg.yml +++ b/nimble/transport/nrf5340/pkg.yml @@ -30,7 +30,7 @@ pkg.deps: - nimble - nimble/transport/common/hci_ipc - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/hw/drivers/ipc_nrf5340" + - "@apache-mynewt-core/hw/drivers/ipc_icbmsg" pkg.apis: - ble_transport diff --git a/nimble/transport/pkg.yml b/nimble/transport/pkg.yml index 30237f75bd..b2cfbebd9c 100644 --- a/nimble/transport/pkg.yml +++ b/nimble/transport/pkg.yml @@ -38,6 +38,8 @@ pkg.deps.'BLE_TRANSPORT_HS == "dialog_cmac" || BLE_TRANSPORT_LL == "dialog_cmac" - nimble/transport/dialog_cmac pkg.deps.'BLE_TRANSPORT_HS == "nrf5340" || BLE_TRANSPORT_LL == "nrf5340"': - nimble/transport/nrf5340 +pkg.deps.'BLE_TRANSPORT_HS == "ipc_icbmsg" || BLE_TRANSPORT_LL == "ipc_icbmsg"': + - nimble/transport/ipc_icbmsg pkg.deps.'BLE_TRANSPORT_LL == "socket"': - nimble/transport/socket pkg.deps.'BLE_TRANSPORT_HS == "uart"': diff --git a/nimble/transport/syscfg.yml b/nimble/transport/syscfg.yml index c2b9ec1e91..f2f1d31bbc 100644 --- a/nimble/transport/syscfg.yml +++ b/nimble/transport/syscfg.yml @@ -29,6 +29,7 @@ syscfg.defs: - native - dialog_cmac - nrf5340 + - ipc_icbmsg - uart - usb - cdc @@ -44,6 +45,7 @@ syscfg.defs: - emspi - dialog_cmac - nrf5340 + - ipc_icbmsg - socket - apollo3 - uart_ll