isotest: Add support for creating/synchronizing to multiple BISes

This adds an additional command line option for the Broadcast exercise,
so that the user can indicate the number of BISes to create as part of a
BIG (Broadcast Source), or the number of BISes to synchronize
to (Broadcast Sink).

For the Broadcast Source exercise, issue the following command,
in order to create a BIG with handle 0x01, associated with the
advertising handle 0x01, with 2 BISes:

    tools/isotest -i hci0 -s 00:00:00:00:00:00 -N 2 -G 1 -T 1

The isotest and btmon logs will look something like this:

isotest[7178]: mgmt socket: fd 3
isotest[7178]: mgmt_set_le: err 0
isotest[7178]: mgmt_set_experimental: err 0
isotest[7179]: Exit
isotest[7178]: Connecting 00:00:00:00:00:00 ...
isotest[7178]: Connected [00:00:00:00:00:00]
isotest[7178]: QoS [BIG 0x01 BIS 0x01 Packing 0x00 Framing 0x00 Encryption 0x00]
isotest[7178]: Input QoS [Interval 10000 us Latency 10 ms SDU 0 PHY 0x00 RTN 2]
isotest[7178]: Output QoS [Interval 10000 us Latency 10 ms SDU 40 PHY 0x02 RTN 2]
isotest[7178]: Connecting 00:00:00:00:00:00 ...
isotest[7178]: Connected [00:00:00:00:00:00]
isotest[7178]: QoS [BIG 0x01 BIS 0x01 Packing 0x00 Framing 0x00 Encryption 0x00]
isotest[7178]: Input QoS [Interval 10000 us Latency 10 ms SDU 0 PHY 0x00 RTN 2]
isotest[7178]: Output QoS [Interval 10000 us Latency 10 ms SDU 40 PHY 0x02 RTN 2]
isotest[7183]: Sending ...
isotest[7183]: Number of packets: 1
isotest[7183]: Socket jitter buffer: 80 buffer
isotest[7183]: [seq 0] 40 bytes buffered 92 (3712 bytes)
isotest[7184]: Sending ...
isotest[7184]: Number of packets: 1
isotest[7184]: Socket jitter buffer: 80 buffer
isotest[7184]: [seq 0] 40 bytes buffered 92 (3712 bytes)
isotest[7178]: Exit

< HCI Command: LE Create Broadcast Isochronous Group (0x08|0x0068) plen 31
        Handle: 0x01
        Advertising Handle: 0x01
        Number of BIS: 2
        SDU Interval: 10000 us (0x002710)
        Maximum SDU size: 40
        Maximum Latency: 10 ms (0x000a)
        RTN: 0x02
        PHY: LE 2M (0x02)
        Packing: Sequential (0x00)
        Framing: Unframed (0x00)
        Encryption: 0x00
        Broadcast Code: 00000000000000000000000000000000

> HCI Event: Command Status (0x0f) plen 4
      LE Create Broadcast Isochronous Group (0x08|0x0068) ncmd 1
        Status: Success (0x00)

> HCI Event: LE Meta Event (0x3e) plen 23
      LE Broadcast Isochronous Group Complete (0x1b)
        Status: Success (0x00)
        Handle: 0x01
        BIG Synchronization Delay: 1974 us (0x0007b6)
        Transport Latency: 1974 us (0x0007b6)
        PHY: LE 2M (0x02)
        NSE: 3
        BN: 1
        PTO: 1
        IRC: 3
        Maximum PDU: 40
        ISO Interval: 10.00 msec (0x0008)
        Connection Handle #0: 10
        Connection Handle #1: 11

< HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13
        Handle: 10
        Data Path Direction: Input (Host to Controller) (0x00)
        Data Path: HCI (0x00)
        Coding Format: Transparent (0x03)
        Company Codec ID: Ericsson Technology Licensing (0)
        Vendor Codec ID: 0
        Controller Delay: 0 us (0x000000)
        Codec Configuration Length: 0
        Codec Configuration:

> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 10

< HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13
        Handle: 11
        Data Path Direction: Input (Host to Controller) (0x00)
        Data Path: HCI (0x00)
        Coding Format: Transparent (0x03)
        Company Codec ID: Ericsson Technology Licensing (0)
        Vendor Codec ID: 0
        Controller Delay: 0 us (0x000000)
        Codec Configuration Length: 0
        Codec Configuration:

> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 11

< ISO Data TX: Handle 10 flags 0x02 dlen 44

< ISO Data TX: Handle 11 flags 0x02 dlen 44

> HCI Event: Number of Completed Packets (0x13) plen 5
        Num handles: 1
        Handle: 10
        Count: 1

> HCI Event: Number of Completed Packets (0x13) plen 5
        Num handles: 1
        Handle: 11
        Count: 1

For the Broadcast Sink exercise, issue the following command,
in order to synchronize to the BISes created by the source:

    tools/isotest -i hci1 -r 36:13:00:E1:1B:F0 -V le_random -N 2 -G 1

The flow is shown by the isotest log and the filtered btmon snippet below:

isotest[4033]: mgmt socket: fd 3
isotest[4034]: Exit
isotest[4033]: mgmt_set_le: err 0
isotest[4033]: mgmt_set_experimental: err 0
isotest[4033]: Waiting for connection 36:13:00:E1:1B:F0...
isotest[4036]: Connected [36:13:00:E1:1B:F0]
isotest[4036]: QoS [BIG 0x01 BIS 0x00 Packing 0x00 Framing 0x00 Encryption 0x00]
isotest[4036]: Input QoS [Interval 1974 us Latency 10 ms SDU 40 PHY 0x00 RTN 0]
isotest[4036]: Output QoS [Interval 0 us Latency 0 ms SDU 0 PHY 0x00 RTN 0]
isotest[4036]: Receiving ...
isotest[4037]: Connected [36:13:00:E1:1B:F0]
isotest[4037]: QoS [BIG 0x01 BIS 0x00 Packing 0x00 Framing 0x00 Encryption 0x00]
isotest[4037]: Input QoS [Interval 1974 us Latency 10 ms SDU 40 PHY 0x00 RTN 0]
isotest[4037]: Output QoS [Interval 0 us Latency 0 ms SDU 0 PHY 0x00 RTN 0]
isotest[4037]: Receiving ...
isotest[4037]: [seq 0] 280 bytes in 6.48 sec speed 0.34 kb/s
isotest[4036]: [seq 0] 280 bytes in 6.54 sec speed 0.33 kb/s
isotest[4037]: [seq 1] 280 bytes in 7.01 sec speed 0.31 kb/s
isotest[4036]: [seq 1] 280 bytes in 7.02 sec speed 0.31 kb/s
isotest[4037]: [seq 2] 280 bytes in 7.06 sec speed 0.31 kb/s
isotest[4036]: [seq 2] 280 bytes in 7.04 sec speed 0.31 kb/s

< HCI Command: LE Periodic Advertising Create Sync (0x08|0x0044) plen 14
        Options: 0x0000
        Use advertising SID, Advertiser Address Type and address
        Reporting initially enabled
        SID: 0x00
        Adv address type: Random (0x01)
        Adv address: 36:13:00:E1:1B:F0 (Non-Resolvable)
        Skip: 0x0000
        Sync timeout: 163840 msec (0x4000)
        Sync CTE type: 0x0000

> HCI Event: Command Status (0x0f) plen 4
      LE Periodic Advertising Create Sync (0x08|0x0044) ncmd 1
        Status: Success (0x00)

< HCI Command: LE Set Extended Scan Parameters (0x08|0x0041) plen 13
        Own address type: Public (0x00)
        Filter policy: Ignore not in accept list (0x01)
        PHYs: 0x05
        Entry 0: LE 1M
          Type: Passive (0x00)
          Interval: 60.000 msec (0x0060)
          Window: 30.000 msec (0x0030)
        Entry 1: LE Coded
          Type: Passive (0x00)
          Interval: 60.000 msec (0x0060)
          Window: 30.000 msec (0x0030)

> HCI Event: Command Complete (0x0e) plen 4
      LE Set Extended Scan Parameters (0x08|0x0041) ncmd 1
        Status: Success (0x00)

< HCI Command: LE Set Extended Scan Enable (0x08|0x0042) plen 6
        Extended scan: Enabled (0x01)
        Filter duplicates: Enabled (0x01)
        Duration: 0 msec (0x0000)
        Period: 0.00 sec (0x0000)

> HCI Event: Command Complete (0x0e) plen 4
      LE Set Extended Scan Enable (0x08|0x0042) ncmd 1
        Status: Success (0x00)

> HCI Event: LE Meta Event (0x3e) plen 16
      LE Periodic Advertising Sync Established (0x0e)
        Status: Success (0x00)
        Sync handle: 0
        Advertising SID: 0x00
        Advertiser address type: Random (0x01)
        Advertiser address: 36:13:00:E1:1B:F0 (Non-Resolvable)
        Advertiser PHY: LE 2M (0x02)
        Periodic advertising interval: 10.00 msec (0x0008)
        Advertiser clock accuracy: 0x00

> HCI Event: LE Meta Event (0x3e) plen 8
      LE Periodic Advertising Report (0x0f)
        Sync handle: 0
        TX power: 127 dbm (0x7f)
        RSSI: -47 dBm (0xd1)
        CTE Type: No Constant Tone Extension (0xff)
        Data status: Complete
        Data length: 0x00

> HCI Event: LE Meta Event (0x3e) plen 20
      LE Broadcast Isochronous Group Info Advertising Report (0x22)
        Sync Handle: 0x0000
        Number BIS: 2
        NSE: 3
        ISO Interval: 10.00 msec (0x0008)
        BN: 1
        PTO: 1
        IRC: 3
        Maximum PDU: 40
        SDU Interval: 10000 us (0x002710)
        Maximum SDU: 40
        PHY: LE 2M (0x02)
        Framing: Unframed (0x00)
        Encryption: 0x00

< HCI Command: LE Broadcast Isochronous Group Create Sync (0x08|0x006b) plen 26
        BIG Handle: 0x01
        BIG Sync Handle: 0x0000
        Encryption: Unencrypted (0x00)
        Broadcast Code: 00000000000000000000000000000000
        Maximum Number Subevents: 0x00
        Timeout: 163840 ms (0x4000)
        Number of BIS: 2
        BIS ID: 0x01
        BIS ID: 0x02

> HCI Event: LE Meta Event (0x3e) plen 19
      LE Broadcast Isochronous Group Sync Estabilished (0x1d)
        Status: Success (0x00)
        BIG Handle: 0x01
        Transport Latency: 1974 us (0x0007b6)
        NSE: 3
        BN: 1
        PTO: 1
        IRC: 3
        Maximum PDU: 40
        ISO Interval: 10.00 msec (0x0008)
        Connection Handle #0: 10
        Connection Handle #1: 11

< HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13
        Handle: 10
        Data Path Direction: Output (Controller to Host) (0x01)
        Data Path: HCI (0x00)
        Coding Format: Transparent (0x03)
        Company Codec ID: Ericsson Technology Licensing (0)
        Vendor Codec ID: 0
        Controller Delay: 0 us (0x000000)
        Codec Configuration Length: 0
        Codec Configuration:

> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 10

< HCI Command: LE Setup Isochronous Data Path (0x08|0x006e) plen 13
        Handle: 11
        Data Path Direction: Output (Controller to Host) (0x01)
        Data Path: HCI (0x00)
        Coding Format: Transparent (0x03)
        Company Codec ID: Ericsson Technology Licensing (0)
        Vendor Codec ID: 0
        Controller Delay: 0 us (0x000000)
        Codec Configuration Length: 0
        Codec Configuration:

> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 11

> ISO Data RX: Handle 10 flags 0x06 dlen 48

> ISO Data RX: Handle 11 flags 0x06 dlen 48
This commit is contained in:
Iulia Tanasescu 2023-05-29 09:27:34 +03:00 committed by Luiz Augusto von Dentz
parent 15eb57049b
commit 8ff103f993
2 changed files with 225 additions and 83 deletions

View File

@ -32,6 +32,7 @@
#include <linux/sockios.h>
#include <time.h>
#include <inttypes.h>
#include <sys/wait.h>
#include "lib/bluetooth.h"
#include "lib/hci.h"
@ -45,6 +46,9 @@
#define SEC_USEC(_t) (_t * 1000000L)
#define TS_USEC(_ts) (SEC_USEC((_ts)->tv_sec) + NSEC_USEC((_ts)->tv_nsec))
#define DEFAULT_BIG_ID 0x01
#define DEFAULT_BIS_ID 0x01
/* Test modes */
enum {
SEND,
@ -72,6 +76,8 @@ static bool quiet;
struct bt_iso_qos *iso_qos;
static bool inout;
static uint8_t num_bis = 1;
struct lookup_table {
const char *name;
int flag;
@ -316,8 +322,6 @@ static int do_connect(char *peer)
struct sockaddr_iso addr;
int sk;
mgmt_set_experimental();
/* Create socket */
sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_ISO);
if (sk < 0) {
@ -390,6 +394,45 @@ error:
return -1;
}
static int *bcast_do_connect_mbis(uint8_t count, char *peer)
{
int *sk;
uint8_t sk_cnt = 0;
sk = malloc(count * sizeof(*sk));
if (!sk) {
syslog(LOG_ERR, "Can't allocate socket array");
return NULL;
}
defer_setup = 1;
for (int i = 0; i < count; i++) {
if (i == count - 1)
defer_setup = 0;
sk[i] = do_connect(peer);
if (sk[i] < 0) {
syslog(LOG_ERR, "Can't create socket: %s (%d)",
strerror(errno), errno);
goto error;
}
sk_cnt++;
}
return sk;
error:
for (int i = 0; i < sk_cnt; i++)
close(sk[i]);
free(sk);
return NULL;
}
static void do_listen(char *filename, void (*handler)(int fd, int sk),
char *peer)
{
@ -431,8 +474,11 @@ static void do_listen(char *filename, void (*handler)(int fd, int sk),
if (peer) {
str2ba(peer, &addr->iso_bc->bc_bdaddr);
addr->iso_bc->bc_bdaddr_type = bdaddr_type;
addr->iso_bc->bc_num_bis = 1;
addr->iso_bc->bc_bis[0] = 1;
addr->iso_bc->bc_num_bis = num_bis;
for (int i = 0; i < num_bis; i++)
addr->iso_bc->bc_bis[i] = i + 1;
optlen += sizeof(*addr->iso_bc);
}
@ -584,6 +630,7 @@ static void recv_mode(int fd, int sk)
strerror(errno), errno);
if (errno != ENOTCONN)
return;
r = 0;
}
@ -704,84 +751,16 @@ static int read_file(int fd, ssize_t count, bool rewind)
return len;
}
static void do_send(int sk, int fd, struct bt_iso_io_qos *out, uint32_t num,
bool repeat)
static void do_send(int sk, int fd, char *peer, bool repeat)
{
uint32_t seq;
struct timespec t_start;
int len, used;
if (clock_gettime(CLOCK_MONOTONIC, &t_start) < 0) {
perror("clock_gettime");
exit(EXIT_FAILURE);
}
for (seq = 0; ; seq++) {
if (fd >= 0) {
len = read_file(fd, out->sdu, repeat);
if (len < 0) {
syslog(LOG_ERR, "read failed: %s (%d)",
strerror(-len), -len);
exit(1);
}
} else
len = out->sdu;
len = send(sk, buf, len, 0);
if (len <= 0) {
syslog(LOG_ERR, "send failed: %s (%d)",
strerror(errno), errno);
exit(1);
}
ioctl(sk, TIOCOUTQ, &used);
if (!quiet)
syslog(LOG_INFO,
"[seq %d] %d bytes buffered %d (%d bytes)",
seq, len, used / len, used);
if (seq && !((seq + 1) % num))
send_wait(&t_start, num * out->interval);
}
}
static void send_mode(char *filename, char *peer, int i, bool repeat)
{
struct bt_iso_qos qos;
int send_len, used;
socklen_t len;
int sk, fd = -1;
struct bt_iso_qos qos;
uint32_t num;
struct bt_iso_io_qos *out;
if (filename) {
char altername[PATH_MAX];
struct stat st;
int err;
snprintf(altername, PATH_MAX, "%s.%u", filename, i);
err = stat(altername, &st);
if (!err)
fd = open_file(altername);
if (fd <= 0)
fd = open_file(filename);
}
sk = do_connect(peer);
if (sk < 0) {
syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
strerror(errno), errno);
exit(1);
}
if (defer_setup) {
syslog(LOG_INFO, "Waiting for %d seconds",
abs(defer_setup) - 1);
sleep(abs(defer_setup) - 1);
}
syslog(LOG_INFO, "Sending ...");
/* Read QoS */
@ -830,14 +809,114 @@ static void send_mode(char *filename, char *peer, int i, bool repeat)
}
}
for (i = 6; i < out->sdu; i++)
for (int i = 6; i < out->sdu; i++)
buf[i] = 0x7f;
do_send(sk, fd, out, num, repeat);
if (clock_gettime(CLOCK_MONOTONIC, &t_start) < 0) {
perror("clock_gettime");
exit(EXIT_FAILURE);
}
for (seq = 0; ; seq++) {
if (fd >= 0) {
send_len = read_file(fd, out->sdu, repeat);
if (send_len < 0) {
syslog(LOG_ERR, "read failed: %s (%d)",
strerror(-send_len), -send_len);
exit(1);
}
} else
send_len = out->sdu;
send_len = send(sk, buf, send_len, 0);
if (send_len <= 0) {
syslog(LOG_ERR, "send failed: %s (%d)",
strerror(errno), errno);
exit(1);
}
ioctl(sk, TIOCOUTQ, &used);
if (!quiet)
syslog(LOG_INFO,
"[seq %d] %d bytes buffered %d (%d bytes)",
seq, send_len, used / send_len, used);
if (seq && !((seq + 1) % num))
send_wait(&t_start, num * out->interval);
}
}
static void send_mode(char *filename, char *peer, int i, bool repeat)
{
int sk, fd = -1;
int *sk_arr;
uint8_t nconn = strcmp(peer, "00:00:00:00:00:00") ? 1 : num_bis;
mgmt_set_experimental();
if (filename) {
char altername[PATH_MAX];
struct stat st;
int err;
snprintf(altername, PATH_MAX, "%s.%u", filename, i);
err = stat(altername, &st);
if (!err)
fd = open_file(altername);
if (fd <= 0)
fd = open_file(filename);
}
if (nconn > 1) {
sk_arr = bcast_do_connect_mbis(nconn, peer);
if (!sk_arr)
exit(1);
for (int i = 0; i < nconn; i++) {
if (fork()) {
/* Parent */
continue;
}
/* Child */
do_send(sk_arr[i], fd, peer, repeat);
exit(0);
}
/* Wait for children to exit */
while (wait(NULL) > 0)
;
for (int i = 0; i < nconn; i++)
close(sk_arr[i]);
free(sk_arr);
return;
}
sk = do_connect(peer);
if (sk < 0) {
syslog(LOG_ERR, "Can't connect to the server: %s (%d)",
strerror(errno), errno);
exit(1);
}
if (defer_setup) {
syslog(LOG_INFO, "Waiting for %d seconds",
abs(defer_setup) - 1);
sleep(abs(defer_setup) - 1);
}
do_send(sk, fd, peer, repeat);
}
static void reconnect_mode(char *peer)
{
mgmt_set_experimental();
while (1) {
int sk;
@ -856,6 +935,8 @@ static void reconnect_mode(char *peer)
static void multy_connect_mode(char *peer)
{
mgmt_set_experimental();
while (1) {
int i, sk;
@ -989,7 +1070,8 @@ static void usage(void)
"\t[-B, --preset <value>]\n"
"\t[-G, --CIG/BIG <value>]\n"
"\t[-T, --CIS/BIS <value>]\n"
"\t[-V, --type <value>] address type (help for list)\n");
"\t[-V, --type <value>] address type (help for list)\n"
"\t[-N, --nbis <value>] Number of BISes to create/synchronize to\n");
}
static const struct option main_options[] = {
@ -1019,6 +1101,7 @@ static const struct option main_options[] = {
{ "CIG/BIG", required_argument, NULL, 'G'},
{ "CIS/BIS", required_argument, NULL, 'T'},
{ "type", required_argument, NULL, 'V'},
{ "nbis", required_argument, NULL, 'N'},
{}
};
@ -1048,6 +1131,8 @@ int main(int argc, char *argv[])
char *filename = NULL;
bool repeat = false;
unsigned int i;
uint8_t nconn = 1;
char *peer;
iso_qos = malloc(sizeof(*iso_qos));
/* Default to 16_2_1 */
@ -1058,7 +1143,7 @@ int main(int argc, char *argv[])
int opt;
opt = getopt_long(argc, argv,
"d::cmr::s::nb:i:j:hqt:CV:W:M:S:P:F:I:L:Y:R:B:G:T:e:k:",
"d::cmr::s::nb:i:j:hqt:CV:W:M:S:P:F:I:L:Y:R:B:G:T:e:k:N:",
main_options, NULL);
if (opt < 0)
break;
@ -1224,6 +1309,23 @@ int main(int argc, char *argv[])
exit(1);
break;
case 'N':
if (optarg)
num_bis = atoi(optarg);
if (num_bis > 1) {
/* If the user requested multiple BISes,
* make sure that all BISes are bound
* for the same BIG and advertising set
*/
if (iso_qos->bcast.big == BT_ISO_QOS_BIG_UNSET)
iso_qos->bcast.big = DEFAULT_BIG_ID;
if (iso_qos->bcast.bis == BT_ISO_QOS_BIS_UNSET)
iso_qos->bcast.bis = DEFAULT_BIS_ID;
}
break;
/* fall through */
default:
usage();
@ -1297,10 +1399,46 @@ int main(int argc, char *argv[])
break;
case CONNECT:
sk = do_connect(argv[optind + i]);
if (sk < 0)
exit(1);
dump_mode(-1, sk);
peer = argv[optind + i];
mgmt_set_experimental();
if (!strcmp(peer, "00:00:00:00:00:00"))
nconn = num_bis;
if (nconn > 1) {
int *sk_arr = bcast_do_connect_mbis(nconn,
peer);
if (!sk_arr)
exit(1);
for (int i = 0; i < nconn; i++) {
if (fork()) {
/* Parent */
continue;
}
/* Child */
dump_mode(-1, sk_arr[i]);
exit(0);
}
/* Wait for children to exit */
while (wait(NULL) > 0)
;
for (int i = 0; i < nconn; i++)
close(sk_arr[i]);
free(sk_arr);
} else {
sk = do_connect(argv[optind + i]);
if (sk < 0)
exit(1);
dump_mode(-1, sk);
}
break;
case RECV:

View File

@ -172,6 +172,10 @@ OPTIONS
-k, --bcode=<BCODE> Socket QoS Broadcast Code
-N, --nbis=<NBIS> Number of BISes to create as part of a
BIG (BIS broadcaster) or to synchronize
to (BIS broadcast receiver)
EXAMPLES
========