Bluetooth: Userchan: Add support for TCP Connection
Added support to connect to an HCI TCP Server. This allows to do integration tests with other frameworks that support a virtual hci interface. Signed-off-by: Victor Chavez <chavez-bermudez@fh-aachen.de>
This commit is contained in:
parent
392769e425
commit
33c922a771
4 changed files with 173 additions and 38 deletions
|
@ -345,6 +345,15 @@ The following peripherals are currently provided with this board:
|
|||
must be powered down and support Bluetooth Low Energy (i.e. support the
|
||||
Bluetooth specification version 4.0 or greater).
|
||||
|
||||
Another possibility is to use a HCI TCP server which acts as a
|
||||
:ref:`virtual Bluetooth controller<bluetooth_virtual_posix>` over TCP.
|
||||
To connect to a HCI TCP server its IP address and port number must
|
||||
be specified. For example, to connect to a HCI TCP server with IP
|
||||
address 127.0.0.0 and port number 1020 use ``zephyr.exe --bt-dev=127.0.0.1:1020``.
|
||||
This alternative option is mainly aimed for testing Bluetooth connectivity over
|
||||
a virtual Bluetooth controller that does not depend on the Linux Bluetooth
|
||||
stack and its HCI interface.
|
||||
|
||||
**USB controller**:
|
||||
It's possible to use the Virtual USB controller working over USB/IP
|
||||
protocol. More information can be found in
|
||||
|
|
|
@ -92,10 +92,11 @@ which is comprised of the following devices:
|
|||
#. A :ref:`Host-only <bluetooth-build-types>` application running in the
|
||||
:ref:`QEMU <application_run_qemu>` emulator or the ``native_posix`` native
|
||||
port of Zephyr
|
||||
#. A Controller, which can be one of two types:
|
||||
#. A Controller, which can be one of the following types:
|
||||
|
||||
* A commercially available Controller
|
||||
* A :ref:`Controller-only <bluetooth-build-types>` build of Zephyr
|
||||
* A Virtual controller
|
||||
|
||||
.. warning::
|
||||
Certain external Controllers are either unable to accept the Host to
|
||||
|
@ -129,11 +130,12 @@ The :ref:`Native POSIX <native_posix>` target builds your Zephyr application
|
|||
with the Zephyr kernel, and some minimal HW emulation as a native Linux
|
||||
executable.
|
||||
This executable is a normal Linux program, which can be debugged and
|
||||
instrumented like any other, and it communicates with a physical external
|
||||
Controller.
|
||||
instrumented like any other, and it communicates with a physical or virtual
|
||||
external Controller.
|
||||
|
||||
Refer to :ref:`bluetooth_qemu_posix` for full instructions on how to build and
|
||||
run an application in this setup.
|
||||
run an application with a physical controller. For the virtual controller refer
|
||||
to :ref:`bluetooth_virtual_posix`.
|
||||
|
||||
Simulated nRF52 with BabbleSim
|
||||
==============================
|
||||
|
|
|
@ -178,6 +178,69 @@ In order to see those logs, you can use the built-in ``btmon`` tool from BlueZ:
|
|||
|
||||
$ btmon
|
||||
|
||||
.. _bluetooth_virtual_posix:
|
||||
|
||||
Running on a Virtual Controller and Native POSIX
|
||||
*************************************************
|
||||
|
||||
An alternative to a Bluetooth physical controller is the use of a virtual
|
||||
controller. This controller can be connected over an HCI TCP server.
|
||||
This TCP server must support the HCI H4 protocol. In comparison to the physical controller
|
||||
variant, the virtual controller allows to test a Zephyr application running on the native
|
||||
boards without a physical Bluetooth controller.
|
||||
|
||||
The main use case for a virtual controller is to do Bluetooth connectivity tests without
|
||||
the need of Bluetooth hardware. This allows to automate Bluetooth integration tests with
|
||||
external applications such as a Bluetooth gateway or a mobile application.
|
||||
|
||||
To demonstrate this functionality an example is given to interact with a virtual controller.
|
||||
For this purpose, the experimental python module `Bumble`_ from Google is used as it allows to create
|
||||
a TCP Bluetooth virtual controller and connect with the Zephyr Bluetooth host. To install
|
||||
bumble follow the `Bumble Getting Started Guide`_.
|
||||
|
||||
.. note::
|
||||
If your Zephyr application requires the use of the HCI LE Set extended commands, install
|
||||
the branch ``controller-extended-advertising`` from Bumble.
|
||||
|
||||
Android Emulator
|
||||
=================
|
||||
|
||||
You can test the virtual controller by connecting a Bluetooth Zephyr application
|
||||
to the `Android Emulator`_.
|
||||
|
||||
To connect your application to the Android Emulator follow the next steps:
|
||||
|
||||
#. Build your Zephyr application and disable the HCI ACL flow
|
||||
control (i.e. ``CONFIG_BT_HCI_ACL_FLOW_CONTROL=n``) as the
|
||||
the virtual controller from android does not support it at the moment.
|
||||
|
||||
#. Install Android Emulator version >= 33.1.4.0. The easiest way to do this is by installing
|
||||
the latest `Android Studio Preview`_ version.
|
||||
|
||||
#. Create a new Android Virtual Device (AVD) with the `Android Device Manager`_. The AVD should use at least SDK API 34.
|
||||
|
||||
#. Run the Android Emulator via terminal as follows:
|
||||
|
||||
``emulator avd YOUR_AVD -packet-streamer-endpoint default``
|
||||
|
||||
#. Create a Bluetooth bridge between the Zephyr application and
|
||||
the virtual controller from Android Emulator with the `Bumble`_ utility ``hci-bridge``.
|
||||
|
||||
``bumble-hci-bridge tcp-server:_:1234 android-netsim``
|
||||
|
||||
This command will create a TCP server bridge on the local host IP address ``127.0.0.1``
|
||||
and port number ``1234``.
|
||||
|
||||
#. Run the Zephyr application and connect to the TCP server created in the last step.
|
||||
|
||||
``./zephyr.exe --bt-dev=127.0.0.1:1234``
|
||||
|
||||
After following these steps the Zephyr application will be available to the Android Emulator
|
||||
over the virtual Bluetooth controller that was bridged with Bumble. You can verify that the
|
||||
Zephyr application can communicate over Bluetooth by opening the Bluetooth settings in your
|
||||
AVD and scanning for your Zephyr application device. To test this you can build the Bluetooth
|
||||
peripheral samples such as :ref:`Peripheral HR <peripheral_hr>` or :ref:`Peripheral DIS <peripheral_dis>`
|
||||
|
||||
.. _bluetooth_ctlr_bluez:
|
||||
|
||||
Using Zephyr-based Controllers with BlueZ
|
||||
|
@ -205,3 +268,8 @@ Additional information about :file:`btmgmt` can be found in its manual pages.
|
|||
.. _LightBlue for iOS: https://itunes.apple.com/us/app/lightblue-explorer/id557428110
|
||||
.. _nRF Mesh for Android: https://play.google.com/store/apps/details?id=no.nordicsemi.android.nrfmeshprovisioner&hl=en
|
||||
.. _nRF Mesh for iOS: https://itunes.apple.com/us/app/nrf-mesh/id1380726771
|
||||
.. _Bumble: https://github.com/google/bumble
|
||||
.. _Bumble Getting Started Guide: https://google.github.io/bumble/getting_started.html
|
||||
.. _Android Emulator: https://developer.android.com/studio/run/emulator
|
||||
.. _Android Device Manager: https://developer.android.com/studio/run/managing-avds
|
||||
.. _Android Studio Preview: https://developer.android.com/studio/preview
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2018 Intel Corporation
|
||||
*
|
||||
* Copyright (c) 2023 Victor Chavez
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
|||
#include <zephyr/device.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
@ -20,6 +19,10 @@
|
|||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "soc.h"
|
||||
#include "cmdline.h" /* native_posix command line options header */
|
||||
|
@ -54,7 +57,13 @@ static struct k_thread rx_thread_data;
|
|||
|
||||
static int uc_fd = -1;
|
||||
|
||||
static int bt_dev_index = -1;
|
||||
static unsigned short bt_dev_index;
|
||||
|
||||
#define TCP_ADDR_BUFF_SIZE 16
|
||||
static bool hci_socket;
|
||||
static char ip_addr[TCP_ADDR_BUFF_SIZE];
|
||||
static unsigned int port;
|
||||
static bool arg_found;
|
||||
|
||||
static struct net_buf *get_rx(const uint8_t *buf)
|
||||
{
|
||||
|
@ -185,27 +194,53 @@ static int uc_send(struct net_buf *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int user_chan_open(uint16_t index)
|
||||
static int user_chan_open(void)
|
||||
{
|
||||
struct sockaddr_hci addr;
|
||||
int fd;
|
||||
|
||||
fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
BTPROTO_HCI);
|
||||
if (fd < 0) {
|
||||
return -errno;
|
||||
}
|
||||
if (hci_socket) {
|
||||
struct sockaddr_hci addr;
|
||||
|
||||
(void)memset(&addr, 0, sizeof(addr));
|
||||
addr.hci_family = AF_BLUETOOTH;
|
||||
addr.hci_dev = index;
|
||||
addr.hci_channel = HCI_CHANNEL_USER;
|
||||
fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
BTPROTO_HCI);
|
||||
if (fd < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
int err = -errno;
|
||||
(void)memset(&addr, 0, sizeof(addr));
|
||||
addr.hci_family = AF_BLUETOOTH;
|
||||
addr.hci_dev = bt_dev_index;
|
||||
addr.hci_channel = HCI_CHANNEL_USER;
|
||||
|
||||
close(fd);
|
||||
return err;
|
||||
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
int err = -errno;
|
||||
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
struct sockaddr_in addr;
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (inet_pton(AF_INET, ip_addr, &(addr.sin_addr)) <= 0) {
|
||||
int err = -errno;
|
||||
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
int err = -errno;
|
||||
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
|
@ -213,14 +248,14 @@ static int user_chan_open(uint16_t index)
|
|||
|
||||
static int uc_open(void)
|
||||
{
|
||||
if (bt_dev_index < 0) {
|
||||
LOG_ERR("No Bluetooth device specified");
|
||||
return -ENODEV;
|
||||
if (hci_socket) {
|
||||
LOG_DBG("hci%d", bt_dev_index);
|
||||
} else {
|
||||
LOG_DBG("hci %s:%d", ip_addr, port);
|
||||
}
|
||||
|
||||
LOG_DBG("hci%d", bt_dev_index);
|
||||
|
||||
uc_fd = user_chan_open(bt_dev_index);
|
||||
uc_fd = user_chan_open();
|
||||
if (uc_fd < 0) {
|
||||
return uc_fd;
|
||||
}
|
||||
|
@ -257,14 +292,33 @@ SYS_INIT(bt_uc_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|
|||
|
||||
static void cmd_bt_dev_found(char *argv, int offset)
|
||||
{
|
||||
if (strncmp(&argv[offset], "hci", 3) || strlen(&argv[offset]) < 4) {
|
||||
posix_print_error_and_exit("Error: Invalid Bluetooth device "
|
||||
"name '%s' (should be e.g. hci0)\n",
|
||||
&argv[offset]);
|
||||
return;
|
||||
}
|
||||
arg_found = true;
|
||||
if (strncmp(&argv[offset], "hci", 3) == 0 && strlen(&argv[offset]) >= 4) {
|
||||
long arg_hci_idx = strtol(&argv[offset + 3], NULL, 10);
|
||||
|
||||
bt_dev_index = strtol(&argv[offset + 3], NULL, 10);
|
||||
if (arg_hci_idx >= 0 && arg_hci_idx <= USHRT_MAX) {
|
||||
bt_dev_index = arg_hci_idx;
|
||||
hci_socket = true;
|
||||
} else {
|
||||
posix_print_error_and_exit("Invalid argument value for --bt-dev. "
|
||||
"hci idx must be within range 0 to 65536.\n");
|
||||
}
|
||||
} else if (sscanf(&argv[offset], "%15[^:]:%d", ip_addr, &port) == 2) {
|
||||
if (port > USHRT_MAX) {
|
||||
posix_print_error_and_exit("Error: IP port for bluetooth "
|
||||
"hci tcp server is out of range.\n");
|
||||
}
|
||||
struct in_addr addr;
|
||||
|
||||
if (inet_pton(AF_INET, ip_addr, &addr) != 1) {
|
||||
posix_print_error_and_exit("Error: IP address for bluetooth "
|
||||
"hci tcp server is incorrect.\n");
|
||||
}
|
||||
} else {
|
||||
posix_print_error_and_exit("Invalid option %s for --bt-dev. "
|
||||
"An hci interface or hci tcp server is expected.\n",
|
||||
&argv[offset]);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_btuserchan_arg(void)
|
||||
|
@ -280,7 +334,8 @@ static void add_btuserchan_arg(void)
|
|||
{ false, true, false,
|
||||
"bt-dev", "hciX", 's',
|
||||
NULL, cmd_bt_dev_found,
|
||||
"A local HCI device to be used for Bluetooth (e.g. hci0)" },
|
||||
"A local HCI device to be used for Bluetooth (e.g. hci0) "
|
||||
"or an HCI TCP Server (e.g. 127.0.0.1:9000)"},
|
||||
ARG_TABLE_ENDMARKER
|
||||
};
|
||||
|
||||
|
@ -289,9 +344,10 @@ static void add_btuserchan_arg(void)
|
|||
|
||||
static void btuserchan_check_arg(void)
|
||||
{
|
||||
if (bt_dev_index < 0) {
|
||||
posix_print_error_and_exit("Error: Bluetooth device missing. "
|
||||
"Specify one using --bt-dev=hciN\n");
|
||||
if (!arg_found) {
|
||||
posix_print_error_and_exit("Error: Bluetooth device missing.\n"
|
||||
"Specify either a local hci interface --bt-dev=hciN\n"
|
||||
"or a valid hci tcp server --bt-dev=ip_address:port\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue