Skip to content

arch: sim: Add BabbleSIM Support - #20108

Merged
acassis merged 3 commits into
apache:masterfrom
LingaoM:bsim_support
Sep 13, 2026
Merged

acassis merged 3 commits into
apache:masterfrom
LingaoM:bsim_support

Conversation

@LingaoM

@LingaoM LingaoM commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR improves the Linux sim target for host-side Bluetooth testing.

It adds optional BabbleSim discrete-time support to arch/sim. When
CONFIG_SIM_BSIM_TIME is enabled, the simulator joins a BabbleSim PHY as a
device and uses the BabbleSim PHY wait protocol as the monotonic time source.
host_sleepuntil() advances through PB_MSG_WAIT requests instead of Linux
wall-time sleeps, so NuttX SIM applications can run in the same discrete-time
domain as other BabbleSim devices.

The PR also fixes the simulated HCI socket watchdog lifetime. The receive
watchdog is now started only after the host HCI socket has been opened
successfully, and is canceled on close/free. This keeps the polling lifetime
tied to the actual host socket lifetime and avoids polling an invalid host fd.

Finally, it adds a runtime HCI socket target option. --bt-dev=hciN overrides
CONFIG_SIM_HCISOCKET_DEVID for the BlueZ HCI user channel, while
--bt-dev=/path/to/socket connects the simulator to an H:4 stream over a Unix
domain socket. Omitting --bt-dev keeps the existing configured default
behavior.

Impact

  • CONFIG_SIM_BSIM_TIME is disabled by default.
  • Existing sim builds keep their current wall-time behavior unless
    CONFIG_SIM_BSIM_TIME is enabled.
  • BabbleSim time support is limited to Linux host SIM, CONFIG_SIM_WALLTIME_SLEEP,
    and non-SMP builds.
  • Building with CONFIG_SIM_BSIM_TIME=y requires:
    • BSIM_COMPONENTS_PATH for BabbleSim headers.
    • BSIM_OUT_PATH or BSIM_LIBS_DIR for BabbleSim libraries.
  • The BabbleSim PHY process must be started externally by the test runner before
    launching the NuttX SIM binary.
  • RTC/realtime reads still use the host realtime clock. BabbleSim is used only
    for monotonic time after the simulator joins the PHY.
  • --bt-dev=hciN keeps the BlueZ user-channel path and still requires the
    normal host permissions/capabilities for BlueZ HCI access.
  • --bt-dev=/path/to/socket allows use of a Unix-socket HCI transport, which can
    connect to another host process or a UART-to-Unix-socket bridge without
    requiring BlueZ raw HCI privileges for the NuttX process.
  • The HCI watchdog change only affects the simulated HCI socket driver lifetime
    handling and does not change the HCI packet format or public Bluetooth APIs.

Testing

Host machine:

  • Ubuntu 22.04 x86_64

Style checks:

$ git diff --check HEAD~2..HEAD
$ PATH=/home/mi/bsim-auto-test/.venv/bin:$PATH \
  ./tools/checkpatch.sh -c -u -m -g HEAD~2..HEAD

Default SIM smoke test:

$ ./tools/configure.sh -l -a ../nuttx-apps sim:nsh
$ make -j16
$ printf 'help\npoweroff\n' | timeout 20s ./nuttx

BabbleSim-enabled build:

$ kconfig-tweak --file .config \
    -e SIM_WALLTIME_SLEEP \
    -d SIM_WALLTIME_SIGNAL \
    -e SIM_BSIM_TIME
$ make olddefconfig
$ BSIM_OUT_PATH=/tmp/bsworld/build/babblesim/bsim \
  BSIM_COMPONENTS_PATH=/tmp/bsworld/build/babblesim/bsim/components \
  make -j16

BabbleSim time smoke test without a controller:

