This is an automated email from the ASF dual-hosted git repository. rymek pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit a2e68282f57b206c5a6ba6146a019877cae5a994 Author: Mariusz Skamra <[email protected]> AuthorDate: Thu Feb 22 16:03:22 2024 +0100 apps/btshell: Add ISO related commands This adds ISO related commands to the btshell application. The commands can be used for testing purposes. --- apps/btshell/src/cmd.c | 51 ++++- apps/btshell/src/cmd_iso.c | 513 +++++++++++++++++++++++++++++++++++++++++++++ apps/btshell/src/cmd_iso.h | 39 ++++ 3 files changed, 602 insertions(+), 1 deletion(-) diff --git a/apps/btshell/src/cmd.c b/apps/btshell/src/cmd.c index ff8bae8c7..1b20078e8 100644 --- a/apps/btshell/src/cmd.c +++ b/apps/btshell/src/cmd.c @@ -41,6 +41,7 @@ #include "cmd.h" #include "btshell.h" #include "cmd_gatt.h" +#include "cmd_iso.h" #include "cmd_l2cap.h" #include "cmd_leaudio.h" @@ -4858,7 +4859,7 @@ static const struct shell_cmd btshell_commands[] = { }, #endif #endif -#if MYNEWT_VAL(BLE_ISO) +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) { .sc_cmd = "base_add", .sc_cmd_func = cmd_leaudio_base_add, @@ -4915,7 +4916,55 @@ static const struct shell_cmd btshell_commands[] = { .help = &leaudio_broadcast_stop_help, #endif }, +#endif /* BLE_ISO_BROADCAST_SOURCE */ +#if MYNEWT_VAL(BLE_ISO) +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + { + .sc_cmd = "big-create", + .sc_cmd_func = cmd_iso_big_create, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_big_create_help, +#endif + }, + { + .sc_cmd = "big-terminate", + .sc_cmd_func = cmd_iso_big_terminate, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_big_terminate_help, +#endif + }, +#endif /* BLE_ISO_BROADCAST_SOURCE */ +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) + { + .sc_cmd = "big-sync-create", + .sc_cmd_func = cmd_iso_big_sync_create, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_big_sync_create_help, #endif + }, + { + .sc_cmd = "big-sync-terminate", + .sc_cmd_func = cmd_iso_big_sync_terminate, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_big_sync_terminate_help, +#endif + }, +#endif /* BLE_ISO_BROADCAST_SINK */ + { + .sc_cmd = "iso-data-path-setup", + .sc_cmd_func = cmd_iso_data_path_setup, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_data_path_setup_help, +#endif + }, + { + .sc_cmd = "iso-data-path-remove", + .sc_cmd_func = cmd_iso_data_path_remove, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_data_path_remove_help, +#endif + }, +#endif /* BLE_ISO */ { 0 }, }; diff --git a/apps/btshell/src/cmd_iso.c b/apps/btshell/src/cmd_iso.c new file mode 100644 index 000000000..8d0ef343d --- /dev/null +++ b/apps/btshell/src/cmd_iso.c @@ -0,0 +1,513 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "host/ble_iso.h" + +#include "cmd_iso.h" + +#include "console/console.h" +#include "shell/shell.h" + +#if (MYNEWT_VAL(BLE_ISO)) +static struct iso_rx_stats { + uint8_t bis_index; + bool ts_valid; + uint32_t ts; + uint16_t seq_num; + uint64_t total_cnt; + uint64_t valid_cnt; + uint64_t error_cnt; + uint64_t lost_cnt; +} rx_stats_pool[MYNEWT_VAL(BLE_MAX_BIS)]; + +static void +iso_rx_stats_update(uint16_t conn_handle, const struct ble_iso_rx_data_info *info, + struct iso_rx_stats *stats) +{ + stats->ts_valid = info->ts_valid; + if (stats->ts_valid) { + stats->ts = info->ts; + } + + stats->seq_num = info->seq_num; + + if (info->status == BLE_ISO_DATA_STATUS_VALID) { + stats->valid_cnt++; + } else if (info->status == BLE_ISO_DATA_STATUS_ERROR) { + stats->error_cnt++; + } else if (info->status == BLE_ISO_DATA_STATUS_LOST) { + stats->lost_cnt++; + } + + stats->total_cnt++; + + if ((stats->total_cnt % 100) == 0) { + console_printf("BIS=%d, seq_num=%d, num_rx=%lld, " + "(valid=%lld, error=%lld, lost=%lld) ", + stats->bis_index, stats->seq_num, + stats->total_cnt, stats->valid_cnt, + stats->error_cnt, stats->lost_cnt); + + if (stats->ts_valid) { + console_printf("ts=10%" PRIu32, stats->ts); + } + + console_printf("\n"); + } +} + +static void +print_iso_big_desc(const struct ble_iso_big_desc *desc) +{ + console_printf(" big_handle=0x%02x, big_sync_delay=%" PRIu32 "," + " transport_latency=%" PRIu32 ", nse=%u, bn=%u, pto=%u," + " irc=%u, max_pdu=%u, iso_interval=%u num_bis=%u", + desc->big_handle, desc->big_sync_delay, + desc->transport_latency_big, desc->nse, desc->bn, desc->pto, + desc->irc, desc->max_pdu, desc->iso_interval, desc->num_bis); + + if (desc->num_bis > 0) { + console_printf(" conn_handles="); + } + + for (uint8_t i = 0; i < desc->num_bis; i++) { + console_printf("0x%04x,", desc->conn_handle[i]); + } +} + +static int +ble_iso_event_handler(struct ble_iso_event *event, void *arg) +{ + switch (event->type) { + case BLE_ISO_EVENT_BIG_CREATE_COMPLETE: + console_printf("BIG Create Completed status: %u", + event->big_created.status); + + if (event->big_created.status == 0) { + print_iso_big_desc(&event->big_created.desc); + console_printf(" phy=0x%02x", event->big_created.phy); + } + + console_printf("\n"); + break; + + case BLE_ISO_EVENT_BIG_SYNC_ESTABLISHED: + console_printf("BIG Sync Established status: %u", + event->big_sync_established.status); + + if (event->big_sync_established.status == 0) { + print_iso_big_desc(&event->big_sync_established.desc); + } + + console_printf("\n"); + break; + + case BLE_ISO_EVENT_BIG_SYNC_TERMINATED: + console_printf("BIG Sync Terminated handle=0x%02x reason: %u\n", + event->big_terminated.big_handle, + event->big_terminated.reason); + break; + + case BLE_ISO_EVENT_ISO_RX: + iso_rx_stats_update(event->iso_rx.conn_handle, event->iso_rx.info, arg); + os_mbuf_free_chain(event->iso_rx.om); + break; + + default: + break; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_big_create_params[] = { + {"adv_handle", "PA advertising handle, usage: =<UINT8>"}, + {"bis_cnt", "BIS count, usage: =<UINT8>"}, + {"sdu_interval", "SDU interval, usage: =<UINT32>"}, + {"max_sdu", "Maximum SDU size, usage: =<UINT16>"}, + {"max_latency", "Maximum transport latency, usage: =<UINT16>"}, + {"rtn", "Retransmission number, usage: =<UINT8>"}, + {"phy", "PHY, usage: =<UINT8>"}, + {"packing", "Packing, usage: =<UINT8>, default: 1"}, + {"framing", "Framing, usage: =<UINT8>, default: 0"}, + {"broadcast_code", "Broadcast Code, usage: =[string], default: NULL"}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_big_create_help = { + .summary = "Create BIG", + .usage = NULL, + .params = cmd_iso_big_create_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_big_create(int argc, char **argv) +{ + struct ble_iso_create_big_params params = { 0 }; + struct ble_iso_big_params big_params = { 0 }; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.adv_handle = parse_arg_uint8("adv_handle", &rc); + if (rc != 0) { + console_printf("invalid 'adv_handle' parameter\n"); + return rc; + } + + params.cb = ble_iso_event_handler; + + params.bis_cnt = parse_arg_uint8("bis_cnt", &rc); + if (rc != 0) { + console_printf("invalid 'bis_cnt' parameter\n"); + return rc; + } + + big_params.sdu_interval = parse_arg_uint32_bounds("sdu_interval", + 0x0000FF, 0x0FFFFF, + &rc); + if (rc != 0) { + console_printf("invalid 'sdu_interval' parameter\n"); + return rc; + } + + big_params.max_sdu = parse_arg_uint16_bounds("max_sdu", 0x0001, 0x0FFF, + &rc); + if (rc != 0) { + console_printf("invalid 'max_sdu' parameter\n"); + return rc; + } + + big_params.max_transport_latency = parse_arg_uint16_bounds("max_latency", + 0x0005, 0x0FA0, + &rc); + if (rc != 0) { + console_printf("invalid 'max_latency' parameter\n"); + return rc; + } + + big_params.rtn = parse_arg_uint8_bounds("rtn", 0x00, 0x1E, &rc); + if (rc != 0) { + console_printf("invalid 'rtn' parameter\n"); + return rc; + } + + big_params.phy = parse_arg_uint8_bounds("phy", 0, 2, &rc); + if (rc != 0) { + console_printf("invalid 'phy' parameter\n"); + return rc; + } + + big_params.packing = parse_arg_uint8_bounds_dflt("packing", 0, 1, 1, &rc); + if (rc != 0) { + console_printf("invalid 'packing' parameter\n"); + return rc; + } + + big_params.framing = parse_arg_uint8_bounds_dflt("framing", 0, 1, 0, &rc); + if (rc != 0) { + console_printf("invalid 'framing' parameter\n"); + return rc; + } + + big_params.broadcast_code = parse_arg_extract("broadcast_code"); + big_params.encryption = big_params.broadcast_code ? 1 : 0; + + rc = ble_iso_create_big(¶ms, &big_params); + if (rc != 0) { + console_printf("BIG create failed (%d)\n", rc); + return rc; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_big_terminate_params[] = { + {"big_handle", "BIG handle, usage: =<UINT8>"}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_big_terminate_help = { + .summary = "Terminate BIG", + .usage = NULL, + .params = cmd_iso_big_terminate_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_big_terminate(int argc, char **argv) +{ + uint8_t big_handle; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + big_handle = parse_arg_uint8("big_handle", &rc); + if (rc != 0) { + console_printf("invalid 'big_handle' parameter\n"); + return rc; + } + + rc = ble_iso_terminate_big(big_handle); + if (rc != 0) { + console_printf("BIG terminate failed (%d)\n", rc); + return rc; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_big_sync_create_params[] = { + {"sync_handle", "PA sync handle, usage: =<UINT16>"}, + {"broadcast_code", "Broadcast Code, usage: =[string], default: NULL"}, + {"mse", "Maximum Subevents to receive data, usage: =<UINT8>"}, + {"sync_timeout", "BIG sync timeout, usage: =<UINT8>"}, + {"idxs", "BIS indexes, usage: =XX,YY,..."}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_big_sync_create_help = { + .summary = "Synchronize to BIG", + .usage = NULL, + .params = cmd_iso_big_sync_create_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_big_sync_create(int argc, char **argv) +{ + struct ble_iso_bis_params bis_params[MYNEWT_VAL(BLE_MAX_BIS)]; + struct ble_iso_big_sync_create_params params = { 0 }; + uint8_t bis_idxs[MYNEWT_VAL(BLE_MAX_BIS)]; + uint8_t big_handle; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.sync_handle = parse_arg_uint16("sync_handle", &rc); + if (rc != 0) { + console_printf("invalid 'sync_handle' parameter\n"); + return rc; + } + + params.broadcast_code = parse_arg_extract("broadcast_code"); + + params.mse = parse_arg_uint8_dflt("mse", 0, &rc); + if (rc != 0) { + console_printf("invalid 'mse' parameter\n"); + return rc; + } + + params.sync_timeout = parse_arg_uint16("sync_timeout", &rc); + if (rc != 0) { + console_printf("invalid 'sync_timeout' parameter\n"); + return rc; + } + + rc = parse_arg_byte_stream_custom("idxs", ",", ARRAY_SIZE(bis_idxs), + bis_idxs, 0, + (unsigned int *)¶ms.bis_cnt); + if (rc != 0) { + console_printf("invalid 'idxs' parameter\n"); + return rc; + } + + for (uint8_t i = 0; i < params.bis_cnt; i++) { + bis_params[i].bis_index = bis_idxs[i]; + bis_params[i].cb = ble_iso_event_handler; + bis_params[i].cb_arg = &rx_stats_pool[i]; + + /* Reset stats */ + memset(&rx_stats_pool[i], 0, sizeof(rx_stats_pool[i])); + rx_stats_pool[i].bis_index = bis_idxs[i]; + } + + params.bis_params = bis_params; + params.cb = ble_iso_event_handler; + + rc = ble_iso_big_sync_create(¶ms, &big_handle); + if (rc != 0) { + console_printf("BIG Sync create failed (%d)\n", rc); + return rc; + } + + console_printf("New big_handle %u created\n", big_handle); + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_big_sync_terminate_params[] = { + {"big_handle", "BIG handle, usage: =<UINT8>"}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_big_sync_terminate_help = { + .summary = "Terminate BIG sync", + .usage = NULL, + .params = cmd_iso_big_sync_terminate_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_big_sync_terminate(int argc, char **argv) +{ + uint8_t big_handle; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + big_handle = parse_arg_uint8("big_handle", &rc); + if (rc != 0) { + console_printf("invalid 'big_handle' parameter\n"); + return rc; + } + + rc = ble_iso_big_sync_terminate(big_handle); + if (rc != 0) { + console_printf("BIG Sync terminate failed (%d)\n", rc); + return rc; + } + + return 0; +} + +static const struct parse_arg_kv_pair cmd_iso_data_dir[] = { + { "tx", BLE_ISO_DATA_DIR_TX }, + { "rx", BLE_ISO_DATA_DIR_RX }, + + { NULL } +}; + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_data_path_setup_params[] = { + {"conn_handle", "Connection handle, usage: =<UINT16>"}, + {"dir", "Data path direction, usage: =[tx|rx]"}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_data_path_setup_help = { + .summary = "Setup ISO Data Path", + .usage = NULL, + .params = cmd_iso_data_path_setup_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_data_path_setup(int argc, char **argv) +{ + struct ble_iso_data_path_setup_params params = { 0 }; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.conn_handle = parse_arg_uint16("conn_handle", &rc); + if (rc != 0) { + console_printf("invalid 'conn_handle' parameter\n"); + return rc; + } + + params.data_path_dir = parse_arg_kv("dir", cmd_iso_data_dir, &rc); + if (rc != 0) { + console_printf("invalid 'dir' parameter\n"); + return rc; + } + + /* For now, the Data Path ID is set to HCI by default */ + + rc = ble_iso_data_path_setup(¶ms); + if (rc != 0) { + console_printf("ISO Data Path setup failed (%d)\n", rc); + return rc; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_data_path_remove_params[] = { + {"conn_handle", "Connection handle, usage: =<UINT16>"}, + {"dir", "Data path direction, usage: =[tx|rx]"}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_data_path_remove_help = { + .summary = "Remove ISO Data Path", + .usage = NULL, + .params = cmd_iso_data_path_remove_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_data_path_remove(int argc, char **argv) +{ + struct ble_iso_data_path_remove_params params = { 0 }; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.conn_handle = parse_arg_uint16("conn_handle", &rc); + if (rc != 0) { + console_printf("invalid 'conn_handle' parameter\n"); + return rc; + } + + params.data_path_dir = parse_arg_kv("dir", cmd_iso_data_dir, &rc); + if (rc != 0) { + console_printf("invalid 'dir' parameter\n"); + return rc; + } + + rc = ble_iso_data_path_remove(¶ms); + if (rc != 0) { + console_printf("ISO Data Path remove failed (%d)\n", rc); + return rc; + } + + return 0; +} +#endif /* BLE_ISO */ diff --git a/apps/btshell/src/cmd_iso.h b/apps/btshell/src/cmd_iso.h new file mode 100644 index 000000000..c027c0885 --- /dev/null +++ b/apps/btshell/src/cmd_iso.h @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_CMD_ISO_ +#define H_CMD_ISO_ + +#include "cmd.h" + +extern const struct shell_cmd_help cmd_iso_big_create_help; +extern const struct shell_cmd_help cmd_iso_big_terminate_help; +extern const struct shell_cmd_help cmd_iso_big_sync_create_help; +extern const struct shell_cmd_help cmd_iso_big_sync_terminate_help; +extern const struct shell_cmd_help cmd_iso_data_path_setup_help; +extern const struct shell_cmd_help cmd_iso_data_path_remove_help; + +int cmd_iso_big_create(int argc, char **argv); +int cmd_iso_big_terminate(int argc, char **argv); +int cmd_iso_big_sync_create(int argc, char **argv); +int cmd_iso_big_sync_terminate(int argc, char **argv); +int cmd_iso_data_path_setup(int argc, char **argv); +int cmd_iso_data_path_remove(int argc, char **argv); + +#endif /* H_CMD_ISO_ */
