| /* |
| * Copyright (c) 2023 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include <zephyr/kernel.h> |
| |
| #include "bs_types.h" |
| #include "bs_tracing.h" |
| #include "time_machine.h" |
| #include "bstests.h" |
| |
| #include <zephyr/types.h> |
| #include <zephyr/sys/printk.h> |
| |
| #include <zephyr/bluetooth/bluetooth.h> |
| |
| #include "common.h" |
| |
| extern enum bst_result_t bst_result; |
| |
| static struct bt_conn *g_conn; |
| |
| CREATE_FLAG(flag_connected); |
| CREATE_FLAG(flag_bonded); |
| |
| static void connected(struct bt_conn *conn, uint8_t err) |
| { |
| char addr[BT_ADDR_LE_STR_LEN]; |
| |
| bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); |
| |
| if (err != BT_HCI_ERR_SUCCESS) { |
| FAIL("Failed to connect to %s: %u\n", addr, err); |
| return; |
| } |
| |
| printk("Connected to %s\n", addr); |
| g_conn = bt_conn_ref(conn); |
| SET_FLAG(flag_connected); |
| } |
| |
| static void disconnected(struct bt_conn *conn, uint8_t reason) |
| { |
| char addr[BT_ADDR_LE_STR_LEN]; |
| |
| bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); |
| |
| printk("Disconnected: %s (reason %u)\n", addr, reason); |
| |
| bt_conn_unref(g_conn); |
| g_conn = NULL; |
| } |
| |
| static struct bt_conn_cb conn_cbs = { |
| .connected = connected, |
| .disconnected = disconnected, |
| }; |
| |
| static void pairing_complete_cb(struct bt_conn *conn, bool bonded) |
| { |
| if (conn == g_conn && bonded) { |
| SET_FLAG(flag_bonded); |
| } |
| } |
| |
| static struct bt_conn_auth_info_cb auto_info_cbs = { |
| .pairing_complete = pairing_complete_cb, |
| }; |
| |
| static void common_init(void) |
| { |
| int err; |
| |
| err = bt_enable(NULL); |
| |
| if (err) { |
| FAIL("Bluetooth init failed: %d\n", err); |
| return; |
| } |
| printk("Bluetooth initialized\n"); |
| |
| bt_conn_cb_register(&conn_cbs); |
| bt_conn_auth_info_cb_register(&auto_info_cbs); |
| } |
| |
| static void create_per_adv_set(struct bt_le_ext_adv **adv) |
| { |
| int err; |
| |
| printk("Creating extended advertising set..."); |
| err = bt_le_ext_adv_create(BT_LE_EXT_ADV_NCONN, NULL, adv); |
| if (err) { |
| printk("Failed to create advertising set: %d\n", err); |
| return; |
| } |
| printk("done.\n"); |
| |
| printk("Setting periodic advertising parameters..."); |
| err = bt_le_per_adv_set_param(*adv, BT_LE_PER_ADV_DEFAULT); |
| if (err) { |
| printk("Failed to set periodic advertising parameters: %d\n", |
| err); |
| return; |
| } |
| printk("done.\n"); |
| } |
| |
| static void create_conn_adv_set(struct bt_le_ext_adv **adv) |
| { |
| int err; |
| |
| printk("Creating connectable extended advertising set..."); |
| err = bt_le_ext_adv_create(BT_LE_EXT_ADV_CONN, NULL, adv); |
| if (err) { |
| printk("Failed to create advertising set: %d\n", err); |
| return; |
| } |
| printk("done.\n"); |
| } |
| |
| static void start_ext_adv_set(struct bt_le_ext_adv *adv) |
| { |
| int err; |
| |
| printk("Starting Extended Advertising..."); |
| err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT); |
| if (err) { |
| printk("Failed to start extended advertising: %d\n", err); |
| return; |
| } |
| printk("done.\n"); |
| } |
| |
| static void start_per_adv_set(struct bt_le_ext_adv *adv) |
| { |
| int err; |
| |
| printk("Starting periodic advertising..."); |
| err = bt_le_per_adv_start(adv); |
| if (err) { |
| printk("Failed to start periodic advertising: %d\n", err); |
| return; |
| } |
| printk("done.\n"); |
| } |
| |
| #if defined(CONFIG_BT_PER_ADV) |
| static void set_per_adv_data(struct bt_le_ext_adv *adv) |
| { |
| int err; |
| const struct bt_data ad[] = { |
| BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, ARRAY_SIZE(mfg_data)), |
| BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, ARRAY_SIZE(mfg_data))}; |
| |
| printk("Setting Periodic Advertising Data..."); |
| err = bt_le_per_adv_set_data(adv, ad, ARRAY_SIZE(ad)); |
| if (err) { |
| printk("Failed to set periodic advertising data: %d\n", |
| err); |
| return; |
| } |
| printk("done.\n"); |
| } |
| #endif |
| |
| static void stop_ext_adv_set(struct bt_le_ext_adv *adv) |
| { |
| int err; |
| |
| printk("Stopping Extended Advertising..."); |
| err = bt_le_ext_adv_stop(adv); |
| if (err) { |
| printk("Failed to stop extended advertising: %d\n", |
| err); |
| return; |
| } |
| printk("done.\n"); |
| } |
| |
| static void stop_per_adv_set(struct bt_le_ext_adv *adv) |
| { |
| int err; |
| |
| printk("Stopping Periodic Advertising..."); |
| err = bt_le_per_adv_stop(adv); |
| if (err) { |
| printk("Failed to stop periodic advertising: %d\n", |
| err); |
| return; |
| } |
| printk("done.\n"); |
| } |
| |
| static void delete_adv_set(struct bt_le_ext_adv *adv) |
| { |
| int err; |
| |
| printk("Delete extended advertising set..."); |
| err = bt_le_ext_adv_delete(adv); |
| if (err) { |
| printk("Failed Delete extended advertising set: %d\n", err); |
| return; |
| } |
| printk("done.\n"); |
| } |
| |
| static void main_per_adv_advertiser(void) |
| { |
| struct bt_le_ext_adv *per_adv; |
| |
| common_init(); |
| |
| create_per_adv_set(&per_adv); |
| |
| start_per_adv_set(per_adv); |
| start_ext_adv_set(per_adv); |
| |
| /* Advertise for a bit */ |
| k_sleep(K_SECONDS(10)); |
| |
| stop_per_adv_set(per_adv); |
| stop_ext_adv_set(per_adv); |
| |
| delete_adv_set(per_adv); |
| per_adv = NULL; |
| |
| PASS("Periodic advertiser passed\n"); |
| } |
| |
| static void main_per_adv_conn_advertiser(void) |
| { |
| struct bt_le_ext_adv *conn_adv; |
| struct bt_le_ext_adv *per_adv; |
| |
| common_init(); |
| |
| create_per_adv_set(&per_adv); |
| create_conn_adv_set(&conn_adv); |
| |
| start_per_adv_set(per_adv); |
| start_ext_adv_set(per_adv); |
| start_ext_adv_set(conn_adv); |
| |
| WAIT_FOR_FLAG(flag_connected); |
| |
| /* Advertise for a bit */ |
| k_sleep(K_SECONDS(10)); |
| |
| stop_per_adv_set(per_adv); |
| stop_ext_adv_set(per_adv); |
| stop_ext_adv_set(conn_adv); |
| |
| delete_adv_set(per_adv); |
| per_adv = NULL; |
| delete_adv_set(conn_adv); |
| conn_adv = NULL; |
| |
| PASS("Periodic advertiser passed\n"); |
| } |
| |
| static void main_per_adv_conn_privacy_advertiser(void) |
| { |
| struct bt_le_ext_adv *conn_adv; |
| struct bt_le_ext_adv *per_adv; |
| |
| common_init(); |
| |
| create_conn_adv_set(&conn_adv); |
| |
| start_ext_adv_set(conn_adv); |
| |
| WAIT_FOR_FLAG(flag_connected); |
| WAIT_FOR_FLAG(flag_bonded); |
| |
| /* Start periodic advertising after bonding so that the scanner gets |
| * the resolved address |
| */ |
| create_per_adv_set(&per_adv); |
| start_per_adv_set(per_adv); |
| start_ext_adv_set(per_adv); |
| |
| /* Advertise for a bit */ |
| k_sleep(K_SECONDS(10)); |
| |
| stop_per_adv_set(per_adv); |
| stop_ext_adv_set(per_adv); |
| stop_ext_adv_set(conn_adv); |
| |
| delete_adv_set(per_adv); |
| per_adv = NULL; |
| delete_adv_set(conn_adv); |
| conn_adv = NULL; |
| |
| PASS("Periodic advertiser passed\n"); |
| } |
| |
| static void main_per_adv_long_data_advertiser(void) |
| { |
| #if defined(CONFIG_BT_PER_ADV) |
| struct bt_le_ext_adv *per_adv; |
| |
| common_init(); |
| |
| create_per_adv_set(&per_adv); |
| |
| set_per_adv_data(per_adv); |
| start_per_adv_set(per_adv); |
| start_ext_adv_set(per_adv); |
| |
| /* Advertise for a bit */ |
| k_sleep(K_SECONDS(10)); |
| |
| stop_per_adv_set(per_adv); |
| stop_ext_adv_set(per_adv); |
| |
| delete_adv_set(per_adv); |
| per_adv = NULL; |
| #endif |
| PASS("Periodic long data advertiser passed\n"); |
| } |
| |
| static const struct bst_test_instance per_adv_advertiser[] = { |
| { |
| .test_id = "per_adv_advertiser", |
| .test_descr = "Basic periodic advertising test. " |
| "Will just start periodic advertising.", |
| .test_post_init_f = test_init, |
| .test_tick_f = test_tick, |
| .test_main_f = main_per_adv_advertiser |
| }, |
| { |
| .test_id = "per_adv_conn_advertiser", |
| .test_descr = "Periodic advertising test with concurrent ACL " |
| "and PA sync.", |
| .test_post_init_f = test_init, |
| .test_tick_f = test_tick, |
| .test_main_f = main_per_adv_conn_advertiser |
| }, |
| { |
| .test_id = "per_adv_conn_privacy_advertiser", |
| .test_descr = "Periodic advertising test with concurrent ACL " |
| "with bonding and PA sync.", |
| .test_post_init_f = test_init, |
| .test_tick_f = test_tick, |
| .test_main_f = main_per_adv_conn_privacy_advertiser |
| }, |
| { |
| .test_id = "per_adv_long_data_advertiser", |
| .test_descr = "Periodic advertising test with a longer data length. " |
| "To test the syncers reassembly of large data packets", |
| .test_post_init_f = test_init, |
| .test_tick_f = test_tick, |
| .test_main_f = main_per_adv_long_data_advertiser |
| }, |
| BSTEST_END_MARKER |
| }; |
| |
| struct bst_test_list *test_per_adv_advertiser(struct bst_test_list *tests) |
| { |
| return bst_add_tests(tests, per_adv_advertiser); |
| } |