$ bs_2G4_phy_v1 -s=<sid> -D=1 -defmodem=BLE_simple -nodump
$ printf 'usleep 1000000\npoweroff\n' | \
  ./nuttx --sim-bsim-sid=<sid> \
          --sim-bsim-pid=2G4 \
          --sim-bsim-dev=0

Observed result:

The 1 second simulated sleep completed in 19 ms wall time when no handbrake
device was present.

BabbleSim handbrake verification:

$ bs_2G4_phy_v1 -s=<sid> -D=2 -defmodem=BLE_simple -nodump
$ bs_device_handbrake -s=<sid> -p=2G4 -d=1 -pp=50000 -r=1
$ printf 'usleep 1000000\npoweroff\n' | \
  ./nuttx --sim-bsim-sid=<sid> \
          --sim-bsim-pid=2G4 \
          --sim-bsim-dev=0

Observed result:

The same 1 second simulated sleep completed in 985 ms wall time with the
handbrake device registered.
A shorter 200 ms check completed in 27 ms without handbrake and 172 ms with
handbrake.

This verifies that NuttX SIM monotonic time advances through the BabbleSim PHY
and that the BabbleSim handbrake affects the NuttX SIM device.

Verified cleanup still works after enabling CONFIG_SIM_BSIM_TIME and without
exporting BabbleSim environment variables:

$ make distclean

HCI socket watchdog and runtime target tests:

Board/config:

- sim:bthcisock

Clean build:

$ make distclean
$ ./tools/configure.sh -l -a ../../nuttx-apps sim:bthcisock
$ kconfig-tweak --file .config --set-val STACK_USAGE_WARNING 0
$ make olddefconfig
$ make -j16

Default startup smoke test:

$ printf 'poweroff\n' | timeout 10s ./nuttx

Observed result:

The simulator reached NSH and powered off cleanly. When no host HCI controller
was available through the default BlueZ target, the board reported
sim_bthcisock_register() failure and continued booting without an invalid-fd
watchdog crash.

Invalid runtime argument smoke test:

$ ./nuttx --bt-dev=invalid

Observed result:

The command exited with status 1 and reported the invalid target without
crashing before nx_start().

Unix socket HCI smoke test:

$ socat -d -d UNIX-LISTEN:/tmp/hci.sock,fork,reuseaddr \
  /dev/ttyACM2,b1000000,raw,echo=0,crtscts=1

$ printf 'ifconfig\nbt bnep0 info\npoweroff\n' | \
  timeout 20s ./nuttx --bt-dev=/tmp/hci.sock

Observed result:

The simulator registered the Bluetooth network device as bnep0, and
bt bnep0 info read controller state through the Unix-socket HCI path, including
BDAddr aa:bb:cc:dd:ee:ff from the attached controller.

@github-actions github-actions Bot added Area: Documentation Improvements or additions to documentation Arch: simulator Issues related to the SIMulator Size: L The size of the change in this PR is large labels Sep 11, 2026
@LingaoM LingaoM changed the title Bsim support arch: sim: Add BabbleSIM Support Sep 11, 2026
@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

Comment thread arch/sim/src/Makefile Outdated
Comment thread arch/sim/src/sim/posix/sim_bsimtime.c Outdated
Comment thread arch/sim/src/sim/posix/sim_bsimtime.c Outdated
Comment thread arch/sim/src/sim/posix/sim_bsimtime.c Outdated
Comment thread arch/sim/src/sim/posix/sim_bsimtime.c Outdated
Comment thread arch/sim/src/sim/posix/sim_hosthcisocket.c Outdated
Comment thread arch/sim/src/sim/posix/sim_hosthcisocket.c Outdated
Comment thread arch/sim/src/sim/posix/sim_hosthcisocket.c
Comment thread arch/sim/src/sim/posix/sim_hosthcisocket.c
Comment thread arch/sim/src/sim/posix/sim_hosthcisocket.c Outdated
Add support for using a BabbleSim PHY as the monotonic time source for
the Linux sim target.  When CONFIG_SIM_BSIM_TIME is enabled, the sim
host build links a small host-side time helper against the BabbleSim
PhyCom and Util libraries.  The helper joins the BabbleSim PHY wait
protocol and advances NuttX monotonic time through PB_MSG_WAIT requests
instead of Linux wall-time sleeps.

