diff --git a/include/zephyr/bluetooth/buf.h b/include/zephyr/bluetooth/buf.h index 4e6056141f18..0bb59b82d6c7 100644 --- a/include/zephyr/bluetooth/buf.h +++ b/include/zephyr/bluetooth/buf.h @@ -100,13 +100,13 @@ struct bt_buf_data { * available for the HCI driver to allocate from. * * TODO: When CONFIG_BT_BUF_ACL_RX_COUNT is removed, - * remove the MAX and only keep the 1. + * remove the MAX and only keep (CONFIG_BT_MAX_CONN + 1) */ -#define BT_BUF_ACL_RX_COUNT_EXTRA CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA -#define BT_BUF_ACL_RX_COUNT (MAX(CONFIG_BT_BUF_ACL_RX_COUNT, 1) + BT_BUF_ACL_RX_COUNT_EXTRA) +#define BT_BUF_ACL_RX_COUNT \ + (MAX(CONFIG_BT_BUF_ACL_RX_COUNT, (CONFIG_BT_MAX_CONN + 1)) + \ + CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA) #else -#define BT_BUF_ACL_RX_COUNT_EXTRA 0 -#define BT_BUF_ACL_RX_COUNT 0 +#define BT_BUF_ACL_RX_COUNT 0 #endif /* CONFIG_BT_CONN && CONFIG_BT_HCI_HOST */ #if defined(CONFIG_BT_BUF_ACL_RX_COUNT) && CONFIG_BT_BUF_ACL_RX_COUNT > 0 @@ -120,15 +120,10 @@ BUILD_ASSERT(BT_BUF_ACL_RX_COUNT <= BT_BUF_ACL_RX_COUNT_MAX, #define BT_BUF_RX_SIZE (MAX(MAX(BT_BUF_ACL_RX_SIZE, BT_BUF_EVT_RX_SIZE), \ BT_BUF_ISO_RX_SIZE)) -/* Controller can generate up to CONFIG_BT_BUF_ACL_TX_COUNT number of unique HCI Number of Completed - * Packets events. - */ -BUILD_ASSERT(CONFIG_BT_BUF_EVT_RX_COUNT > CONFIG_BT_BUF_ACL_TX_COUNT, - "Increase Event RX buffer count to be greater than ACL TX buffer count"); - -/** Buffer count needed for HCI ACL or HCI ISO plus Event RX buffers */ -#define BT_BUF_RX_COUNT (CONFIG_BT_BUF_EVT_RX_COUNT + \ - MAX(BT_BUF_ACL_RX_COUNT, BT_BUF_ISO_RX_COUNT)) +/** Buffer count needed for HCI ACL, HCI ISO or Event RX buffers */ +#define BT_BUF_RX_COUNT (MAX(MAX(CONFIG_BT_BUF_EVT_RX_COUNT, \ + BT_BUF_ACL_RX_COUNT), \ + BT_BUF_ISO_RX_COUNT)) /** Data size needed for HCI Command buffers. */ #define BT_BUF_CMD_TX_SIZE BT_BUF_CMD_SIZE(CONFIG_BT_BUF_CMD_TX_SIZE) diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf index ed542c44d725..f0a22f760f9b 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bis-bt_ll_sw_split.conf @@ -13,7 +13,12 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=2 +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_EVT_RX_COUNT=16 + CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_ACL_TX_SIZE=251 diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf index 50f071290f95..37e29435d49b 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_bt_mesh-bt_ll_sw_split.conf @@ -11,6 +11,11 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=16 + +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + # Controller CONFIG_BT_LL_SW_SPLIT=y diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf index 1437c5339059..7fab285f3bed 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_cis-bt_ll_sw_split.conf @@ -13,7 +13,12 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=2 +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_EVT_RX_COUNT=16 + CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_ACL_TX_SIZE=251 diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf index 7b6f64d6f411..21d4a042ad75 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_df-bt_ll_sw_split.conf @@ -13,7 +13,12 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=2 +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_EVT_RX_COUNT=16 + CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_ACL_TX_SIZE=251 diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf index 69305951b0bf..e9e5ac634835 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso-bt_ll_sw_split.conf @@ -13,7 +13,12 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=2 +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_EVT_RX_COUNT=16 + CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_ACL_TX_SIZE=251 diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf index c150dc6852b4..f29917aaf935 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_central-bt_ll_sw_split.conf @@ -12,6 +12,10 @@ CONFIG_BT=y CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_ACL_TX_SIZE=251 diff --git a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf index d4388c7685b5..ddd7d7e7b317 100644 --- a/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf +++ b/samples/bluetooth/hci_ipc/nrf5340_cpunet_iso_peripheral-bt_ll_sw_split.conf @@ -12,6 +12,10 @@ CONFIG_BT=y CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_ACL_TX_SIZE=251 diff --git a/samples/bluetooth/hci_ipc/prj.conf b/samples/bluetooth/hci_ipc/prj.conf index e6104e9fe47d..755a1f4ac1e5 100644 --- a/samples/bluetooth/hci_ipc/prj.conf +++ b/samples/bluetooth/hci_ipc/prj.conf @@ -11,6 +11,11 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=16 + +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + # Enable and adjust the below value as necessary # CONFIG_BT_BUF_EVT_RX_COUNT=16 # CONFIG_BT_BUF_EVT_RX_SIZE=255 diff --git a/samples/bluetooth/hci_uart/prj.conf b/samples/bluetooth/hci_uart/prj.conf index 0bdcc2cf8850..bdc73dd68e2e 100644 --- a/samples/bluetooth/hci_uart/prj.conf +++ b/samples/bluetooth/hci_uart/prj.conf @@ -17,3 +17,7 @@ CONFIG_BT_TINYCRYPT_ECC=n CONFIG_BT_CTLR_DTM_HCI=y CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 + +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 diff --git a/samples/bluetooth/hci_usb/prj.conf b/samples/bluetooth/hci_usb/prj.conf index 7f0a2d9fe6aa..0f809e424d6d 100644 --- a/samples/bluetooth/hci_usb/prj.conf +++ b/samples/bluetooth/hci_usb/prj.conf @@ -11,3 +11,7 @@ CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n CONFIG_SERIAL=n CONFIG_CONSOLE=n CONFIG_UART_CONSOLE=n + +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 diff --git a/samples/bluetooth/mesh/boards/bbc_microbit.conf b/samples/bluetooth/mesh/boards/bbc_microbit.conf index d71bc9400ae7..053053e78187 100644 --- a/samples/bluetooth/mesh/boards/bbc_microbit.conf +++ b/samples/bluetooth/mesh/boards/bbc_microbit.conf @@ -13,11 +13,9 @@ CONFIG_BT_PERIPHERAL=n CONFIG_BT_EXT_ADV=n CONFIG_BT_RX_STACK_SIZE=1100 CONFIG_BT_BUF_EVT_RX_COUNT=3 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT=3 -# CONFIG_BT_BUF_ACL_TX_COUNT has to be less than CONFIG_BT_BUF_EVT_RX_COUNT -CONFIG_BT_BUF_ACL_TX_COUNT=1 - CONFIG_BT_CTLR_ADV_EXT=n CONFIG_BT_MESH_ADV_BUF_COUNT=3 diff --git a/samples/bluetooth/peripheral_hr/prj_minimal.conf b/samples/bluetooth/peripheral_hr/prj_minimal.conf index 50e873cd66d4..ee8f43974bfc 100644 --- a/samples/bluetooth/peripheral_hr/prj_minimal.conf +++ b/samples/bluetooth/peripheral_hr/prj_minimal.conf @@ -101,7 +101,7 @@ CONFIG_BT_CTLR_PHY_2M=n # Reduce Bluetooth buffers CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT=1 CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=45 -CONFIG_BT_BUF_EVT_RX_COUNT=4 +CONFIG_BT_BUF_EVT_RX_COUNT=2 CONFIG_BT_CONN_TX_MAX=2 CONFIG_BT_L2CAP_TX_BUF_COUNT=2 diff --git a/subsys/bluetooth/common/Kconfig b/subsys/bluetooth/common/Kconfig index c73229449625..c837fc559cf6 100644 --- a/subsys/bluetooth/common/Kconfig +++ b/subsys/bluetooth/common/Kconfig @@ -93,23 +93,15 @@ config BT_BUF_ACL_RX_SIZE K-frame. config BT_BUF_ACL_RX_COUNT_EXTRA - # As Host implementation unconditionally references this Kconfig, we - # hide it for !BT_CONN and default to 0. - int "Number of extra incoming ACL data buffers" if BT_CONN - range 1 65535 if BT_CONN - default BT_MAX_CONN if BT_CONN - range 0 0 + int "Number of extra incoming ACL data buffers" default 0 + range 0 65535 help Number of incoming extra ACL data buffers sent from the Controller to the Host. - By default, the total number of incoming ACL data buffers is equal to - CONFIG_BT_MAX_CONN + 1, to support L2CAP recombination. - - The L2CAP recombination in the Host keeps the first Rx buffer for each - connection and uses one Rx buffer across all connections to receive a - fragment from the Controller. + By default, the number of incoming ACL data buffers is equal to + CONFIG_BT_MAX_CONN + 1. config BT_BUF_ACL_RX_COUNT int "[DEPRECATED] Number of incoming ACL data buffers" @@ -143,8 +135,7 @@ config BT_BUF_EVT_RX_SIZE config BT_BUF_EVT_RX_COUNT int "Number of HCI Event buffers" - default 8 if BT_HCI_RAW - default 4 if BT_RECV_BLOCKING + default 3 if BT_RECV_BLOCKING default 20 if (BT_MESH && !(BT_BUF_EVT_DISCARDABLE_COUNT > 0)) default 10 range 2 255 @@ -201,48 +192,12 @@ config BT_BUF_CMD_TX_SIZE to the maximum of 255. config BT_BUF_CMD_TX_COUNT - # This option is only visible for a user when Host and Controller are build together, or for - # Host-only builds. - int "Number of HCI command buffers" if !BT_HCI_RAW || !BT_CTLR - # This option is present when Host and Controller are build together, or - # for Host only builds, or when Controller-to-Host ACL data flow control - # is disabled. - depends on !BT_HCI_RAW || !BT_CTLR || !BT_HCI_ACL_FLOW_CONTROL - # The Mesh stack usage in applications and tests can start both advertising and scanning in - # parallel. Also, when BT_MESH_WORKQ_SYS is enabled, the Mesh stack is starting Extended - # Advertising in the receive callback run in the system work queue and as the Host also uses - # the system work queue for HCI command Tx towards the Controller, one additional HCI - # command buffer is needed. - range 2 64 if BT_MESH - range 1 64 - default 2 if BT_MESH - default 1 + int "Number of HCI command buffers" + default 2 + range 2 64 help Number of buffers available for outgoing HCI commands from the Host. - HCI Controllers may not support Num_HCI_Command_Packets > 1, hence they default to 1 when - not enabling Controller to Host data flow control (BT_HCI_ACL_FLOW_CONTROL), Read Remote - Version Information (BT_REMOTE_VERSION), Auto-Initiate PHY update (BT_AUTO_PHY_UPDATE), or - Auto-Initiate Data Length Update (BT_AUTO_DATA_LEN_UPDATE). - - Normal HCI commands follow the HCI command flow control using Num_HCI_Command_Packets - return in HCI command complete and status. - - The Host Number of Completed Packets command does not follow normal flow control of HCI - commands and the Controller side HCI drivers that allocates HCI command buffers with - K_NO_WAIT can end up running out of command buffers. - - When Controller to Host data flow control is enabled in the Host-only or combined - Host plus Controller build, the internal BT_BUF_CMD_TX_COUNT is adjusted accordingly - taking into considerations the enabled auto-initiated procedures, and to follow the normal - HCI command flow control to be able to send Ncmd normal HCI commands and - BT_BUF_ACL_RX_COUNT of Host Number of Completed Packets command down to the Controller. - - When Controller to Host data flow control is supported in the Controller-only build, - the internal BT_BUF_CMD_TX_COUNT is adjusted to be equal to (BT_BUF_RX_COUNT + Ncmd). - - Where Ncmd is supported maximum Num_HCI_Command_Packets in the Controller implementation. - endmenu config BT_HAS_HCI_VS diff --git a/subsys/bluetooth/common/hci_common_internal.h b/subsys/bluetooth/common/hci_common_internal.h deleted file mode 100644 index c8b8b37434ff..000000000000 --- a/subsys/bluetooth/common/hci_common_internal.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2025 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#if !defined(CONFIG_BT_HCI_RAW) || !defined(CONFIG_BT_CTLR) || \ - !defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) -/* Following build configurations use configurable CONFIG_BT_BUF_CMD_TX_COUNT: - * 1. Host + Controller build with and without Controller to Host data flow control, or - * 2. Host-only with and without Controller to Host data flow control, or - * 3. Controller-only without Controller to Host data flow control support - */ -#if !defined(CONFIG_BT_HCI_RAW) -/* Host + Controller build, and Host-only build */ - -/* Auto initiated additional HCI command buffers enqueued in the Host */ -#define BT_BUF_CMD_TX_REMOTE_VERSION COND_CODE_1(CONFIG_BT_REMOTE_VERSION, (1), (0)) -#define BT_BUF_CMD_TX_AUTO_PHY_UPDATE COND_CODE_1(CONFIG_BT_AUTO_PHY_UPDATE, (1), (0)) -#define BT_BUF_CMD_TX_AUTO_DATA_LEN_UPDATE COND_CODE_1(CONFIG_BT_AUTO_DATA_LEN_UPDATE, (1), (0)) - -#else /* CONFIG_BT_HCI_RAW */ -#if defined(CONFIG_BT_CTLR) -/* Controller-only build need no additional HCI command buffers */ -BUILD_ASSERT((CONFIG_BT_BUF_CMD_TX_COUNT == CONFIG_BT_CTLR_HCI_NUM_CMD_PKT_MAX), - "Mismatch in allocated HCI command buffers compared to Controller supported value."); -#endif /* CONFIG_BT_CTLR */ - -/* Controller-only build do not enqueue auto initiated HCI commands */ -#define BT_BUF_CMD_TX_REMOTE_VERSION 0 -#define BT_BUF_CMD_TX_AUTO_PHY_UPDATE 0 -#define BT_BUF_CMD_TX_AUTO_DATA_LEN_UPDATE 0 -#endif /* !CONFIG_BT_HCI_RAW */ - -#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) -/* When Controller to Host data flow control is supported in Host plus Controller build, or - * Host-only build, then we need additional BT_BUF_ACL_RX_COUNT number of HCI command buffers for - * enqueuing Host Number of Completed Packets command. - * - * Host keeps the first, and subsequent, Rx buffers (that comes from the driver) for each connection - * to do re-assembly into, up to the L2CAP SDU length required number of Rx buffers. - * BT_BUF_ACL_RX_COUNT_EXTRA holds the application configured number of buffers across active - * connections for recombination of HCI data packets to L2CAP SDUs. - * - * BT_BUF_HCI_EVT_RX_COUNT defines the number of available buffers reserved for "synchronous" - * processing of HCI events like Number of Completed Packets, disconnection complete etc. - * - * BT_BUF_HCI_ACL_RX_COUNT defines the number of available buffers for Controller to Host data - * flow control; keeping the application configured BT_BUF_ACL_RX_COUNT_EXTRA number of buffers - * available for L2CAP recombination, and a reserved number of buffers for processing HCI events. - */ - -/* FIXME: Calculate the maximum number of HCI events of different types that a connection can - * enqueue while the Host is slow at processing HCI events. - * - * 1. Disconnection Complete event - * 2. LE Connection Update Complete event - * 3. LE Long Term Key Request event - * 4. LE Remote Connection Parameter Request Event - * 5. LE Data Length Change event - * 6. LE PHY Update Complete event - * 7. ... - * - * As there is no HCI event flow control defined, implementations will need a transport level flow - * control to restrict buffers required on resource constraint devices, i.e. if these events are not - * processed "synchronous". - */ -#define BT_BUF_HCI_EVT_RX_COUNT 1 -#define BT_BUF_HCI_ACL_RX_COUNT (BT_BUF_RX_COUNT - BT_BUF_HCI_EVT_RX_COUNT - \ - BT_BUF_ACL_RX_COUNT_EXTRA) -#define BT_BUF_CMD_TX_HOST_NUM_CMPLT_PKT (BT_BUF_HCI_ACL_RX_COUNT) - -#else /* !CONFIG_BT_HCI_ACL_FLOW_CONTROL */ -#define BT_BUF_CMD_TX_HOST_NUM_CMPLT_PKT 0 -#endif /* !CONFIG_BT_HCI_ACL_FLOW_CONTROL */ - -/* Based on Host + Controller, Host-only or Controller-only; Calculate the HCI Command Tx count. */ -#define BT_BUF_CMD_TX_COUNT (CONFIG_BT_BUF_CMD_TX_COUNT + \ - BT_BUF_CMD_TX_HOST_NUM_CMPLT_PKT + \ - BT_BUF_CMD_TX_REMOTE_VERSION + \ - BT_BUF_CMD_TX_AUTO_PHY_UPDATE + \ - BT_BUF_CMD_TX_AUTO_DATA_LEN_UPDATE) - -#elif defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) -/* When Controller to Host data flow control is supported in the Controller-only build, ensure - * that BT_BUF_CMD_TX_COUNT is greater than or equal to (BT_BUF_RX_COUNT + Ncmd), - * where Ncmd is supported maximum Num_HCI_Command_Packets in the Controller implementation. - */ -BUILD_ASSERT(!IS_ENABLED(CONFIG_BT_BUF_CMD_TX_COUNT), - "Configurable HCI command buffer count disallowed."); -BUILD_ASSERT(IS_ENABLED(CONFIG_BT_CTLR_HCI_NUM_CMD_PKT_MAX), - "Undefined Controller implementation supported Num_HCI_Command_Packets value."); - -/** Can use all of buffer count needed for HCI ACL, HCI ISO or Event RX buffers for ACL RX */ -#define BT_BUF_HCI_ACL_RX_COUNT (BT_BUF_RX_COUNT) - -/* Controller-only with Controller to Host data flow control */ -#define BT_BUF_CMD_TX_COUNT (BT_BUF_RX_COUNT + CONFIG_BT_CTLR_HCI_NUM_CMD_PKT_MAX) - -#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig index e0914cc2c298..a7b2c1a74f10 100644 --- a/subsys/bluetooth/controller/Kconfig +++ b/subsys/bluetooth/controller/Kconfig @@ -127,15 +127,6 @@ endchoice comment "BLE Controller configuration" -config BT_CTLR_HCI_NUM_CMD_PKT_MAX - # Hidden Controller implementation supported Num_HCI_Command_Packets value. - # This value will be used to calculate the total number of HCI command buffers to be - # allocated, BT_BUF_CMD_TX_COUNT, dependent on HCI Controller to Host data flow control - # being enabled. - int - default 1 if BT_LL_SW_SPLIT - default 1 - config BT_CTLR_CRYPTO bool "Crypto functions in Controller" default y diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 2b6ff78d8ab0..2fd7dc41a9eb 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -21,8 +21,6 @@ #include #include -#include "common/hci_common_internal.h" - #include "../host/hci_ecc.h" #include "util/util.h" @@ -185,13 +183,13 @@ static uint8_t sf_curr; #endif #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) -int32_t hci_hbuf_total; -uint32_t hci_hbuf_sent; -uint32_t hci_hbuf_acked; -uint16_t hci_hbuf_pend[CONFIG_BT_MAX_CONN]; +int32_t hci_hbuf_total; +uint32_t hci_hbuf_sent; +uint32_t hci_hbuf_acked; +uint16_t hci_hbuf_pend[CONFIG_BT_MAX_CONN]; atomic_t hci_state_mask; static struct k_poll_signal *hbuf_signal; -#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ +#endif #if defined(CONFIG_BT_CONN) static uint32_t conn_count; @@ -476,7 +474,7 @@ static void reset(struct net_buf *buf, struct net_buf **evt) atomic_set_bit(&hci_state_mask, HCI_STATE_BIT_RESET); k_poll_signal_raise(hbuf_signal, 0x0); } -#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ +#endif hci_recv_fifo_reset(); } @@ -524,22 +522,6 @@ static void set_ctl_to_host_flow(struct net_buf *buf, struct net_buf **evt) hci_hbuf_total = -hci_hbuf_total; } -/* Host Number of Completed Packets command does not follow normal flow - * control of HCI commands and the Controller side HCI drivers that - * allocates HCI command buffers with K_NO_WAIT can end up running out - * of command buffers. - * - * Host will generate up to acl_pkts number of Host Number of Completed - * Packets command plus a number of normal HCI commands. - * - * Normal HCI commands follow the HCI command flow control using - * Num_HCI_Command_Packets return in HCI command complete and status. - * - * Note: Zephyr Controller does not support Num_HCI_Command_Packets > 1. - */ -BUILD_ASSERT(BT_BUF_HCI_ACL_RX_COUNT < BT_BUF_CMD_TX_COUNT, - "Too low HCI command buffers compare to ACL Rx buffers."); - static void host_buffer_size(struct net_buf *buf, struct net_buf **evt) { struct bt_hci_cp_host_buffer_size *cmd = (void *)buf->data; @@ -553,38 +535,15 @@ static void host_buffer_size(struct net_buf *buf, struct net_buf **evt) ccst->status = BT_HCI_ERR_CMD_DISALLOWED; return; } - - /* Fragmentation from Controller to Host not supported, require + /* fragmentation from controller to host not supported, require * ACL MTU to be at least the LL MTU */ if (acl_mtu < LL_LENGTH_OCTETS_RX_MAX) { - LOG_ERR("FC: Require Host ACL MTU (%u) >= LL Max Data Length (%u)", acl_mtu, - LL_LENGTH_OCTETS_RX_MAX); ccst->status = BT_HCI_ERR_INVALID_PARAM; return; } - /* Host Number of Completed Packets command does not follow normal flow - * control of HCI commands and the Controller side HCI drivers that - * allocates HCI command buffers with K_NO_WAIT can end up running out - * of command buffers. - * - * Host will generate up to acl_pkts number of Host Number of Completed - * Packets command plus a number of normal HCI commands. - * - * Normal HCI commands follow the HCI command flow control using - * Num_HCI_Command_Packets return in HCI command complete and status. - * - * Note: Zephyr Controller does not support Num_HCI_Command_Packets > 1. - */ - if (acl_pkts >= BT_BUF_CMD_TX_COUNT) { - LOG_WRN("FC: Host ACL packets (%u), BT_BUF_CMD_TX_COUNT (%u)", acl_pkts, - BT_BUF_CMD_TX_COUNT); - acl_pkts = BT_BUF_CMD_TX_COUNT - CONFIG_BT_CTLR_HCI_NUM_CMD_PKT_MAX; - } - - LOG_DBG("FC: host buf size %u count %u", acl_mtu, acl_pkts); - + LOG_DBG("FC: host buf size: %d", acl_pkts); hci_hbuf_total = -acl_pkts; } @@ -626,7 +585,7 @@ static void host_num_completed_packets(struct net_buf *buf, hci_hbuf_acked += count; k_poll_signal_raise(hbuf_signal, 0x0); } -#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ +#endif #if defined(CONFIG_BT_CTLR_LE_PING) static void read_auth_payload_timeout(struct net_buf *buf, struct net_buf **evt) @@ -787,7 +746,7 @@ static int ctrl_bb_cmd_handle(uint16_t ocf, struct net_buf *cmd, case BT_OCF(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS): host_num_completed_packets(cmd, evt); break; -#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ +#endif #if defined(CONFIG_BT_CTLR_LE_PING) case BT_OCF(BT_HCI_OP_READ_AUTH_PAYLOAD_TIMEOUT): @@ -8810,7 +8769,7 @@ void hci_acl_encode(struct node_rx_pdu *node_rx, struct net_buf *buf) LL_ASSERT(handle < ARRAY_SIZE(hci_hbuf_pend)); hci_hbuf_pend[handle]++; } -#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ +#endif break; default: @@ -9012,7 +8971,6 @@ void hci_init(struct k_poll_signal *signal_host_buf) { #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) hbuf_signal = signal_host_buf; -#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */ - +#endif reset(NULL, NULL); } diff --git a/subsys/bluetooth/host/buf.c b/subsys/bluetooth/host/buf.c index 713db81d929f..112b9af59921 100644 --- a/subsys/bluetooth/host/buf.c +++ b/subsys/bluetooth/host/buf.c @@ -5,16 +5,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include #include #include -#include "common/hci_common_internal.h" - #include "hci_core.h" #include "conn_internal.h" #include "iso_internal.h" +#include + /* Events have a length field of 1 byte. This size fits all events. * * It's true that we don't put all kinds of events there (yet). However, the diff --git a/subsys/bluetooth/host/hci_common.c b/subsys/bluetooth/host/hci_common.c index 26bb1913d837..272d472896b5 100644 --- a/subsys/bluetooth/host/hci_common.c +++ b/subsys/bluetooth/host/hci_common.c @@ -30,17 +30,7 @@ struct net_buf *bt_hci_cmd_complete_create(uint16_t op, uint8_t plen) buf = bt_hci_evt_create(BT_HCI_EVT_CMD_COMPLETE, sizeof(*cc) + plen); cc = net_buf_add(buf, sizeof(*cc)); - - /* The Num_HCI_Command_Packets parameter allows the Controller to - * indicate the number of HCI command packets the Host can send to the - * Controller. If the Controller requires the Host to stop sending - * commands, Num_HCI_Command_Packets will be set to zero. - * - * NOTE: Zephyr Controller (and may be other Controllers) do not support - * higher Number of HCI Command packets than 1. - */ cc->ncmd = 1U; - cc->opcode = sys_cpu_to_le16(op); return buf; @@ -55,17 +45,7 @@ struct net_buf *bt_hci_cmd_status_create(uint16_t op, uint8_t status) cs = net_buf_add(buf, sizeof(*cs)); cs->status = status; - - /* The Num_HCI_Command_Packets parameter allows the Controller to - * indicate the number of HCI command packets the Host can send to the - * Controller. If the Controller requires the Host to stop sending - * commands, Num_HCI_Command_Packets will be set to zero. - * - * NOTE: Zephyr Controller (and may be other Controllers) do not support - * higher Number of HCI Command packets than 1. - */ cs->ncmd = 1U; - cs->opcode = sys_cpu_to_le16(op); return buf; diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 0e406091a059..92b6d1433ba3 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -29,11 +29,10 @@ #include #include -#include "common/hci_common_internal.h" #include "common/bt_str.h" -#include "common/rpa.h" #include "common/assert.h" +#include "common/rpa.h" #include "keys.h" #include "monitor.h" #include "hci_core.h" @@ -110,7 +109,7 @@ struct cmd_data { struct k_sem *sync; }; -static struct cmd_data cmd_data[BT_BUF_CMD_TX_COUNT]; +static struct cmd_data cmd_data[CONFIG_BT_BUF_CMD_TX_COUNT]; #define cmd(buf) (&cmd_data[net_buf_id(buf)]) #define acl(buf) ((struct acl_data *)net_buf_user_data(buf)) @@ -130,7 +129,7 @@ void bt_hci_cmd_state_set_init(struct net_buf *buf, * command complete or command status. */ #define CMD_BUF_SIZE MAX(BT_BUF_EVT_RX_SIZE, BT_BUF_CMD_TX_SIZE) -NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, BT_BUF_CMD_TX_COUNT, +NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT, CMD_BUF_SIZE, sizeof(struct bt_buf_data), NULL); struct event_handler { @@ -1904,7 +1903,7 @@ static int set_flow_control(void) hbs = net_buf_add(buf, sizeof(*hbs)); (void)memset(hbs, 0, sizeof(*hbs)); hbs->acl_mtu = sys_cpu_to_le16(CONFIG_BT_BUF_ACL_RX_SIZE); - hbs->acl_pkts = sys_cpu_to_le16(BT_BUF_HCI_ACL_RX_COUNT); + hbs->acl_pkts = sys_cpu_to_le16(BT_BUF_ACL_RX_COUNT); err = bt_hci_cmd_send_sync(BT_HCI_OP_HOST_BUFFER_SIZE, buf, NULL); if (err) { diff --git a/subsys/bluetooth/host/hci_raw.c b/subsys/bluetooth/host/hci_raw.c index 82209f68e8d0..3366b7b3935c 100644 --- a/subsys/bluetooth/host/hci_raw.c +++ b/subsys/bluetooth/host/hci_raw.c @@ -18,10 +18,7 @@ #include -#include "common/hci_common_internal.h" - #include "hci_ecc.h" - #include "monitor.h" #include "hci_raw_internal.h" @@ -57,7 +54,7 @@ static void hci_rx_buf_destroy(struct net_buf *buf) NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, BT_BUF_RX_SIZE, sizeof(struct bt_buf_data), hci_rx_buf_destroy); -NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, BT_BUF_CMD_TX_COUNT, +NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT, BT_BUF_CMD_SIZE(CONFIG_BT_BUF_CMD_TX_SIZE), sizeof(struct bt_buf_data), NULL); NET_BUF_POOL_FIXED_DEFINE(hci_acl_pool, CONFIG_BT_BUF_ACL_TX_COUNT, diff --git a/tests/bluetooth/hci_codecs_info/src/main.c b/tests/bluetooth/hci_codecs_info/src/main.c index a4eabc9b7a9f..de9537ebabcc 100644 --- a/tests/bluetooth/hci_codecs_info/src/main.c +++ b/tests/bluetooth/hci_codecs_info/src/main.c @@ -209,8 +209,6 @@ ZTEST(test_hci_codecs_info, test_read_codec_capabilities) ptr = &rp->capabilities[0]; zassert_mem_equal(ptr, codec_capabilities, sizeof(codec_capabilities), 0, "Reading codec capabilities content failed"); - - net_buf_unref(rsp); } #define READ_DELAY_CODING_FMT 0xff @@ -293,6 +291,4 @@ ZTEST(test_hci_codecs_info, test_read_ctlr_delay) "Reading controller min delay failed"); zassert_equal(sys_get_le24(rp->max_ctlr_delay), MAX_CTLR_DELAY, "Reading controller max delay failed"); - - net_buf_unref(rsp); } diff --git a/tests/bsim/babblekit/CMakeLists.txt b/tests/bsim/babblekit/CMakeLists.txt new file mode 100644 index 000000000000..67fdbc8bd31f --- /dev/null +++ b/tests/bsim/babblekit/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Helpers that can be used on bsim targets but don't have other +# dependencies (e.g. on Bluetooth, etc). +add_library(babblekit) + +target_link_libraries(babblekit PUBLIC + kernel + zephyr_interface +) + +target_include_directories(babblekit PUBLIC + include +) + +target_sources(babblekit PRIVATE + src/sync.c +) diff --git a/tests/bsim/babblekit/include/babblekit/flags.h b/tests/bsim/babblekit/include/babblekit/flags.h new file mode 100644 index 000000000000..a614e811309d --- /dev/null +++ b/tests/bsim/babblekit/include/babblekit/flags.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * Provides a way to set/clear and block on binary flags. + * + * These flags are often used to wait until the test has gotten in a particular + * state, e.g. a connection is established or a message has been successfully + * sent. + * + * These macros can only be called from Zephyr threads. They can't be called + * from e.g. a bs_tests callback. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* Declare a flag that has been defined in another file */ +#define DECLARE_FLAG(flag) extern atomic_t flag + +/* Define a new binary flag. + * Use @ref DEFINE_FLAG_STATIC if defining flags with the same name in multiple files. + * + * @param flag Name of the flag + */ +#define DEFINE_FLAG(flag) atomic_t flag = (atomic_t) false + +/* Define a new, static binary flag. + * + * @param flag Name of the flag + */ +#define DEFINE_FLAG_STATIC(flag) static atomic_t flag = (atomic_t) false + +#define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true) +#define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false) + +#define IS_FLAG_SET(flag) (atomic_get(&flag) != false) + +/* Block until `flag` is equal to `val` */ +#define WAIT_FOR_VAL(var, val) \ + while (atomic_get(&var) != val) { \ + (void)k_sleep(K_MSEC(1)); \ + } + +/* Block until `flag` is true */ +#define WAIT_FOR_FLAG(flag) \ + while (!(bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } + +/* Block until `flag` is false */ +#define WAIT_FOR_FLAG_UNSET(flag) \ + while ((bool)atomic_get(&flag)) { \ + (void)k_sleep(K_MSEC(1)); \ + } + +/* Block until `flag` is true and set it to false */ +#define TAKE_FLAG(flag) \ + while (!(bool)atomic_cas(&flag, true, false)) { \ + (void)k_sleep(K_MSEC(1)); \ + } diff --git a/tests/bsim/babblekit/include/babblekit/sync.h b/tests/bsim/babblekit/include/babblekit/sync.h new file mode 100644 index 000000000000..d57538ac4d91 --- /dev/null +++ b/tests/bsim/babblekit/include/babblekit/sync.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + * + * This file provides a synchronization mechanism between devices, for the + * simple use-case when there are only two devices in the simulation. + */ + + +/* + * @brief Initialize the sync library + * + * This initializes a simple synchronization library based on bsim backchannels. + * + * Calling `bk_sync_wait()` on device A will make it block until + * `bk_sync_send()` is called on device B. + * + * @note Only works between two devices in a simulation, with IDs 0 and 1. + * + * @retval 0 Sync channel operational + * @retval -1 Failed to open sync channel + * + */ +int bk_sync_init(void); + +/* + * @brief Send a synchronization packet + * + * @note Only works between two devices in a simulation, with IDs 0 and 1. + * + */ +void bk_sync_send(void); + +/* + * @brief Wait for a synchronization packet + * + * This blocks until the other device has called `bk_sync_send()`. + * + * @note Only works between two devices in a simulation, with IDs 0 and 1. + * + */ +void bk_sync_wait(void); diff --git a/tests/bsim/babblekit/include/babblekit/testcase.h b/tests/bsim/babblekit/include/babblekit/testcase.h new file mode 100644 index 000000000000..0cbbb7562fff --- /dev/null +++ b/tests/bsim/babblekit/include/babblekit/testcase.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bs_tracing.h" +#include "bs_types.h" +#include "bstests.h" + +extern enum bst_result_t bst_result; + +/* + * @brief Mark the test as in progress + * + * Call this at the start of the test entry point. + * + * @param ... format-string and arguments to print to console + * + */ +#define TEST_START(msg, ...) \ + do { \ + bst_result = In_progress; \ + bs_trace_info_time(2, "Test start: " msg "\n", ##__VA_ARGS__); \ + } while (0) + +/* + * @brief Fail the test and exit + * + * Printf-like function that also terminates the device with an error code. + * + * @param ... format-string and arguments to print to console + * + */ +#define TEST_FAIL(msg, ...) \ + do { \ + bst_result = Failed; \ + bs_trace_error_time_line(msg "\n", ##__VA_ARGS__); \ + } while (0) + +/* + * @brief Mark the currently-running test as "Passed" + * + * Mark the test as "passed". The execution continues after that point. + * + * @note Use this if you use backchannels (testlib/bsim/sync.h). + * + * After calling this, the executable will eventually return 0 when it exits. + * Unless `TEST_FAIL` is called (e.g. in a callback). + * + * @param ... format-string and arguments to print to console + * + */ +#define TEST_PASS(msg, ...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(2, "Test end: " msg "\n", ##__VA_ARGS__); \ + } while (0) + +/* + * @brief Mark test case as passed and end execution + * + * Mark the role / test-case as "Passed" and return 0. + * + * @note DO NOT use this if you use backchannels (testlib/bsim/sync.h). + * + * @note This macro only ends execution for the current executable, not all + * executables in a simulation. + * + * @param ... format-string and arguments to print to console + * + */ +#define TEST_PASS_AND_EXIT(msg, ...) \ + do { \ + bst_result = Passed; \ + bs_trace_info_time(2, "Test end: " msg "\n", ##__VA_ARGS__); \ + bs_trace_silent_exit(0); \ + } while (0) + +/* + * @brief Assert `expr` is true + * + * Assert that `expr` is true. If assertion is false, print a printf-like + * message to the console and fail the test. I.e. return non-zero. + * + * @note This is different than `sys/__assert.h`. + * + * @param message String to print to console + * + */ +#define TEST_ASSERT(expr, ...) \ + do { \ + if (!(expr)) { \ + TEST_FAIL(__VA_ARGS__); \ + } \ + } while (0) + +/* + * @brief Assert `expr` is true + * + * Assert that `expr` is true. If assertion is false, fail the test. I.e. return non-zero. + * + * @note This is different than `sys/__assert.h`. + * + */ +#define TEST_ASSERT_NO_MSG(expr) \ + TEST_ASSERT(expr, "") + +/* + * @brief Print a value. Lower-level than `printk` or `LOG_xx`. + * + * Print a message to console. + * + * This can be safely called at any time in the execution of the device. + * Use it to print when the logging subsystem is not available, e.g. early + * startup or shutdown. + * + * @param ... format-string and arguments to print to console + * + */ +#define TEST_PRINT(msg, ...) \ + bs_trace_print(BS_TRACE_INFO, __FILE__, __LINE__, 0, BS_TRACE_AUTOTIME, 0, \ + msg "\n", ##__VA_ARGS__) diff --git a/tests/bsim/babblekit/src/sync.c b/tests/bsim/babblekit/src/sync.c new file mode 100644 index 000000000000..6a2124200772 --- /dev/null +++ b/tests/bsim/babblekit/src/sync.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "argparse.h" +#include "bs_types.h" +#include "bs_tracing.h" +#include "time_machine.h" +#include "bs_pc_backchannel.h" + +#include +LOG_MODULE_REGISTER(sync, CONFIG_LOG_DEFAULT_LEVEL); + +#define CHANNEL_ID 0 +#define MSG_SIZE 1 + +int bk_sync_init(void) +{ + uint device_number = get_device_nbr(); + uint peer_number = device_number ^ 1; + uint device_numbers[] = { peer_number }; + uint channel_numbers[] = { CHANNEL_ID }; + uint *ch; + + ch = bs_open_back_channel(device_number, device_numbers, channel_numbers, + ARRAY_SIZE(channel_numbers)); + if (!ch) { + return -1; + } + + LOG_DBG("Sync initialized"); + + return 0; +} + +void bk_sync_send(void) +{ + uint8_t sync_msg[MSG_SIZE] = { get_device_nbr() }; + + LOG_DBG("Sending sync"); + bs_bc_send_msg(CHANNEL_ID, sync_msg, ARRAY_SIZE(sync_msg)); +} + +void bk_sync_wait(void) +{ + uint8_t sync_msg[MSG_SIZE]; + + LOG_DBG("Waiting for sync"); + + while (true) { + if (bs_bc_is_msg_received(CHANNEL_ID) > 0) { + bs_bc_receive_msg(CHANNEL_ID, sync_msg, ARRAY_SIZE(sync_msg)); + if (sync_msg[0] != get_device_nbr()) { + /* Received a message from another device, exit */ + break; + } + } + + k_sleep(K_MSEC(1)); + } + + LOG_DBG("Sync received"); +} diff --git a/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh b/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh index 65769185867f..e7b14cbba416 100755 --- a/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh +++ b/tests/bsim/bluetooth/compile.nrf5340bsim_nrf5340_cpuapp.sh @@ -19,6 +19,8 @@ mkdir -p ${WORK_DIR} source ${ZEPHYR_BASE}/tests/bsim/compile.source +app=tests/bsim/bluetooth/host/gatt/notify_stress sysbuild=1 compile + app=tests/bsim/bluetooth/ll/conn conf_file=prj_split_privacy.conf sysbuild=1 compile app=tests/bsim/bluetooth/ll/bis sysbuild=1 compile app=tests/bsim/bluetooth/ll/cis conf_overlay=overlay-acl_group.conf sysbuild=1 compile diff --git a/tests/bsim/bluetooth/host/att/sequential/tester/prj.conf b/tests/bsim/bluetooth/host/att/sequential/tester/prj.conf index fc5c80fa13d8..461c7dd50295 100644 --- a/tests/bsim/bluetooth/host/att/sequential/tester/prj.conf +++ b/tests/bsim/bluetooth/host/att/sequential/tester/prj.conf @@ -6,6 +6,8 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=1 +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_CMD_TX_SIZE=255 CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255 diff --git a/tests/bsim/bluetooth/host/att/sequential/tester/src/main.c b/tests/bsim/bluetooth/host/att/sequential/tester/src/main.c index 13148bb70c05..cecbd8cab137 100644 --- a/tests/bsim/bluetooth/host/att/sequential/tester/src/main.c +++ b/tests/bsim/bluetooth/host/att/sequential/tester/src/main.c @@ -15,7 +15,6 @@ #include #include -#include "common/hci_common_internal.h" #include "common/bt_str.h" #include "host/conn_internal.h" @@ -49,7 +48,7 @@ static uint16_t server_write_handle; static K_FIFO_DEFINE(rx_queue); #define CMD_BUF_SIZE MAX(BT_BUF_EVT_RX_SIZE, BT_BUF_CMD_TX_SIZE) -NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, BT_BUF_CMD_TX_COUNT, +NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT, CMD_BUF_SIZE, 8, NULL); static K_SEM_DEFINE(cmd_sem, 1, 1); diff --git a/tests/bsim/bluetooth/host/compile.sh b/tests/bsim/bluetooth/host/compile.sh index 098c983d75f6..2f2c32749973 100755 --- a/tests/bsim/bluetooth/host/compile.sh +++ b/tests/bsim/bluetooth/host/compile.sh @@ -45,6 +45,7 @@ app=tests/bsim/bluetooth/host/gatt/authorization compile app=tests/bsim/bluetooth/host/gatt/caching compile app=tests/bsim/bluetooth/host/gatt/general compile app=tests/bsim/bluetooth/host/gatt/notify compile +app=tests/bsim/bluetooth/host/gatt/notify_stress compile app=tests/bsim/bluetooth/host/gatt/notify_multiple compile app=tests/bsim/bluetooth/host/gatt/settings compile app=tests/bsim/bluetooth/host/gatt/settings conf_file=prj_2.conf compile diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/CMakeLists.txt b/tests/bsim/bluetooth/host/gatt/notify_stress/CMakeLists.txt new file mode 100644 index 000000000000..b279e8c14396 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/CMakeLists.txt @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(bsim_test_gatt) + +add_subdirectory(${ZEPHYR_BASE}/tests/bsim/babblekit babblekit) +target_link_libraries(app PRIVATE babblekit) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources} ) + +zephyr_include_directories( + ${BSIM_COMPONENTS_PATH}/libUtilv1/src/ + ${BSIM_COMPONENTS_PATH}/libPhyComv1/src/ + ) diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/Kconfig.sysbuild b/tests/bsim/bluetooth/host/gatt/notify_stress/Kconfig.sysbuild new file mode 100644 index 000000000000..7b30da2f0a2e --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/Kconfig.sysbuild @@ -0,0 +1,14 @@ +# Copyright 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config NET_CORE_BOARD + string + default "nrf5340bsim_nrf5340_cpunet" if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" + +config NATIVE_SIMULATOR_PRIMARY_MCU_INDEX + int + # Let's pass the test arguments to the application MCU test + # otherwise by default they would have gone to the net core. + default 0 if $(BOARD) = "nrf5340bsim_nrf5340_cpuapp" diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/nrf5340_cpunet-bt_ll_sw_split.conf b/tests/bsim/bluetooth/host/gatt/notify_stress/nrf5340_cpunet-bt_ll_sw_split.conf new file mode 100644 index 000000000000..69b946201e96 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/nrf5340_cpunet-bt_ll_sw_split.conf @@ -0,0 +1,30 @@ +CONFIG_IPC_SERVICE=y +CONFIG_MBOX=y +CONFIG_ISR_STACK_SIZE=1024 +CONFIG_IDLE_STACK_SIZE=256 +CONFIG_MAIN_STACK_SIZE=512 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512 +CONFIG_IPC_SERVICE_BACKEND_RPMSG_WQ_STACK_SIZE=512 +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_CBPRINTF_REDUCED_INTEGRAL=y +CONFIG_ISR_TABLES_LOCAL_DECLARATION=y + +CONFIG_BT=y +CONFIG_BT_HCI_RAW=y +CONFIG_BT_MAX_CONN=1 + +# Controller +# CONFIG_BT_LL_SW_SPLIT=y +CONFIG_BT_CTLR_ASSERT_HANDLER=y + +CONFIG_BT_CTLR_DATA_LENGTH_MAX=70 +CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=191 +CONFIG_BT_CTLR_RX_BUFFERS=10 + +CONFIG_BT_BUF_CMD_TX_SIZE=65 +CONFIG_BT_BUF_EVT_RX_SIZE=68 +CONFIG_BT_BUF_EVT_RX_COUNT=17 +CONFIG_BT_BUF_ACL_TX_COUNT=16 +CONFIG_BT_BUF_ACL_TX_SIZE=70 +CONFIG_BT_BUF_ACL_RX_SIZE=70 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/prj.conf b/tests/bsim/bluetooth/host/gatt/notify_stress/prj.conf new file mode 100644 index 000000000000..8b5ca4899aa9 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/prj.conf @@ -0,0 +1,41 @@ +CONFIG_BT=y +CONFIG_BT_DEVICE_NAME="GATT tester" +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_GATT_CLIENT=y + +CONFIG_BT_GATT_AUTO_DISCOVER_CCC=y + +CONFIG_BT_SMP=y +CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y +CONFIG_BT_L2CAP_ECRED=y +CONFIG_BT_EATT=y + +CONFIG_BT_AUTO_PHY_UPDATE=n +CONFIG_BT_AUTO_DATA_LEN_UPDATE=n + +# Zephyr Controller has bug, connection update fails with instant passed under high throughput +CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=n + +CONFIG_ASSERT=y +CONFIG_BT_TESTING=y +CONFIG_LOG=y + +# Maximum possible EATT channels are used to parallelize notifications as much as possible, +# increasing traffic towards Central. +CONFIG_BT_EATT_MAX=16 + +# This is aligned with CONFIG_BT_EATT_MAX to utilize all EATT channels +CONFIG_BT_BUF_ACL_TX_COUNT=16 + +# Aligned with characteristic size +CONFIG_BT_BUF_ACL_RX_SIZE=70 +CONFIG_BT_BUF_ACL_TX_SIZE=70 + +CONFIG_BT_BUF_EVT_RX_COUNT=17 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 + +CONFIG_BT_BUF_CMD_TX_COUNT=2 + +# Explicitly use Zephyr Controller, defaults to SDC in nRFConnect SDK +# CONFIG_BT_LL_SW_SPLIT=y diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/src/common.h b/tests/bsim/bluetooth/host/gatt/notify_stress/src/common.h new file mode 100644 index 000000000000..4258969f4dae --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/src/common.h @@ -0,0 +1,21 @@ +/** + * Common macros used by both sides of the test + * + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#define CHRC_SIZE 60 + +#define TEST_SERVICE_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, \ + 0x07, 0x08, 0x09, 0x00, 0x00) + +#define TEST_CHRC_UUID \ + BT_UUID_DECLARE_128(0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, \ + 0x07, 0x08, 0x09, 0xFF, 0x11) + +#define NOTIFICATION_COUNT 30 diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/src/gatt_client_test.c b/tests/bsim/bluetooth/host/gatt/notify_stress/src/gatt_client_test.c new file mode 100644 index 000000000000..d298e0940d8e --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/src/gatt_client_test.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "babblekit/testcase.h" +#include "babblekit/flags.h" +#include "common.h" + +DEFINE_FLAG_STATIC(flag_is_connected); +DEFINE_FLAG_STATIC(flag_is_encrypted); +DEFINE_FLAG_STATIC(flag_discover_complete); +DEFINE_FLAG_STATIC(flag_long_subscribed); + +static struct bt_conn *g_conn; +static uint16_t long_chrc_handle; +static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID; + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != 0) { + TEST_FAIL("Failed to connect to %s (%u)", addr, err); + return; + } + + printk("Connected to %s\n", addr); + + SET_FLAG(flag_is_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != g_conn) { + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(g_conn); + + g_conn = NULL; + UNSET_FLAG(flag_is_connected); +} + +void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) +{ + if (err) { + TEST_FAIL("Encryption failure (%d)", err); + } else if (level < BT_SECURITY_L2) { + TEST_FAIL("Insufficient sec level (%d)", level); + } else { + SET_FLAG(flag_is_encrypted); + } +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, + .security_changed = security_changed, +}; + +void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) +{ + char addr_str[BT_ADDR_LE_STR_LEN]; + int err; + + if (g_conn != NULL) { + return; + } + + /* We're only interested in connectable events */ + if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) { + return; + } + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Device found: %s (RSSI %d)\n", addr_str, rssi); + + printk("Stopping scan\n"); + err = bt_le_scan_stop(); + if (err != 0) { + TEST_FAIL("Could not stop scan: %d"); + return; + } + + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &g_conn); + if (err != 0) { + TEST_FAIL("Could not connect to peer: %d", err); + } +} + +static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) +{ + int err; + + if (attr == NULL) { + if (long_chrc_handle == 0) { + TEST_FAIL("Did not discover long_chrc (%x)", long_chrc_handle); + } + + (void)memset(params, 0, sizeof(*params)); + + SET_FLAG(flag_discover_complete); + + return BT_GATT_ITER_STOP; + } + + printk("[ATTRIBUTE] handle %u\n", attr->handle); + + if (params->type == BT_GATT_DISCOVER_PRIMARY && + bt_uuid_cmp(params->uuid, TEST_SERVICE_UUID) == 0) { + printk("Found test service\n"); + params->uuid = NULL; + params->start_handle = attr->handle + 1; + params->type = BT_GATT_DISCOVER_CHARACTERISTIC; + + err = bt_gatt_discover(conn, params); + if (err != 0) { + TEST_FAIL("Discover failed (err %d)", err); + } + + return BT_GATT_ITER_STOP; + } else if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) { + const struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; + + if (bt_uuid_cmp(chrc->uuid, TEST_CHRC_UUID) == 0) { + printk("Found long_chrc\n"); + long_chrc_handle = chrc->value_handle; + } + } + + return BT_GATT_ITER_CONTINUE; +} + +static void gatt_discover(enum bt_att_chan_opt opt) +{ + static struct bt_gatt_discover_params discover_params; + int err; + + printk("Discovering services and characteristics\n"); + + discover_params.uuid = test_svc_uuid; + discover_params.func = discover_func; + discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; + discover_params.chan_opt = opt; + + err = bt_gatt_discover(g_conn, &discover_params); + if (err != 0) { + TEST_FAIL("Discover failed(err %d)", err); + } + + WAIT_FOR_FLAG(flag_discover_complete); + printk("Discover complete\n"); +} + +static void test_long_subscribed(struct bt_conn *conn, uint8_t err, + struct bt_gatt_subscribe_params *params) +{ + if (err) { + TEST_FAIL("Subscribe failed (err %d)", err); + } + + SET_FLAG(flag_long_subscribed); + + if (!params) { + printk("params NULL\n"); + return; + } + + if (params->value_handle == long_chrc_handle) { + printk("Subscribed to long characteristic\n"); + } else { + TEST_FAIL("Unknown handle %d", params->value_handle); + } +} + +static volatile size_t num_notifications; +uint8_t test_notify(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, + uint16_t length) +{ + printk("Received notification #%u with length %d\n", num_notifications++, length); + + /* This causes ACL data drop in HCI IPC driver. */ + k_sleep(K_MSEC(1000)); + + return BT_GATT_ITER_CONTINUE; +} + +static struct bt_gatt_discover_params disc_params_long; +static struct bt_gatt_subscribe_params sub_params_long = { + .notify = test_notify, + .subscribe = test_long_subscribed, + .ccc_handle = 0x0000, + .disc_params = &disc_params_long, + .end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE, + .value = BT_GATT_CCC_NOTIFY, +}; + +static void gatt_subscribe_long(enum bt_att_chan_opt opt) +{ + int err; + + UNSET_FLAG(flag_long_subscribed); + sub_params_long.value_handle = long_chrc_handle; + sub_params_long.chan_opt = opt; + err = bt_gatt_subscribe(g_conn, &sub_params_long); + if (err < 0) { + TEST_FAIL("Failed to subscribe"); + } else { + printk("Subscribe request sent\n"); + } +} + +static void gatt_unsubscribe_long(enum bt_att_chan_opt opt) +{ + int err; + + UNSET_FLAG(flag_long_subscribed); + sub_params_long.value_handle = long_chrc_handle; + sub_params_long.chan_opt = opt; + err = bt_gatt_unsubscribe(g_conn, &sub_params_long); + if (err < 0) { + TEST_FAIL("Failed to unsubscribe"); + } else { + printk("Unsubscribe request sent\n"); + } +} + +static void setup(void) +{ + int err; + + err = bt_enable(NULL); + if (err != 0) { + TEST_FAIL("Bluetooth discover failed (err %d)", err); + } + + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err != 0) { + TEST_FAIL("Scanning failed to start (err %d)", err); + } + + printk("Scanning successfully started\n"); + + WAIT_FOR_FLAG(flag_is_connected); + + err = bt_conn_set_security(g_conn, BT_SECURITY_L2); + if (err) { + TEST_FAIL("Starting encryption procedure failed (%d)", err); + } + + WAIT_FOR_FLAG(flag_is_encrypted); + + while (bt_eatt_count(g_conn) < CONFIG_BT_EATT_MAX) { + k_sleep(K_MSEC(10)); + } + + printk("EATT connected\n"); +} + +static void test_main_client(void) +{ + setup(); + + gatt_discover(BT_ATT_CHAN_OPT_ENHANCED_ONLY); + gatt_subscribe_long(BT_ATT_CHAN_OPT_ENHANCED_ONLY); + WAIT_FOR_FLAG(flag_long_subscribed); + + printk("Subscribed\n"); + + while (num_notifications < NOTIFICATION_COUNT) { + k_sleep(K_MSEC(100)); + } + + gatt_unsubscribe_long(BT_ATT_CHAN_OPT_ENHANCED_ONLY); + WAIT_FOR_FLAG(flag_long_subscribed); + + printk("Unsubscribed\n"); + + TEST_PASS("GATT client Passed"); +} + +static const struct bst_test_instance test_vcs[] = { + { + .test_id = "gatt_client_enhanced_notif_stress", + .test_main_f = test_main_client, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_gatt_client_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_vcs); +} diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/src/gatt_server_test.c b/tests/bsim/bluetooth/host/gatt/notify_stress/src/gatt_server_test.c new file mode 100644 index 000000000000..4046deb60011 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/src/gatt_server_test.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "babblekit/testcase.h" +#include "babblekit/flags.h" +#include "common.h" + +extern enum bst_result_t bst_result; + +DEFINE_FLAG_STATIC(flag_is_connected); +DEFINE_FLAG_STATIC(flag_subscribe); + +static struct bt_conn *g_conn; + +#define ARRAY_ITEM(i, _) i +const uint8_t chrc_data[] = { LISTIFY(CHRC_SIZE, ARRAY_ITEM, (,)) }; /* 1, 2, 3 ... */ + +static void connected(struct bt_conn *conn, uint8_t err) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err != 0) { + TEST_FAIL("Failed to connect to %s (%u)", addr, err); + return; + } + + printk("Connected to %s\n", addr); + + g_conn = bt_conn_ref(conn); + SET_FLAG(flag_is_connected); +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) +{ + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != g_conn) { + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(g_conn); + + g_conn = NULL; + UNSET_FLAG(flag_is_connected); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +static ssize_t read_test_chrc(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + printk("Read char\n"); + return bt_gatt_attr_read(conn, attr, buf, len, offset, (void *)chrc_data, + sizeof(chrc_data)); +} + +static void subscribe(const struct bt_gatt_attr *attr, uint16_t value) +{ + const bool notif_enabled = (value == BT_GATT_CCC_NOTIFY); + + if (notif_enabled) { + SET_FLAG(flag_subscribe); + } + + printk("Notifications %s\n", notif_enabled ? "enabled" : "disabled"); +} + +BT_GATT_SERVICE_DEFINE(test_svc, BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID), + BT_GATT_CHARACTERISTIC(TEST_CHRC_UUID, + BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_READ, + BT_GATT_PERM_READ, read_test_chrc, NULL, NULL), + BT_GATT_CCC(subscribe, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE)); + +static volatile size_t num_notifications_sent; + +static void notification_sent(struct bt_conn *conn, void *user_data) +{ + size_t *length = user_data; + + printk("Sent notification #%u with length %d\n", num_notifications_sent++, *length); +} + +static void notify(void) +{ + static size_t length = CHRC_SIZE; + static struct bt_gatt_notify_params params = { + .attr = &attr_test_svc[1], + .data = chrc_data, + .len = CHRC_SIZE, + .func = notification_sent, + .user_data = &length, + .uuid = NULL, + .chan_opt = BT_ATT_CHAN_OPT_ENHANCED_ONLY, + }; + int err; + + do { + err = bt_gatt_notify_cb(g_conn, ¶ms); + + if (err == -ENOMEM) { + /* The delay is needed to schedule other threads, but keep it as short as + * possible. + */ + k_sleep(K_MSEC(1)); + } else if (err) { + TEST_FAIL("Notify failed (err %d)", err); + } + } while (err); +} + +static void setup(void) +{ + int err; + const struct bt_data ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + }; + + err = bt_enable(NULL); + if (err != 0) { + TEST_FAIL("Bluetooth init failed (err %d)", err); + return; + } + + printk("Bluetooth initialized\n"); + + err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0); + if (err != 0) { + TEST_FAIL("Advertising failed to start (err %d)", err); + return; + } + + printk("Advertising successfully started\n"); + + WAIT_FOR_FLAG(flag_is_connected); + + while (bt_eatt_count(g_conn) < CONFIG_BT_EATT_MAX) { + k_sleep(K_MSEC(100)); + } + printk("EATT connected\n"); + + WAIT_FOR_FLAG(flag_subscribe); +} + +static void test_main_server(void) +{ + setup(); + + for (int i = 0; i < NOTIFICATION_COUNT; i++) { + notify(); + } + + while (num_notifications_sent < NOTIFICATION_COUNT) { + k_sleep(K_MSEC(100)); + } + + TEST_PASS("GATT server passed"); +} + +static const struct bst_test_instance test_gatt_server[] = { + { + .test_id = "gatt_server_enhanced_notif_stress", + .test_main_f = test_main_server, + }, + BSTEST_END_MARKER, +}; + +struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests) +{ + return bst_add_tests(tests, test_gatt_server); +} diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/src/main.c b/tests/bsim/bluetooth/host/gatt/notify_stress/src/main.c new file mode 100644 index 000000000000..14ee71fd4d24 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/src/main.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bstests.h" + +extern struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests); +extern struct bst_test_list *test_gatt_client_install(struct bst_test_list *tests); + +bst_test_install_t test_installers[] = { + test_gatt_server_install, + test_gatt_client_install, + NULL +}; + +int main(void) +{ + bst_main(); + return 0; +} diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/sysbuild.cmake b/tests/bsim/bluetooth/host/gatt/notify_stress/sysbuild.cmake new file mode 100644 index 000000000000..2ef52ac6f612 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/sysbuild.cmake @@ -0,0 +1,19 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +if(NOT("${SB_CONFIG_NET_CORE_BOARD}" STREQUAL "")) + set(NET_APP hci_ipc) + set(NET_APP_SRC_DIR ${ZEPHYR_BASE}/samples/bluetooth/${NET_APP}) + + ExternalZephyrProject_Add( + APPLICATION ${NET_APP} + SOURCE_DIR ${NET_APP_SRC_DIR} + BOARD ${SB_CONFIG_NET_CORE_BOARD} + ) + + set(${NET_APP}_CONF_FILE ${APP_DIR}/nrf5340_cpunet-bt_ll_sw_split.conf CACHE INTERNAL "") + + native_simulator_set_primary_mcu_index(${DEFAULT_IMAGE} ${NET_APP}) + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) +endif() +native_simulator_set_final_executable(${DEFAULT_IMAGE}) diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/test_scripts/run_test.sh b/tests/bsim/bluetooth/host/gatt/notify_stress/test_scripts/run_test.sh new file mode 100755 index 000000000000..61096ae50e7a --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/test_scripts/run_test.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# Copyright 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# Test purpose: +# +# Verify that the Central can receive 30 notifications from the Peripheral over all available EATT +# channels. +# +# Note: The number of notifications and the size of the characteristic are chosen empirically. +# +# This test is designed to stress HCI driver to guarantee that no data is dropped between Host and +# Controller. Specifically, the HCI IPC driver that tends to drop data when the Host is not able to +# process it fast enough. The test is guaranteed to fail with Controller to Host HCI data flow +# control being disabled. +# +# Test Setup: +# +# - Devices: Central and Peripheral +# - Characteristic Length: Peripheral exposes a long characteristic (greater than 23 bytes). +# - Connection: Central connects to Peripheral. +# - Notification subscription: Central subscribes to notificaitons from the Peripheral. +# - EATT Usage: EATT is enabled, and the maximum possible EATT channels are established to +# parallelize notifications as much as possible, increasing traffic towards Central. +# +# Test Steps: +# +# 1. The Peripheral sends 30 notifications to the Central over all available EATT channels. +# 2. Upon receiving a notification, the Central holds the received notification callback for 1 +# second before releasing it. +# 3. The test passes if all 30 notifications are successfully sent by the Peripheral and received +# by the Central. + +set -eu + +source ${ZEPHYR_BASE}/tests/bsim/sh_common.source + +EXECUTE_TIMEOUT=150 + +verbosity_level=2 +simulation_id="gatt_notify_enhanced_stress" +server_id="gatt_server_enhanced_notif_stress" +client_id="gatt_client_enhanced_notif_stress" + +cd ${BSIM_OUT_PATH}/bin + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_gatt_notify_stress_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=0 -testid=${client_id} -RealEncryption=1 + +Execute ./bs_${BOARD}_tests_bsim_bluetooth_host_gatt_notify_stress_prj_conf \ + -v=${verbosity_level} -s=${simulation_id} -d=1 -testid=${server_id} -RealEncryption=1 + +Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=2 -sim_length=70e6 $@ + +wait_for_background_jobs diff --git a/tests/bsim/bluetooth/host/gatt/notify_stress/testcase.yaml b/tests/bsim/bluetooth/host/gatt/notify_stress/testcase.yaml new file mode 100644 index 000000000000..ead6f5effdd8 --- /dev/null +++ b/tests/bsim/bluetooth/host/gatt/notify_stress/testcase.yaml @@ -0,0 +1,12 @@ +tests: + bluetooth.host.gatt.notify_stress: + build_only: true + sysbuild: true + tags: + - bluetooth + platform_allow: + - nrf52_bsim/native + - nrf5340bsim/nrf5340/cpuapp + harness: bsim + harness_config: + bsim_exe_name: tests_bsim_bluetooth_host_gatt_notify_stress_prj_conf diff --git a/tests/bsim/bluetooth/host/l2cap/split/tester/prj.conf b/tests/bsim/bluetooth/host/l2cap/split/tester/prj.conf index 905ae4bbdca1..82dfa9686ee0 100644 --- a/tests/bsim/bluetooth/host/l2cap/split/tester/prj.conf +++ b/tests/bsim/bluetooth/host/l2cap/split/tester/prj.conf @@ -6,6 +6,8 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=16 +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_CMD_TX_SIZE=255 CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255 diff --git a/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c b/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c index 7b6fece797a1..f762ee824737 100644 --- a/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c +++ b/tests/bsim/bluetooth/host/l2cap/split/tester/src/main.c @@ -15,7 +15,6 @@ #include #include -#include "common/hci_common_internal.h" #include "common/bt_str.h" #include "host/conn_internal.h" @@ -35,7 +34,7 @@ DEFINE_FLAG(flag_data_length_updated); static K_FIFO_DEFINE(rx_queue); #define CMD_BUF_SIZE MAX(BT_BUF_EVT_RX_SIZE, BT_BUF_CMD_TX_SIZE) -NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, BT_BUF_CMD_TX_COUNT, +NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT, CMD_BUF_SIZE, 8, NULL); static K_SEM_DEFINE(cmd_sem, 1, 1); diff --git a/tests/bsim/bluetooth/host/misc/disconnect/tester/prj.conf b/tests/bsim/bluetooth/host/misc/disconnect/tester/prj.conf index fc5c80fa13d8..461c7dd50295 100644 --- a/tests/bsim/bluetooth/host/misc/disconnect/tester/prj.conf +++ b/tests/bsim/bluetooth/host/misc/disconnect/tester/prj.conf @@ -6,6 +6,8 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=1 +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_CMD_TX_SIZE=255 CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255 diff --git a/tests/bsim/bluetooth/host/misc/disconnect/tester/src/main.c b/tests/bsim/bluetooth/host/misc/disconnect/tester/src/main.c index 47a3e785455e..4755a55d4d38 100644 --- a/tests/bsim/bluetooth/host/misc/disconnect/tester/src/main.c +++ b/tests/bsim/bluetooth/host/misc/disconnect/tester/src/main.c @@ -15,7 +15,6 @@ #include #include -#include "common/hci_common_internal.h" #include "common/bt_str.h" #include "host/conn_internal.h" @@ -45,7 +44,7 @@ DEFINE_FLAG(flag_data_length_updated); static K_FIFO_DEFINE(rx_queue); #define CMD_BUF_SIZE MAX(BT_BUF_EVT_RX_SIZE, BT_BUF_CMD_TX_SIZE) -NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, BT_BUF_CMD_TX_COUNT, +NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT, CMD_BUF_SIZE, 8, NULL); static K_SEM_DEFINE(cmd_sem, 1, 1); diff --git a/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf b/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf index 9f7868e815ab..a3c8f43c71f7 100644 --- a/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf +++ b/tests/bsim/bluetooth/ll/cis/sysbuild/hci_ipc/nrf5340_cpunet_iso_acl_group-bt_ll_sw_split.conf @@ -14,7 +14,12 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_HCI_RAW_RESERVE=1 CONFIG_BT_MAX_CONN=4 +# Workaround: Unable to allocate command buffer when using K_NO_WAIT since +# Host number of completed commands does not follow normal flow control. +CONFIG_BT_BUF_CMD_TX_COUNT=10 + CONFIG_BT_BUF_EVT_RX_COUNT=16 + CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_BT_BUF_ACL_TX_SIZE=251 diff --git a/tests/bsim/bluetooth/ll/throughput/prj.conf b/tests/bsim/bluetooth/ll/throughput/prj.conf index f4805907f607..6f52a3d5091c 100644 --- a/tests/bsim/bluetooth/ll/throughput/prj.conf +++ b/tests/bsim/bluetooth/ll/throughput/prj.conf @@ -11,9 +11,4 @@ CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255 CONFIG_BT_L2CAP_TX_MTU=247 -# BT HCI ACL RX Data Buffers -CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 -CONFIG_BT_BUF_ACL_RX_SIZE=255 - -# Maximum LL ACL PDU length CONFIG_BT_CTLR_DATA_LENGTH_MAX=251