blob: b22d269bcdb51d7c94b1db42f42860d8e44484bd [file] [log] [blame]
/*
* 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);
}
}
}