A SIM binary built with CONFIG_SIM_BSIM_TIME enabled joins BabbleSim time
at startup.  Runtime options allow the test runner to select the
BabbleSim simulation id, PHY id, and device number:

  --sim-bsim-sid=<simulation-id>
  --sim-bsim-pid=<phy-id>
  --sim-bsim-dev=<device-number>

Keep the integration inside the sim host time path rather than exposing
a new application API.  RTC/realtime reads still use the host realtime
clock; the BabbleSim source is used only for monotonic time after the sim
has joined the PHY.  The Kconfig option depends on the sleep based
walltime mode and is disabled for SMP and non-Linux hosts.

The build requires BSIM_COMPONENTS_PATH for headers and either
BSIM_OUT_PATH or BSIM_LIBS_DIR for shared libraries.  The path checks are
skipped for clean, distclean, clean_context, and context targets so a
tree with CONFIG_SIM_BSIM_TIME enabled can still be cleaned without
exporting the BabbleSim environment first.

Document the configuration, build environment, runtime options, and the
requirement that the BabbleSim PHY process is started separately by the
test runner.

Testing:

  Host: Ubuntu 22.04 x86_64
  Board/config: sim:nsh

  Style check:

    git diff --check

  Default sim build and smoke test:

    ./tools/configure.sh -l -a ../nuttx-apps sim:nsh
    make -j16
    printf 'help\npoweroff\n' | timeout 20s ./nuttx

  BabbleSim-enabled build:

    kconfig-tweak --file .config \
      -e SIM_WALLTIME_SLEEP \
      -d SIM_WALLTIME_SIGNAL \
      -e SIM_BSIM_TIME
    make olddefconfig
    BSIM_OUT_PATH=/tmp/bsworld/build/babblesim/bsim \
    BSIM_COMPONENTS_PATH=/tmp/bsworld/build/babblesim/bsim/components \
      make -j16

  Verified actual BabbleSim PHY time integration without a controller by
  starting bs_2G4_phy_v1 and running NSH usleep through the PHY wait
  barrier:

    bs_2G4_phy_v1 -s=<sid> -D=1 -defmodem=BLE_simple -nodump
    printf 'usleep 1000000\npoweroff\n' | \
      ./nuttx --sim-bsim-sid=<sid> \
              --sim-bsim-pid=2G4 \
              --sim-bsim-dev=0

  The same 1 second simulated sleep completed in 19 ms wall time when no
  handbrake device was present.  With handbrake registered as device 1:

    bs_2G4_phy_v1 -s=<sid> -D=2 -defmodem=BLE_simple -nodump
    bs_device_handbrake -s=<sid> -p=2G4 -d=1 -pp=50000 -r=1

  the same NuttX usleep test completed in 985 ms wall time.  A shorter
  200 ms check showed the same behavior: 27 ms without handbrake and
  172 ms with handbrake.  This verifies that NuttX sim time advances
  through the BabbleSim PHY and that the handbrake affects the NuttX sim
  device.

  Also verified make distclean succeeds after CONFIG_SIM_BSIM_TIME was
  enabled and without exporting BSIM_COMPONENTS_PATH.

  BSWorld out-of-tree native BLE examples:

    ./tools/configure.sh -l /path/to/bsim-auto-test/tests/nuttx/native_ble/source/advertiser/config
    make -j16
    exodus --tarball -o /path/to/bsim-auto-test/tests/nuttx/native_ble/source/advertiser/prebuilt/nuttx.tgz nuttx
    ./tools/configure.sh -l /path/to/bsim-auto-test/tests/nuttx/native_ble/source/scanner/config
    make -j16
    exodus --tarball -o /path/to/bsim-auto-test/tests/nuttx/native_ble/source/scanner/prebuilt/nuttx.tgz nuttx
    pytest tests/nuttx/native_ble -q --no-ellisys

