From b379434aa53c939b267d5d71a1dc94bf34d4724c Mon Sep 17 00:00:00 2001 From: Dominik Chat Date: Mon, 9 Oct 2023 15:51:06 +0200 Subject: [PATCH] applications: Add ipc_radio firmware code Add ipc_radio firmware code for network core. This image serves purpose as universal network core image for hci_rpmsg rpc_host and IEEE 802.15.4 remote image. Jira: NCSDK-23798 Signed-off-by: Dominik Chat --- CODEOWNERS | 1 + applications/ipc_radio/CMakeLists.txt | 26 ++ applications/ipc_radio/Kconfig | 53 +++ applications/ipc_radio/overlay-802154.conf | 10 + .../ipc_radio/overlay-bt_hci_ipc.conf | 24 ++ applications/ipc_radio/overlay-bt_rpc.conf | 32 ++ applications/ipc_radio/prj.conf | 9 + applications/ipc_radio/sample.yaml | 36 ++ applications/ipc_radio/src/802154.c | 22 + applications/ipc_radio/src/bt_empty.c | 24 ++ applications/ipc_radio/src/bt_hci_ipc.c | 382 ++++++++++++++++++ applications/ipc_radio/src/ipc_bt.h | 42 ++ applications/ipc_radio/src/main.c | 39 ++ sysbuild/Kconfig.netcore | 40 +- sysbuild/netcore.cmake | 28 ++ 15 files changed, 767 insertions(+), 1 deletion(-) create mode 100644 applications/ipc_radio/CMakeLists.txt create mode 100644 applications/ipc_radio/Kconfig create mode 100644 applications/ipc_radio/overlay-802154.conf create mode 100644 applications/ipc_radio/overlay-bt_hci_ipc.conf create mode 100644 applications/ipc_radio/overlay-bt_rpc.conf create mode 100644 applications/ipc_radio/prj.conf create mode 100644 applications/ipc_radio/sample.yaml create mode 100644 applications/ipc_radio/src/802154.c create mode 100644 applications/ipc_radio/src/bt_empty.c create mode 100644 applications/ipc_radio/src/bt_hci_ipc.c create mode 100644 applications/ipc_radio/src/ipc_bt.h create mode 100644 applications/ipc_radio/src/main.c diff --git a/CODEOWNERS b/CODEOWNERS index 8f6145e655a9..2d7272a03edc 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -30,6 +30,7 @@ # Applications /applications/asset_tracker_v2/ @nrfconnect/ncs-cia @coderbyheart /applications/connectivity_bridge/ @nrfconnect/ncs-cia @nordic-auko +/applications/ipc_radio/ @dchat-nordic /applications/machine_learning/ @pdunaj /applications/matter_bridge/ @Damian-Nordic @kkasperczyk-no /applications/matter_weather_station/ @Damian-Nordic @kkasperczyk-no diff --git a/applications/ipc_radio/CMakeLists.txt b/applications/ipc_radio/CMakeLists.txt new file mode 100644 index 000000000000..dfcc9c186aec --- /dev/null +++ b/applications/ipc_radio/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(ipc_radio) + +target_include_directories(app PRIVATE ./src) + +target_sources_ifdef(CONFIG_IPC_RADIO_802154 app PRIVATE src/802154.c) + +if(CONFIG_IPC_RADIO_BT_HCI_IPC) + target_sources(app PRIVATE src/bt_hci_ipc.c) +else() + target_sources(app PRIVATE src/bt_empty.c) +endif() + +# NORDIC SDK APP START +target_sources(app PRIVATE + src/main.c +) +# NORDIC SDK APP END diff --git a/applications/ipc_radio/Kconfig b/applications/ipc_radio/Kconfig new file mode 100644 index 000000000000..82550a967d9c --- /dev/null +++ b/applications/ipc_radio/Kconfig @@ -0,0 +1,53 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +mainmenu "Nordic ipc_radio firmware" + +config IPC_RADIO_802154 + bool "IPC IEEE 802.15.4 radio" + select NRF_802154_SER_RADIO + help + Enable the IPC IEEE 802.15.4 radio serialization. + +config IPC_RADIO_BT + bool "IPC Bluetooth" + help + Enable the IPC Bluetooth radio serialization. + +if IPC_RADIO_BT + +choice IPC_RADIO_BT_SER + default IPC_RADIO_BT_HCI_IPC + prompt "Bluetooth serialization type" + help + Type of the IPC Bluetooth radio serialization used. + +config IPC_RADIO_BT_HCI_IPC + bool "Bluetooth HCI serialization" + depends on IPC_SERVICE + depends on BT_HCI_RAW + help + Use Bluetooth HCI serialization over ipc_service. + +config IPC_RADIO_BT_RPC + bool "Bluetooth host API serialization over RPC" + depends on BT_RPC_HOST + help + Use nRF RPC serialization for Bluetooth. + +endchoice # IPC_RADIO_BT_SER + +config BT_MAX_CONN + default 4 if IPC_RADIO_802154 + default 16 if !IPC_RADIO_802154 + +endif # IPC_RADIO_BT + +module = IPC_RADIO +module-str = "ipc_radio" +source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config" + +source "Kconfig.zephyr" diff --git a/applications/ipc_radio/overlay-802154.conf b/applications/ipc_radio/overlay-802154.conf new file mode 100644 index 000000000000..cdb702838b49 --- /dev/null +++ b/applications/ipc_radio/overlay-802154.conf @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_NRF_802154_SER_RADIO=y +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=2 + +CONFIG_IPC_RADIO_802154=y diff --git a/applications/ipc_radio/overlay-bt_hci_ipc.conf b/applications/ipc_radio/overlay-bt_hci_ipc.conf new file mode 100644 index 000000000000..f08b7f62183b --- /dev/null +++ b/applications/ipc_radio/overlay-bt_hci_ipc.conf @@ -0,0 +1,24 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +CONFIG_MBOX=y +CONFIG_IPC_SERVICE=y + +CONFIG_BT=y +CONFIG_BT_HCI_RAW=y +CONFIG_BT_CTLR_ASSERT_HANDLER=y +CONFIG_BT_HCI_RAW_RESERVE=1 + +CONFIG_ASSERT=y +CONFIG_DEBUG_INFO=y +CONFIG_EXCEPTION_STACK_TRACE=y + +CONFIG_IPC_RADIO_BT=y +CONFIG_IPC_RADIO_BT_HCI_IPC=y diff --git a/applications/ipc_radio/overlay-bt_rpc.conf b/applications/ipc_radio/overlay-bt_rpc.conf new file mode 100644 index 000000000000..fcd0273fbe6e --- /dev/null +++ b/applications/ipc_radio/overlay-bt_rpc.conf @@ -0,0 +1,32 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_NRF_RPC_THREAD_STACK_SIZE=4096 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 + +CONFIG_BT=y +CONFIG_BT_RPC=y +CONFIG_BT_RPC_HOST=y + +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_MAX_CONN=1 +CONFIG_BT_MAX_PAIRED=1 +CONFIG_BT_SMP=y + +# Host side registers all GATT services using dynamic database +CONFIG_BT_GATT_DYNAMIC_DB=y + +# Enable bonding +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y +CONFIG_SETTINGS=y + +CONFIG_IPC_RADIO_BT=y +CONFIG_IPC_RADIO_BT_RPC=y diff --git a/applications/ipc_radio/prj.conf b/applications/ipc_radio/prj.conf new file mode 100644 index 000000000000..77b0c3e69f2a --- /dev/null +++ b/applications/ipc_radio/prj.conf @@ -0,0 +1,9 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_SERIAL=n +CONFIG_UART_CONSOLE=n +CONFIG_LOG=n diff --git a/applications/ipc_radio/sample.yaml b/applications/ipc_radio/sample.yaml new file mode 100644 index 000000000000..3c83abe14b84 --- /dev/null +++ b/applications/ipc_radio/sample.yaml @@ -0,0 +1,36 @@ +sample: + name: IPC radio firmware + description: IPC radio firmware application +tests: + applications.ipc_radio.hci: + build_only: true + platform_allow: nrf5340dk_nrf5340_cpunet thingy53_nrf5340_cpunet + tags: bluetooth ci_build + integration_platforms: + - nrf5340dk_nrf5340_cpunet + - thingy53_nrf5340_cpunet + extra_args: EXTRA_CONF_FILE=overlay-bt_hci_ipc.conf + applications.ipc_radio.rpc: + build_only: true + platform_allow: nrf5340dk_nrf5340_cpunet thingy53_nrf5340_cpunet + tags: bluetooth ci_build + integration_platforms: + - nrf5340dk_nrf5340_cpunet + - thingy53_nrf5340_cpunet + extra_args: EXTRA_CONF_FILE=overlay-bt_rpc.conf + applications.ipc_radio.802154: + build_only: true + platform_allow: nrf5340dk_nrf5340_cpunet thingy53_nrf5340_cpunet + tags: ci_build + integration_platforms: + - nrf5340dk_nrf5340_cpunet + - thingy53_nrf5340_cpunet + extra_args: EXTRA_CONF_FILE=overlay-802154.conf + applications.ipc_radio.hci802154: + build_only: true + platform_allow: nrf5340dk_nrf5340_cpunet thingy53_nrf5340_cpunet + tags: bluetooth ci_build + integration_platforms: + - nrf5340dk_nrf5340_cpunet + - thingy53_nrf5340_cpunet + extra_args: EXTRA_CONF_FILE="overlay-bt_hci_ipc.conf;overlay-802154.conf" diff --git a/applications/ipc_radio/src/802154.c b/applications/ipc_radio/src/802154.c new file mode 100644 index 000000000000..32077119969e --- /dev/null +++ b/applications/ipc_radio/src/802154.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include + +void nrf_802154_serialization_error(const nrf_802154_ser_err_data_t *err) +{ + ARG_UNUSED(err); + __ASSERT(false, "802.15.4 serialization error"); + k_oops(); +} + +void nrf_802154_sl_fault_handler(uint32_t id, int32_t line, const char *err) +{ + __ASSERT(false, "module_id: %u, line: %d, %s", id, line, err); + k_oops(); +} diff --git a/applications/ipc_radio/src/bt_empty.c b/applications/ipc_radio/src/bt_empty.c new file mode 100644 index 000000000000..e12a8f277202 --- /dev/null +++ b/applications/ipc_radio/src/bt_empty.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include + +#include "ipc_bt.h" + +LOG_MODULE_DECLARE(ipc_radio, CONFIG_IPC_RADIO_LOG_LEVEL); + +int ipc_bt_init(void) +{ + LOG_DBG("Empty ipc_bt_init called."); + return -ENOSYS; +} + +int ipc_bt_process(void) +{ + LOG_DBG("Empty ipc_bt_process called."); + return -ENOSYS; +} diff --git a/applications/ipc_radio/src/bt_hci_ipc.c b/applications/ipc_radio/src/bt_hci_ipc.c new file mode 100644 index 000000000000..161cdeef9851 --- /dev/null +++ b/applications/ipc_radio/src/bt_hci_ipc.c @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#if defined(CONFIG_BT_HCI_VS_FATAL_ERROR) +#include +#endif /* CONFIG_BT_HCI_VS_FATAL_ERROR */ + +#include + +#include "ipc_bt.h" + +LOG_MODULE_DECLARE(ipc_radio, CONFIG_IPC_RADIO_LOG_LEVEL); + +#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) || defined(CONFIG_BT_HCI_VS_FATAL_ERROR) +static bool ipc_ept_ready; +#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER || CONFIG_BT_HCI_VS_FATAL_ERROR */ + +static K_SEM_DEFINE(ipc_bound_sem, 0, 1); + +static struct ipc_ept hci_ept; + +static K_FIFO_DEFINE(tx_queue); +static K_FIFO_DEFINE(rx_queue); + +enum hci_h4_type { + HCI_H4_CMD = 0x01, /* rx */ + HCI_H4_ACL = 0x02, /* rx */ + HCI_H4_EVT = 0x04, /* tx */ + HCI_H4_ISO = 0x05 /* rx */ +}; + +#define HCI_FATAL_MSG true +#define HCI_REGULAR_MSG false + +static void recv_cmd(const uint8_t *data, size_t len) +{ + const struct bt_hci_cmd_hdr *hdr = (const struct bt_hci_cmd_hdr *)data; + struct net_buf *buf; + + if (len < sizeof(*hdr)) { + LOG_ERR("Not enough data for command header."); + return; + } + + if ((len - sizeof(*hdr)) != hdr->param_len) { + LOG_ERR("Command param_len does not match the remaining data length."); + return; + } + + buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, hdr, sizeof(*hdr)); + if (!buf) { + LOG_ERR("No available command buffers."); + return; + } + + data += sizeof(*hdr); + len -= sizeof(*hdr); + + if (len > net_buf_tailroom(buf)) { + LOG_ERR("Not enough space in buffer."); + net_buf_unref(buf); + return; + } + + LOG_DBG("Received HCI CMD packet (opcode: %#x, len: %u).", + sys_le16_to_cpu(hdr->opcode), hdr->param_len); + + net_buf_add_mem(buf, data, len); + net_buf_put(&tx_queue, buf); +} + +static void recv_acl(const uint8_t *data, size_t len) +{ + const struct bt_hci_acl_hdr *hdr = (const struct bt_hci_acl_hdr *)data; + struct net_buf *buf; + + if (len < sizeof(*hdr)) { + LOG_ERR("Not enough data for ACL header."); + return; + } + + if ((len - sizeof(*hdr)) != sys_le16_to_cpu(hdr->len)) { + LOG_ERR("ACL payload length does not match the remaining data length."); + return; + } + + buf = bt_buf_get_tx(BT_BUF_ACL_OUT, K_NO_WAIT, hdr, sizeof(*hdr)); + if (!buf) { + LOG_ERR("No available ACL buffers."); + return; + } + + data += sizeof(*hdr); + len -= sizeof(*hdr); + + if (len > net_buf_tailroom(buf)) { + LOG_ERR("Not enough space in buffer."); + net_buf_unref(buf); + return; + } + + LOG_DBG("Received HCI ACL packet (handle: %u, len: %u).", + sys_le16_to_cpu(hdr->handle), sys_le16_to_cpu(hdr->len)); + + net_buf_add_mem(buf, data, len); + net_buf_put(&tx_queue, buf); +} + +static void recv_iso(const uint8_t *data, size_t len) +{ + const struct bt_hci_iso_hdr *hdr = (const struct bt_hci_iso_hdr *)data; + struct net_buf *buf; + + if (len < sizeof(*hdr)) { + LOG_ERR("Not enough data for ISO header."); + return; + } + + if ((len - sizeof(*hdr)) != bt_iso_hdr_len(sys_le16_to_cpu(hdr->len))) { + LOG_ERR("ISO payload length does not match the remaining data length."); + return; + } + + buf = bt_buf_get_tx(BT_BUF_ISO_OUT, K_NO_WAIT, hdr, sizeof(*hdr)); + if (!buf) { + LOG_ERR("No available ISO buffers."); + return; + } + + data += sizeof(*hdr); + len -= sizeof(*hdr); + + if (len > net_buf_tailroom(buf)) { + LOG_ERR("Not enough space in buffer."); + net_buf_unref(buf); + return; + } + + LOG_DBG("Received HCI ISO packet (handle: %u, len: %u).", + sys_le16_to_cpu(hdr->handle), sys_le16_to_cpu(hdr->len)); + + net_buf_add_mem(buf, data, len); + net_buf_put(&tx_queue, buf); +} + +static void send(struct net_buf *buf, bool is_fatal_err) +{ + uint8_t type; + uint8_t retries = 0; + int ret; + + LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); + LOG_HEXDUMP_DBG(buf->data, buf->len, "Controller buffer:"); + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_IN: + type = HCI_H4_ACL; + break; + case BT_BUF_EVT: + type = HCI_H4_EVT; + break; + case BT_BUF_ISO_IN: + type = HCI_H4_ISO; + break; + default: + LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); + net_buf_unref(buf); + return; + } + net_buf_push_u8(buf, type); + + LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:"); + + do { + ret = ipc_service_send(&hci_ept, buf->data, buf->len); + if (ret < 0) { + retries++; + if (retries > 10) { + LOG_WRN("IPC send has been blocked during 10 retires."); + retries = 0; + } + + if (is_fatal_err) { + LOG_ERR("IPC service send error: %d", ret); + } else { + k_yield(); + } + } + } while (ret < 0); + + LOG_INF("Sent message of %d bytes.", ret); + + net_buf_unref(buf); +} + +static void bound(void *priv) +{ +#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) || defined(CONFIG_BT_HCI_VS_FATAL_ERROR) + ipc_ept_ready = true; +#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER || CONFIG_BT_HCI_VS_FATAL_ERROR */ + + k_sem_give(&ipc_bound_sem); +} + +static void recv(const void *data, size_t len, void *priv) +{ + const uint8_t *tmp = (const uint8_t *)data; + enum hci_h4_type type; + + LOG_INF("Received hci message of %u bytes.", len); + LOG_HEXDUMP_DBG(data, len, "HCI data:"); + + type = (enum hci_h4_type)*tmp++; + len -= sizeof(type); + + switch (type) { + case HCI_H4_CMD: + recv_cmd(tmp, len); + break; + + case HCI_H4_ACL: + recv_acl(tmp, len); + break; + + case HCI_H4_ISO: + recv_iso(tmp, len); + break; + + default: + LOG_ERR("Unknown HCI type %u.", type); + return; + } +} + +static void tx_thread(void) +{ + struct net_buf *buf; + int err; + + while (1) { + buf = net_buf_get(&tx_queue, K_FOREVER); + err = bt_send(buf); + if (err) { + LOG_ERR("bt_send failed err: %d.", err); + net_buf_unref(buf); + } + + k_yield(); + } +} + +K_THREAD_DEFINE(tx_thread_id, CONFIG_BT_HCI_TX_STACK_SIZE, tx_thread, + NULL, NULL, NULL, + CONFIG_BT_HCI_TX_PRIO, 0, 0); + +static struct ipc_ept_cfg hci_ept_cfg = { + .name = "nrf_bt_hci", + .cb = { + .bound = bound, + .received = recv, + }, +}; + +#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) +void bt_ctlr_assert_handle(char *file, uint32_t line) +{ + (void)irq_lock(); + + LOG_ERR("HCI Fatal error in: %s at %d.", file, line); + +#if defined(CONFIG_BT_HCI_VS_FATAL_ERROR) + if (ipc_ept_ready) { + struct net_buf *buf; + + buf = hci_vs_err_assert(file, line); + if (!buf) { + send(buf, HCI_FATAL_MSG); + } else { + LOG_ERR("Can't send Fatal Error HCI event."); + } + } else { + LOG_ERR("HCI Fatal error before IPC endpoint is ready."); + } + +#else /* !CONFIG_BT_HCI_VS_FATAL_ERROR */ + LOG_ERR("Controller assert in: %s at %d.", file, line); + +#endif /* !CONFIG_BT_HCI_VS_FATAL_ERROR */ + + for (;;) { + }; +} +#endif /* CONFIG_BT_CTLR_ASSERT_HANDLER */ + +#if defined(CONFIG_BT_HCI_VS_FATAL_ERROR) +void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t *esf) +{ + LOG_PANIC(); + + (void)irq_lock(); + + if ((!esf) && (ipc_ept_ready)) { + struct net_buf *buf; + + buf = hci_vs_err_stack_frame(reason, esf); + if (!buf) { + send(buf, HCI_FATAL_MSG); + } else { + LOG_ERR("Can't create Fatal Error HCI event."); + } + } + + for (;;) { + }; + + CODE_UNREACHABLE; +} +#endif /* CONFIG_BT_HCI_VS_FATAL_ERROR */ + +int ipc_bt_init(void) +{ + int err; + const struct device *hci_ipc_instance = DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_hci_ipc)); + + LOG_INF("Initializing ipc_radio bt_hci."); + + err = bt_enable_raw(&rx_queue); + if (err) { + LOG_ERR("bt_enable_raw failed: %d.", err); + return err; + } + + err = ipc_service_open_instance(hci_ipc_instance); + if ((err < 0) && (err != -EALREADY)) { + LOG_ERR("IPC service instance initialization failed: %d.", err); + return err; + } + + err = ipc_service_register_endpoint(hci_ipc_instance, &hci_ept, &hci_ept_cfg); + if (err) { + LOG_ERR("Registering endpoint failed: %d.", err); + return err; + } + + return 0; +} + +int ipc_bt_process(void) +{ + struct net_buf *buf; + + k_sem_take(&ipc_bound_sem, K_FOREVER); + + while (1) { + buf = net_buf_get(&rx_queue, K_FOREVER); + send(buf, HCI_REGULAR_MSG); + } + + return 0; +} diff --git a/applications/ipc_radio/src/ipc_bt.h b/applications/ipc_radio/src/ipc_bt.h new file mode 100644 index 000000000000..c24d554333f8 --- /dev/null +++ b/applications/ipc_radio/src/ipc_bt.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef IPC_BT_H_ +#define IPC_BT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Initialize the IPC Bluetooth interface. + * + * The function might not have any functionality if the interface + * does not need to be initialized (or is initialized automatically). + * When this function is not needed, it should be implemented as an empty + * function and return -ENOSYS. + * + * @retval -ENOSYS The function is not implemented. + * @return 0 in case of success or negative value in case of error. + */ +int ipc_bt_init(void); + +/** @brief Give processing time to the IPC Bluetooth interface. + * + * The function might not have any functionality if the interface + * does not need to be given processing time (or is processed automatically). + * When this function is not needed, it should be implemented as an empty + * function and return -ENOSYS. + * + * @retval -ENOSYS The function is not implemented. + * @return 0 in case of success or negative value in case of error. + */ +int ipc_bt_process(void); + +#ifdef __cplusplus +} +#endif + +#endif /* IPC_BT_H_ */ diff --git a/applications/ipc_radio/src/main.c b/applications/ipc_radio/src/main.c new file mode 100644 index 000000000000..fb058ca57367 --- /dev/null +++ b/applications/ipc_radio/src/main.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include + +#include "ipc_bt.h" + +LOG_MODULE_REGISTER(ipc_radio, CONFIG_IPC_RADIO_LOG_LEVEL); + +#if !(CONFIG_IPC_RADIO_802154 || CONFIG_IPC_RADIO_BT) +#error "No radio serialization selected." +#endif + +int main(void) +{ + int err; + + err = ipc_bt_init(); + if ((err) && (err != -ENOSYS)) { + LOG_ERR("Error initializing ipc radio %d", err); + return err; + } + + for (;;) { + err = ipc_bt_process(); + + if (err == -ENOSYS) { + /* Particular implementation does not need the process function */ + return 0; + } else if (err) { + LOG_ERR("Error processing ipc radio %d", err); + return err; + } + } +} diff --git a/sysbuild/Kconfig.netcore b/sysbuild/Kconfig.netcore index 6f2cea544f24..8043c5191d91 100644 --- a/sysbuild/Kconfig.netcore +++ b/sysbuild/Kconfig.netcore @@ -46,6 +46,10 @@ config SUPPORT_NETCORE_MULTIPROTOCOL_RPMSG bool default y +config SUPPORT_NETCORE_IPC_RADIO + bool + default y + config NRF_DEFAULT_EMPTY bool @@ -58,12 +62,16 @@ config NRF_DEFAULT_802154 config NRF_DEFAULT_MULTIPROTOCOL bool +config NRF_DEFAULT_IPC_RADIO + bool + choice NETCORE prompt "Netcore image" default NETCORE_EMPTY if NRF_DEFAULT_EMPTY && NETCORE_REMOTE_BOARD_NAME != "" default NETCORE_HCI_IPC if NRF_DEFAULT_BLUETOOTH && NETCORE_REMOTE_BOARD_NAME != "" default NETCORE_802154_RPMSG if NRF_DEFAULT_802154 && NETCORE_REMOTE_BOARD_NAME != "" default NETCORE_MULTIPROTOCOL_RPMSG if NRF_DEFAULT_MULTIPROTOCOL && NETCORE_REMOTE_BOARD_NAME != "" + default NETCORE_IPC_RADIO if NRF_DEFAULT_IPC_RADIO && NETCORE_REMOTE_BOARD_NAME != "" default NETCORE_NONE depends on SUPPORT_NETCORE && !EXTERNAL_CONFIGURED_NETCORE @@ -101,6 +109,15 @@ config NETCORE_MULTIPROTOCOL_RPMSG help Include multiprotocol_rpmsg as the netcore image to use +config NETCORE_IPC_RADIO + bool "ipc_radio [Experimental]" + depends on SUPPORT_NETCORE_IPC_RADIO + select EXPERIMENTAL + help + Add ipc_radio as a netcore image to use. + The image can be configured as Bluetooth radio, + IEEE 802.15.4 radio or left empty. + endchoice if !NETCORE_NONE @@ -112,6 +129,7 @@ config NETCORE_IMAGE_NAME default "rpc_host" if NETCORE_RPC_HOST default "802154_rpmsg" if NETCORE_802154_RPMSG default "multiprotocol_rpmsg" if NETCORE_MULTIPROTOCOL_RPMSG + default "ipc_radio" if NETCORE_IPC_RADIO help Name of netcore image. @@ -122,6 +140,7 @@ config NETCORE_IMAGE_PATH default "${ZEPHYR_NRF_MODULE_DIR}/samples/bluetooth/rpc_host" if NETCORE_RPC_HOST default "${ZEPHYR_BASE}/samples/boards/nrf/ieee802154/802154_rpmsg" if NETCORE_802154_RPMSG default "${ZEPHYR_NRF_MODULE_DIR}/samples/nrf5340/multiprotocol_rpmsg" if NETCORE_MULTIPROTOCOL_RPMSG + default "${ZEPHYR_NRF_MODULE_DIR}/applications/ipc_radio" if NETCORE_IPC_RADIO help Source directory of netcore image. @@ -145,6 +164,25 @@ config NETCORE_APP_UPDATE Enabling this will add support for network core updates from the application core, requires b0n for network core and MCUboot for application core. -endif +if NETCORE_IPC_RADIO + +config NETCORE_IPC_RADIO_BT_HCI_IPC + bool + help + Use HCI serialization for Bluetooth + +config NETCORE_IPC_RADIO_BT_RPC + bool + help + Use nRF RPC serialization for Bluetooth + +config NETCORE_IPC_RADIO_IEEE802154 + bool + help + Use Spinel serialization for IEEE 802.15.4 + +endif # NETCORE_IPC_RADIO + +endif # !NETCORE_NONE endmenu diff --git a/sysbuild/netcore.cmake b/sysbuild/netcore.cmake index c54c879b3ec5..d3a9374b210c 100644 --- a/sysbuild/netcore.cmake +++ b/sysbuild/netcore.cmake @@ -31,4 +31,32 @@ if(SB_CONFIG_SUPPORT_NETCORE AND NOT SB_CONFIG_NETCORE_NONE AND DEFINED SB_CONFI ) endif() +# Include ipc_radio overlays if ipc_radio is enabled. +if(SB_CONFIG_NETCORE_IPC_RADIO) + if(SB_CONFIG_NETCORE_IPC_RADIO_BT_HCI_IPC AND SB_CONFIG_NETCORE_IPC_RADIO_BT_RPC) + message(FATAL_ERROR "HCI IPC can't be used together with BT RPC as ipc_radio configuration.") + endif() + + if(SB_CONFIG_NETCORE_IPC_RADIO_BT_RPC) + add_overlay_config( + ${SB_CONFIG_NETCORE_IMAGE_NAME} + ${SB_CONFIG_NETCORE_IMAGE_PATH}/overlay-bt_rpc.conf + ) + endif() + + if(SB_CONFIG_NETCORE_IPC_RADIO_BT_HCI_IPC) + add_overlay_config( + ${SB_CONFIG_NETCORE_IMAGE_NAME} + ${SB_CONFIG_NETCORE_IMAGE_PATH}/overlay-bt_hci_ipc.conf + ) + endif() + + if(SB_CONFIG_NETCORE_IPC_RADIO_IEEE802154) + add_overlay_config( + ${SB_CONFIG_NETCORE_IMAGE_NAME} + ${SB_CONFIG_NETCORE_IMAGE_PATH}/overlay-802154.conf + ) + endif() +endif() + set_property(GLOBAL PROPERTY PM_DOMAINS ${PM_DOMAINS})