| /* |
| * Copyright (c) 2019 Bose Corporation |
| * Copyright (c) 2020-2021 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include "bs_dynargs.h" |
| #include "bs_pc_backchannel.h" |
| #include <argparse.h> |
| #include <posix_native_task.h> |
| |
| #include "common.h" |
| |
| extern enum bst_result_t bst_result; |
| struct bt_conn *default_conn; |
| atomic_t flag_connected; |
| atomic_t flag_disconnected; |
| atomic_t flag_conn_updated; |
| volatile bt_security_t security_level; |
| |
| const struct bt_data ad[AD_SIZE] = { |
| BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)) |
| }; |
| |
| static void device_found(const struct bt_le_scan_recv_info *info, struct net_buf_simple *ad) |
| { |
| char addr_str[BT_ADDR_LE_STR_LEN]; |
| int err; |
| |
| if (default_conn) { |
| return; |
| } |
| |
| /* We're only interested in connectable events */ |
| if ((info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) == 0) { |
| return; |
| } |
| |
| bt_addr_le_to_str(info->addr, addr_str, sizeof(addr_str)); |
| printk("Device found: %s (RSSI %d)\n", addr_str, info->rssi); |
| |
| /* connect only to devices in close proximity */ |
| if (info->rssi < -70) { |
| FAIL("RSSI too low"); |
| return; |
| } |
| |
| printk("Stopping scan\n"); |
| if (bt_le_scan_stop()) { |
| FAIL("Could not stop scan"); |
| return; |
| } |
| |
| err = bt_conn_le_create(info->addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, |
| &default_conn); |
| if (err) { |
| FAIL("Could not connect to peer: %d", err); |
| } |
| } |
| |
| struct bt_le_scan_cb common_scan_cb = { |
| .recv = device_found, |
| }; |
| |
| static void connected(struct bt_conn *conn, uint8_t err) |
| { |
| char addr[BT_ADDR_LE_STR_LEN]; |
| |
| (void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); |
| |
| if (default_conn == NULL) { |
| default_conn = bt_conn_ref(conn); |
| } |
| |
| if (err != 0) { |
| bt_conn_unref(default_conn); |
| default_conn = NULL; |
| |
| FAIL("Failed to connect to %s (0x%02x)\n", addr, err); |
| return; |
| } |
| |
| printk("Connected to %s (%p)\n", addr, conn); |
| SET_FLAG(flag_connected); |
| } |
| |
| void disconnected(struct bt_conn *conn, uint8_t reason) |
| { |
| char addr[BT_ADDR_LE_STR_LEN]; |
| |
| if (conn != default_conn) { |
| return; |
| } |
| |
| bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); |
| |
| printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); |
| |
| bt_conn_unref(default_conn); |
| default_conn = NULL; |
| UNSET_FLAG(flag_connected); |
| UNSET_FLAG(flag_conn_updated); |
| SET_FLAG(flag_disconnected); |
| |
| security_level = BT_SECURITY_L1; |
| } |
| |
| static void conn_param_updated_cb(struct bt_conn *conn, uint16_t interval, uint16_t latency, |
| uint16_t timeout) |
| { |
| printk("Connection parameter updated: %p 0x%04X (%u us), 0x%04X, 0x%04X\n", conn, interval, |
| BT_CONN_INTERVAL_TO_US(interval), latency, timeout); |
| |
| SET_FLAG(flag_conn_updated); |
| } |
| |
| static void security_changed_cb(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) |
| { |
| printk("Security changed: %p level %d err %d\n", conn, level, err); |
| |
| if (err == BT_SECURITY_ERR_SUCCESS) { |
| security_level = level; |
| } |
| } |
| |
| BT_CONN_CB_DEFINE(conn_callbacks) = { |
| .connected = connected, |
| .disconnected = disconnected, |
| .le_param_updated = conn_param_updated_cb, |
| .security_changed = security_changed_cb, |
| }; |
| |
| void test_tick(bs_time_t HW_device_time) |
| { |
| if (bst_result != Passed) { |
| FAIL("test failed (not passed after %i seconds)\n", WAIT_SECONDS); |
| } |
| } |
| |
| void test_init(void) |
| { |
| bst_ticker_set_next_tick_absolute(WAIT_TIME); |
| bst_result = In_progress; |
| } |
| |
| #define SYNC_MSG_SIZE 1 |
| static int32_t dev_cnt; |
| static uint backchannel_nums[255]; |
| static uint chan_cnt; |
| |
| static void register_more_cmd_args(void) |
| { |
| static bs_args_struct_t args_struct_toadd[] = { |
| { |
| .option = "D", |
| .name = "number_devices", |
| .type = 'i', |
| .dest = (void *)&dev_cnt, |
| .descript = "Number of devices which will connect in this phy", |
| .is_mandatory = true, |
| }, |
| ARG_TABLE_ENDMARKER, |
| }; |
| |
| bs_add_extra_dynargs(args_struct_toadd); |
| } |
| NATIVE_TASK(register_more_cmd_args, PRE_BOOT_1, 100); |
| |
| uint16_t get_dev_cnt(void) |
| { |
| return (uint16_t)dev_cnt; |
| } |
| |
| /** |
| * @brief Get the channel id based on remote device ID |
| * |
| * The is effectively a very simple hashing function to generate unique channel IDs from device IDs |
| * |
| * @param dev 16-bit device ID |
| * |
| * @return uint 32-bit channel ID |
| */ |
| static uint get_chan_num(uint16_t dev) |
| { |
| uint16_t self = (uint16_t)bsim_args_get_global_device_nbr(); |
| uint channel_id; |
| |
| if (self < dev) { |
| channel_id = (dev << 16) | self; |
| } else { |
| channel_id = (self << 16) | dev; |
| } |
| |
| return channel_id; |
| } |
| |
| /** |
| * @brief Set up the backchannels between each pair of device |
| * |
| * Each pair of devices will get a unique channel |
| */ |
| static void setup_backchannels(void) |
| { |
| __ASSERT_NO_MSG(dev_cnt > 0 && dev_cnt < ARRAY_SIZE(backchannel_nums)); |
| const uint self = bsim_args_get_global_device_nbr(); |
| uint device_numbers[dev_cnt]; |
| uint *channels; |
| |
| for (int32_t i = 0; i < dev_cnt; i++) { |
| if (i != self) { /* skip ourselves*/ |
| backchannel_nums[chan_cnt] = get_chan_num((uint16_t)i); |
| device_numbers[chan_cnt++] = i; |
| } |
| } |
| |
| channels = bs_open_back_channel(self, device_numbers, backchannel_nums, chan_cnt); |
| __ASSERT_NO_MSG(channels != NULL); |
| } |
| NATIVE_TASK(setup_backchannels, PRE_BOOT_3, 100); |
| |
| static uint get_chan_id_from_chan_num(uint chan_num) |
| { |
| for (uint i = 0; i < ARRAY_SIZE(backchannel_nums); i++) { |
| if (backchannel_nums[i] == chan_num) { |
| return i; |
| } |
| } |
| |
| return 0; |
| } |
| |
| void backchannel_sync_send(uint dev) |
| { |
| const uint chan_id = get_chan_id_from_chan_num(get_chan_num((uint16_t)dev)); |
| uint8_t sync_msg[SYNC_MSG_SIZE] = {0}; |
| |
| printk("Sending sync to %u\n", chan_id); |
| bs_bc_send_msg(chan_id, sync_msg, ARRAY_SIZE(sync_msg)); |
| } |
| |
| void backchannel_sync_send_all(void) |
| { |
| for (int32_t i = 0; i < dev_cnt; i++) { |
| const uint self = bsim_args_get_global_device_nbr(); |
| |
| if (i != self) { /* skip ourselves*/ |
| backchannel_sync_send(i); |
| } |
| } |
| } |
| |
| void backchannel_sync_wait(uint dev) |
| { |
| const uint chan_id = get_chan_id_from_chan_num(get_chan_num((uint16_t)dev)); |
| |
| printk("Waiting for sync to %u\n", chan_id); |
| |
| while (true) { |
| if (bs_bc_is_msg_received(chan_id) > 0) { |
| uint8_t sync_msg[SYNC_MSG_SIZE]; |
| |
| bs_bc_receive_msg(chan_id, sync_msg, ARRAY_SIZE(sync_msg)); |
| /* We don't really care about the content of the message */ |
| break; |
| } |
| |
| k_sleep(K_MSEC(1)); |
| } |
| } |
| |
| void backchannel_sync_wait_all(void) |
| { |
| for (int32_t i = 0; i < dev_cnt; i++) { |
| const uint self = bsim_args_get_global_device_nbr(); |
| |
| if (i != self) { /* skip ourselves*/ |
| backchannel_sync_wait(i); |
| } |
| } |
| } |
| |
| void backchannel_sync_wait_any(void) |
| { |
| while (true) { |
| for (int32_t i = 0; i < dev_cnt; i++) { |
| const uint self = bsim_args_get_global_device_nbr(); |
| |
| if (i != self) { /* skip ourselves*/ |
| const uint chan_id = |
| get_chan_id_from_chan_num(get_chan_num((uint16_t)i)); |
| |
| if (bs_bc_is_msg_received(chan_id) > 0) { |
| uint8_t sync_msg[SYNC_MSG_SIZE]; |
| |
| bs_bc_receive_msg(chan_id, sync_msg, ARRAY_SIZE(sync_msg)); |
| /* We don't really care about the content of the message */ |
| |
| return; |
| } |
| } |
| } |
| |
| k_sleep(K_MSEC(100)); |
| } |
| } |
| |
| void backchannel_sync_clear(uint dev) |
| { |
| const uint chan_id = get_chan_id_from_chan_num(get_chan_num((uint16_t)dev)); |
| |
| while (bs_bc_is_msg_received(chan_id)) { |
| uint8_t sync_msg[SYNC_MSG_SIZE]; |
| |
| bs_bc_receive_msg(chan_id, sync_msg, ARRAY_SIZE(sync_msg)); |
| /* We don't really care about the content of the message */ |
| } |
| } |
| |
| void backchannel_sync_clear_all(void) |
| { |
| for (int32_t i = 0; i < dev_cnt; i++) { |
| const uint self = bsim_args_get_global_device_nbr(); |
| |
| if (i != self) { /* skip ourselves*/ |
| backchannel_sync_clear(i); |
| } |
| } |
| } |