Assisted-by: OpenAI Codex
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
Start the simulated HCI socket receive watchdog only after the host HCI
socket has been opened successfully.  The previous code armed the watchdog
immediately after driver registration, before the Bluetooth stack opened the
driver and before the device had a valid host fd.

Cancel the watchdog on close/free and close any opened host fd during
allocation-failure cleanup.  This keeps the polling path tied to the actual
socket lifetime and prevents the watchdog from polling an invalid host fd.

Testing:

  Host: Ubuntu 22.04 x86_64
  Board/config: sim:bthcisock

  Style checks:

    git diff --check HEAD~2..HEAD
    PATH=/home/mi/bsim-auto-test/.venv/bin:$PATH \
      ./tools/checkpatch.sh -c -u -m -g HEAD~2..HEAD

  Clean build:

    make distclean
    ./tools/configure.sh -l -a ../../nuttx-apps sim:bthcisock
    kconfig-tweak --file .config --set-val STACK_USAGE_WARNING 0
    make olddefconfig
    make -j16

  Default startup smoke test:

    printf 'poweroff\n' | timeout 10s ./nuttx

  Verified the sim still reaches NSH and powers off cleanly.  When no
  host HCI controller is available through the default BlueZ target, the
  board reports sim_bthcisock_register() failure and continues booting;
  no invalid-fd watchdog crash occurs.

Assisted-by: OpenAI Codex
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
Allow sim HCI socket users to select the host-side HCI target at runtime
with --bt-dev.  Passing --bt-dev=hciN overrides CONFIG_SIM_HCISOCKET_DEVID
for the BlueZ HCI user channel, while omitting the option keeps the existing
configured default behavior.

Also allow --bt-dev=/path/to/socket to connect to an H:4 stream exposed
through a Unix-domain socket.  This lets sim applications use a controller
provided by another host process or by a UART-to-Unix-socket bridge without
requiring BlueZ raw HCI privileges for the NuttX process.

Use host-side output for early --bt-dev parse errors, since NuttX stdio is
not initialized before nx_start().

Document the BlueZ and Unix socket modes, including the capability
requirements for BlueZ and the socat bridge example for Unix socket mode.

Testing:

  Host: Ubuntu 22.04 x86_64
  Board/config: sim:bthcisock

  Style checks:

    git diff --check HEAD~2..HEAD
    PATH=/home/mi/bsim-auto-test/.venv/bin:$PATH \
      ./tools/checkpatch.sh -c -u -m -g HEAD~2..HEAD

  Clean build:

    make distclean
    ./tools/configure.sh -l -a ../../nuttx-apps sim:bthcisock
    kconfig-tweak --file .config --set-val STACK_USAGE_WARNING 0
    make olddefconfig
    make -j16

  Invalid runtime argument smoke test:

    ./nuttx --bt-dev=invalid

  Verified the command exits with status 1 and reports the invalid target
  without crashing before nx_start().

  Unix socket HCI smoke test:

    socat -d -d UNIX-LISTEN:/tmp/hci.sock,fork,reuseaddr \
      /dev/ttyACM2,b1000000,raw,echo=0,crtscts=1
    printf 'ifconfig\nbt bnep0 info\npoweroff\n' | \
      timeout 20s ./nuttx --bt-dev=/tmp/hci.sock

  Verified the sim registers the Bluetooth network device as bnep0 and
  bt bnep0 info reads the controller state through the Unix-socket HCI
  path, including BDAddr aa:bb:cc:dd:ee:ff from the attached controller.

Assisted-by: OpenAI Codex
Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
@acassis
acassis merged commit 89c4b8c into apache:master Sep 13, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: simulator Issues related to the SIMulator Area: Documentation Improvements or additions to documentation Size: L The size of the change in this PR is large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants