1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #12012 from HendrikVE/nimble_shell_module

sys/stdio_nimble: add new stdio module using nimble
This commit is contained in:
Francisco 2022-02-04 11:10:17 +01:00 committed by GitHub
commit 14f22c17aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 680 additions and 2 deletions

View File

@ -39,7 +39,13 @@ TEST_INTERACTIVE_DELAY = int(os.environ.get('TEST_INTERACTIVE_DELAY') or 1)
# By default never reset after the terminal is open unless explicitly requested
# through an environment variable.
TESTRUNNER_RESET_AFTER_TERM = int(os.environ.get('TESTRUNNER_RESET_AFTER_TERM')
or '0')
or 0)
# When running e.g. tests/shell_ble we don't want to reset the board, because
# then ble-serial would terminate and the created virtual serial port would get
# lost. By default the board is reset before the test starts.
TESTRUNNER_RESET_BOARD_ON_STARTUP = \
int(os.environ.get('TESTRUNNER_RESET_BOARD_ON_STARTUP') or 1)
MAKE = os.environ.get('MAKE', 'make')
@ -70,7 +76,8 @@ def find_exc_origin(exc_info):
def setup_child(timeout=10, spawnclass=pexpect.spawnu, env=None, logfile=None):
# Some boards can't be reset after a terminal is open. Therefore reset
# before `cleanterm`.
_reset_board(env)
if TESTRUNNER_RESET_BOARD_ON_STARTUP:
_reset_board(env)
# on platforms exposing UART over USB, wait a little before connecting to
# the serial terminal. This gives time for stdio to be ready.

View File

@ -201,6 +201,7 @@ PSEUDOMODULES += stdin
PSEUDOMODULES += stdio_available
PSEUDOMODULES += stdio_cdc_acm
PSEUDOMODULES += stdio_ethos
PSEUDOMODULES += stdio_nimble_debug
PSEUDOMODULES += stdio_uart_rx
PSEUDOMODULES += stm32_eth
PSEUDOMODULES += stm32_eth_auto

View File

@ -2,6 +2,7 @@ STDIO_MODULES = \
slipdev_stdio \
stdio_cdc_acm \
stdio_ethos \
stdio_nimble \
stdio_null \
stdio_rtt \
stdio_semihosting \
@ -29,6 +30,18 @@ ifneq (,$(filter stdio_ethos,$(USEMODULE)))
USEMODULE += stdin
endif
ifneq (,$(filter stdio_nimble,$(USEMODULE)))
USEMODULE += stdio_available
USEPKG += nimble
USEMODULE += tsrb
USEMODULE += isrpipe
USEMODULE += nimble_svc_gap
USEMODULE += nimble_svc_gatt
ifneq (,$(filter stdio_nimble_debug,$(USEMODULE)))
FEATURES_REQUIRED += periph_uart
endif
endif
ifneq (,$(filter stdin,$(USEMODULE)))
ifneq (,$(filter stdio_uart,$(USEMODULE)))
USEMODULE += stdio_uart_rx

View File

@ -135,6 +135,17 @@ ifneq (,$(filter nimble_netif,$(USEMODULE)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS=1
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT=1
endif
else
ifneq (,$(filter stdio_nimble,$(USEMODULE)))
# the maximum fragment size that we can receive. For maximum efficiency this
# should be equal to the maximum configured link layer packet size.
# WARNING: this value MUST never be larger than MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE
CFLAGS += -DMYNEWT_VAL_BLE_L2CAP_COC_MPS=251
# in order to fit a 251 byte COC data segment into a single mbuf buffer, the
# used block size must be at least 297 byte (251 data + 48 overhead)
CFLAGS += -DMYNEWT_VAL_MSYS_1_BLOCK_SIZE="(MYNEWT_VAL_BLE_L2CAP_COC_MPS + 48)"
endif
endif
ifneq (,$(filter nimble_rpble,$(USEMODULE)))

View File

@ -176,6 +176,13 @@ void nimble_riot_init(void)
nimble_autoconn_enable();
#endif
#ifdef MODULE_STDIO_NIMBLE
extern void stdio_nimble_init(void);
/* stdio_nimble_init() needs to be called after nimble stack initialization
* and before nimble_autoadv_init() */
stdio_nimble_init();
#endif
#ifdef MODULE_NIMBLE_AUTOADV
extern void nimble_autoadv_init(void);
nimble_autoadv_init();

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup sys_stdio_nimble STDIO over NimBLE
* @ingroup sys
*
* @experimental This feature is experimental as some use-cases, such as examples/twr_aloha, show
* unexpected behaviour.
*
* @brief Standard input/output backend using NimBLE.
*
* @note 'stdio_read' blocks until at least one character was read.
*
* @note 'stdio_write' is considered non-blocking even though it uses a mutex to protect the
* write buffer since only 'stdio_write' uses this mutex. Characters will be written
* in FIFO mode. Characters that do not fit in the buffer will be dropped.
*
* @{
* @file
*
* @author Hendrik van Essen <hendrik.ve@fu-berlin.de>
*/
#ifndef STDIO_NIMBLE_H
#define STDIO_NIMBLE_H
#include "stdio_base.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Whether to clear the buffers when establishing a new connection or
* not. Defaults to true.
*/
#ifndef CONFIG_STDIO_NIMBLE_CLEAR_BUFFER_ON_CONNECT
#define CONFIG_STDIO_NIMBLE_CLEAR_BUFFER_ON_CONNECT 1
#endif
/**
* @brief Size of buffer for stdin in bytes
*
* @note Must be a power of two!
*/
#ifndef CONFIG_STDIO_NIMBLE_STDIN_BUFSIZE
#define CONFIG_STDIO_NIMBLE_STDIN_BUFSIZE 1024
#endif
/**
* @brief Size of buffer for stdout in bytes
*
* @note Must be a power of two!
*/
#ifndef CONFIG_STDIO_NIMBLE_STDOUT_BUFSIZE
#define CONFIG_STDIO_NIMBLE_STDOUT_BUFSIZE 2048
#endif
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* STDIO_NIMBLE_H */

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

110
sys/stdio_nimble/README.md Normal file
View File

@ -0,0 +1,110 @@
# STDIO NimBLE
This module uses NimBLE for stdio. The bluetooth characteristic for
stdin is writable and the characteristic for stdout uses the indicate
mechanism to publish the system's output to a connected device. Data will be
sent out asynchronously via callout functions.
To use this module, add
```
USEMODULE += stdio_nimble
```
to your makefile.
You can change the default buffer sizes by adding
```
CFLAGS += -DCONFIG_STDIO_NIMBLE_STDIN_BUFSIZE=1024
CFLAGS += -DCONFIG_STDIO_NIMBLE_STDOUT_BUFSIZE=2048
```
to your makefile. \
**NOTE:** These values must be a power of two!
By default, stdin and stdout buffers are cleared on a connect event. To keep the
content add the following to your makefile:
```
CFLAGS += -DCONFIG_STDIO_NIMBLE_CLEAR_BUFFER_ON_CONNECT=0
```
For automatic bluetooth advertising a module is provided: *nimble_autoadv*.
It will take care of enabling advertising on disconnect events and
disabling advertising on connect events. It can be enabled by adding
```
USEMODULE += nimble_autoadv
```
to your makefile.
The advertised device name can then optionally be configured with
```
CFLAGS += -DNIMBLE_AUTOADV_DEVICE_NAME='"Riot OS device"'
```
Otherwise the device will appear as "*RIOT OS device*".
## Instructions to connect to the bluetooth shell via ble-serial
- Configure and compile shell app for nrf52840dongle target in `tests/shell`.\
Add following to Makefile:
```
BOARD = nrf52840dongle
USEMODULE += nimble_autoadv
USEMODULE += stdio_nimble
```
**NOTE:** You can also have a look at `tests/shell_ble`.
- Flash
`$ make -C tests/shell -j clean all flash`
- Install the ble-serial tool
`$ pip install ble-serial`
- Scan for your device (device name `Riot OS device`) and note its BLE address.\
When you get `ble-scan: command not found` you can also run
`python -m ble_serial.scan` instead.
```
$ ble-scan
Started BLE scan
6BE8174C-A0F8-4479-AFA6-9828372CAFE9 (RSSI=-40): Riot OS device
A2862DCB-D382-4C0B-95BF-FA9A961F8D88 (RSSI=-48): Unknown
F2C75C08-7DD7-4F43-BEF0-151C92068FE5 (RSSI=-66): Unknown
69400683-FBE5-4B45-8CFE-98594076E5F4 (RSSI=-89): Unknown
```
- Discover characteristics (check the one advertised by the gatt server stdin/stdout)
```
$ ble-scan -d 6BE8174C-A0F8-4479-AFA6-9828372CAFE9
Started deep scan of 6BE8174C-A0F8-4479-AFA6-9828372CAFE9
SERVICE e6d54866-0292-4779-b8f8-c52bbec91e71 (Handle: 10): Unknown
CHARACTERISTIC 35f28386-3070-4f3b-ba38-27507e991762 (Handle: 11): Unknown ['indicate']
DESCRIPTOR 00002902-0000-1000-8000-00805f9b34fb (Handle: 13): Client Characteristic Configuration
CHARACTERISTIC ccdd113f-40d5-4d68-86ac-a728dd82f4aa (Handle: 14): Unknown ['write']
Completed deep scan of 6BE8174C-A0F8-4479-AFA6-9828372CAFE9
```
- Create a virtual port and mount it on /tmp/dev_riot_ble
```
$ ble-serial -d 6BE8174C-A0F8-4479-AFA6-9828372CAFE9 -p /tmp/dev_riot_ble --write-uuid ccdd113f-40d5-4d68-86ac-a728dd82f4aa --read-uuid 35f28386-3070-4f3b-ba38-27507e991762
17:44:18.765 | INFO | linux_pty.py: Slave created on /tmp/dev_riot_ble -> /dev/ttys006
17:44:18.766 | INFO | ble_interface.py: Receiver set up
17:44:18.766 | INFO | ble_interface.py: Trying to connect with 6BE8174C-A0F8-4479-AFA6-9828372CAFE9
17:44:19.861 | INFO | ble_interface.py: Device 6BE8174C-A0F8-4479-AFA6-9828372CAFE9 connected
17:44:19.862 | INFO | ble_interface.py: Found write characteristic ccdd113f-40d5-4d68-86ac-a728dd82f4aa (H. 14)
17:44:19.862 | INFO | ble_interface.py: Found notify characteristic 35f28386-3070-4f3b-ba38-27507e991762 (H. 11)
17:44:19.883 | INFO | main.py: Running main loop!
```
- Open the virtual com port (the port name is from the logs in previous steps)
```
$ picocom -q -b 115200 --imap lfcrlf /tmp/dev_riot_ble
ps
pid | state Q | pri
1 | running Q | 7
2 | bl anyfl _ | 5
3 | bl anyfl _ | 0
>
```

View File

@ -0,0 +1,387 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys
* @{
*
* @file
* @brief STDIO over NimBLE implementation
*
*
* @author Hendrik van Essen <hendrik.ve@fu-berlin.de>
* @author Francisco Molina <francois-xavier.molina@inria.fr>
*
* @}
*/
#include <errno.h>
#include <stdlib.h>
#include "nimble_riot.h"
#include "nimble/nimble_port.h"
#include "net/bluetil/ad.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "host/ble_gatt.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
#include <stdarg.h>
#include "stdio_uart.h"
#include "periph/uart.h"
#endif /* IS_USED(MODULE_STDIO_NIMBLE_DEBUG) */
#if IS_USED(MODULE_VFS)
#include "vfs.h"
#endif
#include "tsrb.h"
#include "isrpipe.h"
#include "stdio_nimble.h"
#define NIMBLE_MAX_PAYLOAD MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE)
/* Nimble uses ZTIMER_MSEC => 1 tick equals 1 ms */
#define CALLOUT_TICKS_MS 1
enum {
STDIO_NIMBLE_DISCONNECTED,
STDIO_NIMBLE_CONNECTED,
STDIO_NIMBLE_SUBSCRIBED,
STDIO_NIMBLE_SENDING,
};
/* isrpipe for stdin */
static uint8_t _isrpipe_stdin_mem[CONFIG_STDIO_NIMBLE_STDIN_BUFSIZE];
static isrpipe_t _isrpipe_stdin = ISRPIPE_INIT(_isrpipe_stdin_mem);
/* tsrb for stdout */
static uint8_t _tsrb_stdout_mem[CONFIG_STDIO_NIMBLE_STDOUT_BUFSIZE];
static tsrb_t _tsrb_stdout = TSRB_INIT(_tsrb_stdout_mem);
/* intermediate buffer to transfer data between tsrb and nimble functions,
* which are all based on os_mbuf implementation */
static uint8_t _stdin_read_buf[NIMBLE_MAX_PAYLOAD];
static uint8_t _stdout_write_buf[NIMBLE_MAX_PAYLOAD];
/* information about bluetooth connection */
static uint16_t _conn_handle;
static uint16_t _val_handle_stdout;
static volatile uint8_t _status = STDIO_NIMBLE_DISCONNECTED;
/* nimble related structs */
static struct ble_npl_callout _send_stdout_callout;
static struct ble_gap_event_listener _gap_event_listener;
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
#define DEBUG_PRINTF_BUFSIZE 512
#define PREFIX_STDIN "\nSTDIN: "
#define PREFIX_STDOUT "STDOUT: "
static char _debug_printf_buf[DEBUG_PRINTF_BUFSIZE];
#endif /* IS_USED(MODULE_STDIO_NIMBLE_DEBUG) */
static int _debug_printf(const char *format, ...)
{
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
unsigned state = irq_disable();
va_list va;
va_start(va, format);
int rc = vsnprintf(_debug_printf_buf, DEBUG_PRINTF_BUFSIZE, format, va);
va_end(va);
uart_write(STDIO_UART_DEV, (const uint8_t *)_debug_printf_buf, rc);
irq_restore(state);
return rc;
#else
(void)format;
return 0;
#endif
}
/**
* @brief UUID for stdio service (value: e6d54866-0292-4779-b8f8-c52bbec91e71)
*/
static const ble_uuid128_t gatt_svr_svc_stdio_uuid
= BLE_UUID128_INIT(0x71, 0x1e, 0xc9, 0xbe, 0x2b, 0xc5, 0xf8, 0xb8,
0x79, 0x47, 0x92, 0x02, 0x66, 0x48, 0xd5, 0xe6);
/**
* @brief UUID for stdout characteristic (value: 35f28386-3070-4f3b-ba38-27507e991762)
*/
static const ble_uuid128_t gatt_svr_chr_stdout_uuid
= BLE_UUID128_INIT(0x62, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x35);
/**
* @brief UUID for stdin characteristic (value: ccdd113f-40d5-4d68-86ac-a728dd82f4aa)
*/
static const ble_uuid128_t gatt_svr_chr_stdin_uuid
= BLE_UUID128_INIT(0xaa, 0xf4, 0x82, 0xdd, 0x28, 0xa7, 0xac, 0x86,
0x68, 0x4d, 0xd5, 0x40, 0x3f, 0x11, 0xdd, 0xcc);
/**
* @brief Nimble access callback for stdin characteristic
*/
static int gatt_svr_chr_access_stdin(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
/**
* @brief Dummy access callback, because nimble requires one
*/
static int gatt_svr_chr_access_noop(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
(void)conn_handle;
(void)attr_handle;
(void)ctxt;
(void)arg;
return 0;
}
/**
* @brief Struct to define the stdio bluetooth service with its characteristics
*/
static const struct ble_gatt_svc_def _gatt_svr_svcs[] =
{
/*
* access_cb defines a callback for read and write access events on
* given characteristics
*/
{
/* Service: stdio */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *)&gatt_svr_svc_stdio_uuid.u,
.characteristics = (struct ble_gatt_chr_def[]) { {
/* Characteristic: stdout */
.uuid = (ble_uuid_t *)&gatt_svr_chr_stdout_uuid.u,
.access_cb = gatt_svr_chr_access_noop,
.val_handle = &_val_handle_stdout,
.flags = BLE_GATT_CHR_F_INDICATE,
}, {
/* Characteristic: stdin */
.uuid = (ble_uuid_t *)&gatt_svr_chr_stdin_uuid.u,
.access_cb = gatt_svr_chr_access_stdin,
.flags = BLE_GATT_CHR_F_WRITE,
}, {
0, /* No more characteristics in this service */
}, }
},
{
0, /* No more services */
},
};
static void _purge_buffer(void)
{
tsrb_clear(&_isrpipe_stdin.tsrb);
#if IS_USED(MODULE_SHELL)
/* send Ctrl-C to the shell to reset the input */
isrpipe_write_one(&_isrpipe_stdin, '\x03');
#endif
tsrb_clear(&_tsrb_stdout);
}
static void _send_stdout(struct ble_npl_event *ev)
{
(void)ev;
/* rearm callout */
ble_npl_callout_reset(&_send_stdout_callout, CALLOUT_TICKS_MS);
if (_status == STDIO_NIMBLE_SUBSCRIBED) {
_status = STDIO_NIMBLE_SENDING;
int to_send = tsrb_peek(&_tsrb_stdout, _stdout_write_buf, NIMBLE_MAX_PAYLOAD);
if (to_send > 0) {
struct os_mbuf *om = ble_hs_mbuf_from_flat(_stdout_write_buf, to_send);
if (om != NULL) {
int rc = ble_gattc_indicate_custom(_conn_handle, _val_handle_stdout, om);
if (rc == 0) {
/* bytes were successfully sent, so drop them from the buffer */
tsrb_drop(&_tsrb_stdout, to_send);
_debug_printf("%d bytes sent successfully\n", to_send);
}
else {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
}
else {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
}
else {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
}
}
static int _gap_event_cb(struct ble_gap_event *event, void *arg)
{
(void)arg;
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
_debug_printf("BLE_GAP_EVENT_CONNECT\n");
if (event->connect.status == 0) {
_status = STDIO_NIMBLE_CONNECTED;
if (CONFIG_STDIO_NIMBLE_CLEAR_BUFFER_ON_CONNECT) {
_purge_buffer();
}
_conn_handle = event->connect.conn_handle;
}
else {
_status = STDIO_NIMBLE_DISCONNECTED;
}
break;
case BLE_GAP_EVENT_DISCONNECT:
_debug_printf("BLE_GAP_EVENT_DISCONNECT\n");
_status = STDIO_NIMBLE_DISCONNECTED;
break;
case BLE_GAP_EVENT_SUBSCRIBE:
_debug_printf("BLE_GAP_EVENT_SUBSCRIBE\n");
if (event->subscribe.attr_handle == _val_handle_stdout) {
if (event->subscribe.cur_indicate == 1) {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
else {
_status = STDIO_NIMBLE_CONNECTED;
}
}
break;
case BLE_GAP_EVENT_NOTIFY_TX:
_debug_printf("BLE_GAP_EVENT_NOTIFY_TX\n");
if (event->notify_tx.indication == 1) {
if (event->notify_tx.status == BLE_HS_EDONE) {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
else if (event->notify_tx.status != 0) {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
}
break;
case BLE_GAP_EVENT_MTU:
_debug_printf("BLE_GAP_EVENT_MTU: mtu = %d\n", event->mtu.value);
break;
}
return 0;
}
static int gatt_svr_chr_access_stdin(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
(void)conn_handle;
(void)attr_handle;
(void)arg;
uint16_t om_len = OS_MBUF_PKTLEN(ctxt->om);
/* read sent data */
int rc = ble_hs_mbuf_to_flat(ctxt->om, _stdin_read_buf, sizeof(_stdin_read_buf), &om_len);
isrpipe_write(&_isrpipe_stdin, _stdin_read_buf, om_len);
return rc;
}
void stdio_init(void)
{
#if IS_USED(MODULE_VFS)
vfs_bind_stdio();
#endif
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
uart_init(STDIO_UART_DEV, STDIO_UART_BAUDRATE, NULL, NULL);
#endif
ble_npl_callout_init(&_send_stdout_callout, nimble_port_get_dflt_eventq(),
_send_stdout, NULL);
}
#if IS_USED(MODULE_STDIO_AVAILABLE)
int stdio_available(void)
{
return tsrb_avail(&_isrpipe_stdin.tsrb);
}
#endif
ssize_t stdio_read(void *buffer, size_t count)
{
/* blocks until at least one character was read */
ssize_t res = isrpipe_read(&_isrpipe_stdin, buffer, count);
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
unsigned state = irq_disable();
uart_write(STDIO_UART_DEV, (const uint8_t *)PREFIX_STDIN, strlen(PREFIX_STDIN));
uart_write(STDIO_UART_DEV, (const uint8_t *)buffer, res);
uart_write(STDIO_UART_DEV, (const uint8_t *)"\n", 1);
irq_restore(state);
#endif
return res;
}
ssize_t stdio_write(const void *buffer, size_t len)
{
unsigned state = irq_disable();
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
uart_write(STDIO_UART_DEV, (const uint8_t *)PREFIX_STDOUT, strlen(PREFIX_STDOUT));
uart_write(STDIO_UART_DEV, (const uint8_t *)buffer, len);
uart_write(STDIO_UART_DEV, (const uint8_t *)"\n", 1);
#endif
irq_restore(state);
unsigned int consumed = tsrb_add(&_tsrb_stdout, buffer, len);
if (!ble_npl_callout_is_active(&_send_stdout_callout)) {
/* bootstrap callout */
ble_npl_callout_reset(&_send_stdout_callout, CALLOUT_TICKS_MS);
}
return consumed;
}
/* is going to be called by auto_init */
void stdio_nimble_init(void)
{
int rc = 0;
/* verify and add our custom services */
rc = ble_gatts_count_cfg(_gatt_svr_svcs);
assert(rc == 0);
rc = ble_gatts_add_svcs(_gatt_svr_svcs);
assert(rc == 0);
/* reload the GATT server to link our added services */
ble_gatts_start();
/* register gap event listener */
rc = ble_gap_event_listener_register(&_gap_event_listener, _gap_event_cb, NULL);
assert(rc == 0);
/* fix compilation error when using DEVELHELP=0 */
(void)rc;
}

View File

@ -32,6 +32,8 @@ EXPECTED_PS = (
RIOT_TERMINAL = os.environ.get('RIOT_TERMINAL')
CLEANTERMS = {"socat"}
TESTRUNNER_SHELL_SKIP_REBOOT = bool(int(os.environ.get('TESTRUNNER_SHELL_SKIP_REBOOT') or 0))
# In native we are directly executing the binary (no terminal program). We must
# therefore use Ctrl-V (DLE or "data link escape") before Ctrl-C to send a
# literal ETX instead of SIGINT.
@ -220,6 +222,10 @@ def testfunc(child):
# loop other defined commands and expected output
for cmd, expected in CMDS:
if cmd == "reboot" and TESTRUNNER_SHELL_SKIP_REBOOT:
continue
check_cmd(child, cmd, expected)
if RIOT_TERMINAL in CLEANTERMS:

42
tests/shell_ble/Makefile Normal file
View File

@ -0,0 +1,42 @@
DEVELHELP = 0
BOARD ?= nrf52dk
include ../Makefile.tests_common
USEMODULE += app_metadata
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
USEMODULE += stdio_nimble stdio_nimble_debug
USEMODULE += nimble_autoadv
CFLAGS += -DNIMBLE_AUTOADV_DEVICE_NAME='"tests/shell_ble"'
TESTRUNNER_SHELL_SKIP_REBOOT = 1
TESTRUNNER_RESET_BOARD_ON_STARTUP = 0
ifneq (,$(filter term,$(MAKECMDGOALS)))
# for z1, socat doesn't work (unknown reason)
ifeq (z1, $(BOARD))
RIOT_TERMINAL ?= pyterm
endif
# Use a terminal that does not introduce extra characters into the stream.
RIOT_TERMINAL ?= socat
else ifneq (,$(filter test,$(MAKECMDGOALS)))
# Use the virtual serial port created by ble-serial
RIOT_TERMINAL = picocom
endif
# The test requires some setup so it cannot currently be run
TEST_ON_CI_BLACKLIST += all
APP_SHELL_FMT ?= NONE
include $(RIOTBASE)/Makefile.include
# the test script skips tests if socat is not used
$(call target-export-variables,$(RIOT_TERMINAL),RIOT_TERMINAL)
# a reboot or a reset would disconnect the device from bluetooth and break the test
$(call target-export-variables,$(TESTRUNNER_SHELL_SKIP_REBOOT),TESTRUNNER_SHELL_SKIP_REBOOT)
$(call target-export-variables,$(TESTRUNNER_RESET_BOARD_ON_STARTUP),TESTRUNNER_RESET_BOARD_ON_STARTUP)

22
tests/shell_ble/README.md Normal file
View File

@ -0,0 +1,22 @@
This is basically the same tests as for the normal shell, but here we are
testing via blueooth instead of UART. You have to set up a virtual serial port
manually.
For instructions on how to open a virtual serial port to your bluetooth device
see `sys/stdio_nimble/README`.
**Note:** `make term` and `make test-with-config` will open two different types of terminals.
- When calling `make term` then a terminal will communicate with the board
via UART. Due to the nature of `stdio_nimble` the board won't respond to input
coming from here)
- When calling `make test-with-config` then picocom will communicate with the board via the
given virtual serial port
So a procedure to run this test could be:
0. Make sure that the current test application instance is fresh and no test was
run on it before. Otherwise your test might fail, because the test case
`check_control_d` only works once per run.
1. Execute `make flash term`
2. Open a virtual serial port with `ble-serial` and note the virtual serial port
that was created (search for `Slave created on /tmp/dev_riot_ble -> /dev/pts/25`)
3. Execute `PORT=/dev/pts/25 make test-with-config`

1
tests/shell_ble/main.c Symbolic link
View File

@ -0,0 +1 @@
../shell/main.c

View File

@ -0,0 +1 @@
../../shell/tests/01-run.py