Ranging CS data from multiple connections

Hi,

I succeeded in implementing Channel sounding for multiple devices (based on previous samples). But now there is a little difference in how the data gets collected (buffer) and how the range estimation gets computed (somewhere outside the files).

As you can see, the connections and scanning works already fine when i re-implement my code for reconnecting sequentially with the devices. But the data doesn't get updated correctly:

I think i should change some things in data collected / range data collect (the first 6 functions, which are new from the new sample)

Kind regards,

Nick De Leenheer

/*
 * Copyright (c) 2024 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

/** @file
 *  @brief Channel Sounding Initiator with Ranging Requestor sample
 */

#include <math.h>
#include <zephyr/kernel.h>
#include <zephyr/types.h>
#include <zephyr/sys/reboot.h>
#include <zephyr/bluetooth/cs.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/conn.h>
#include <bluetooth/scan.h>
#include <bluetooth/services/ras.h>
#include <bluetooth/gatt_dm.h>
#include <bluetooth/cs_de.h>

#include <dk_buttons_and_leds.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app_main, LOG_LEVEL_INF);

#define CON_STATUS_LED DK_LED1

#define CS_CONFIG_ID	       0
#define NUM_MODE_0_STEPS       3
#define PROCEDURE_COUNTER_NONE (-1)
#define DE_SLIDING_WINDOW_SIZE (10)
#define MAX_AP		       (CONFIG_BT_RAS_MAX_ANTENNA_PATHS)

// #define LOCAL_PROCEDURE_MEM                                                                        \
// 	((BT_RAS_MAX_STEPS_PER_PROCEDURE * sizeof(struct bt_le_cs_subevent_step)) +                \
// 	 (BT_RAS_MAX_STEPS_PER_PROCEDURE * BT_RAS_MAX_STEP_DATA_LEN))

#define LOCAL_PROCEDURE_MEM 6000

static K_SEM_DEFINE(sem_remote_capabilities_obtained, 0, 1);
static K_SEM_DEFINE(sem_config_created, 0, 1);
static K_SEM_DEFINE(sem_cs_security_enabled, 0, 1);
static K_SEM_DEFINE(sem_connected, 0, 1);
static K_SEM_DEFINE(sem_discovery_done, 0, 1);
static K_SEM_DEFINE(sem_mtu_exchange_done, 0, 1);
static K_SEM_DEFINE(sem_security, 0, 1);
static K_SEM_DEFINE(sem_local_steps, 1, 1);
static K_SEM_DEFINE(sem_disconnected, 0, 1);
static K_SEM_DEFINE(sem_ranging_done, 0, 1);
static K_SEM_DEFINE(sem_nrf_noise, 0, 1);

static K_MUTEX_DEFINE(distance_estimate_buffer_mutex);

static struct bt_conn *connection;
NET_BUF_SIMPLE_DEFINE_STATIC(latest_local_steps, LOCAL_PROCEDURE_MEM);
NET_BUF_SIMPLE_DEFINE_STATIC(latest_peer_steps, BT_RAS_PROCEDURE_MEM);
static int32_t most_recent_local_ranging_counter = PROCEDURE_COUNTER_NONE;
static int32_t dropped_ranging_counter = PROCEDURE_COUNTER_NONE;

/* For scanning & connecting with multiple devices */
#define MAX_DEVICES 3
static bt_addr_le_t addresses[MAX_DEVICES];
static int num_found = 0;
static bool scanning_for_initial_devices = true;
static bool connection_in_progress = false;
static struct bt_conn *connection = NULL;
static struct bt_conn *connections[MAX_DEVICES];

/* For parsing the name of devices */
#define NAME_LEN 30
char reflector_names[MAX_DEVICES][NAME_LEN];
char reflector_name[NAME_LEN] = "(onbekend)";

/* For the ranging process */
#define RANGING_ROUNDS 1
static bool ranging_done = false;

/* For buffering Distance estimations */
static uint8_t buffer_index;
static uint8_t buffer_num_valid;
static cs_de_dist_estimates_t distance_estimate_buffer[MAX_AP][DE_SLIDING_WINDOW_SIZE];

static void store_distance_estimates(cs_de_report_t *p_report)
{
	int lock_state = k_mutex_lock(&distance_estimate_buffer_mutex, K_FOREVER);

	__ASSERT_NO_MSG(lock_state == 0);

	for (uint8_t ap = 0; ap < p_report->n_ap; ap++) {
		memcpy(&distance_estimate_buffer[ap][buffer_index],
		       &p_report->distance_estimates[ap], sizeof(cs_de_dist_estimates_t));
	}

	buffer_index = (buffer_index + 1) % DE_SLIDING_WINDOW_SIZE;

	if (buffer_num_valid < DE_SLIDING_WINDOW_SIZE) {
		buffer_num_valid++;
	}

	k_mutex_unlock(&distance_estimate_buffer_mutex);
}

static cs_de_dist_estimates_t get_distance(uint8_t ap)
{
	cs_de_dist_estimates_t averaged_result = {};
	uint8_t num_ifft = 0;
	uint8_t num_phase_slope = 0;
	uint8_t num_rtt = 0;

	int lock_state = k_mutex_lock(&distance_estimate_buffer_mutex, K_FOREVER);

	__ASSERT_NO_MSG(lock_state == 0);

	for (uint8_t i = 0; i < buffer_num_valid; i++) {
		if (isfinite(distance_estimate_buffer[ap][i].ifft)) {
			num_ifft++;
			averaged_result.ifft += distance_estimate_buffer[ap][i].ifft;
		}
		if (isfinite(distance_estimate_buffer[ap][i].phase_slope)) {
			num_phase_slope++;
			averaged_result.phase_slope += distance_estimate_buffer[ap][i].phase_slope;
		}
		if (isfinite(distance_estimate_buffer[ap][i].rtt)) {
			num_rtt++;
			averaged_result.rtt += distance_estimate_buffer[ap][i].rtt;
		}
	}

	k_mutex_unlock(&distance_estimate_buffer_mutex);

	if (num_ifft) {
		averaged_result.ifft /= num_ifft;
	}

	if (num_phase_slope) {
		averaged_result.phase_slope /= num_phase_slope;
	}

	if (num_rtt) {
		averaged_result.rtt /= num_rtt;
	}

	return averaged_result;
}

static void ranging_data_get_complete_cb(struct bt_conn *conn, uint16_t ranging_counter, int err)
{
	ARG_UNUSED(conn);

	if (err) {
		LOG_ERR("Error when getting ranging data with ranging counter %d (err %d)",
			ranging_counter, err);
		return;
	}

	// LOG_DBG("Ranging data get completed for ranging counter %d", ranging_counter);

	/* This struct is static to avoid putting it on the stack (it's very large) */
	static cs_de_report_t cs_de_report;

	memset(&cs_de_report, 0, sizeof(cs_de_report));

	cs_de_populate_report(&latest_local_steps, &latest_peer_steps, BT_CONN_LE_CS_ROLE_INITIATOR,
			      &cs_de_report);

	net_buf_simple_reset(&latest_local_steps);
	net_buf_simple_reset(&latest_peer_steps);
	k_sem_give(&sem_local_steps);

	cs_de_quality_t quality = cs_de_calc(&cs_de_report);

	if (quality == CS_DE_QUALITY_OK) {
		for (uint8_t ap = 0; ap < cs_de_report.n_ap; ap++) {
			if (cs_de_report.tone_quality[ap] == CS_DE_TONE_QUALITY_OK) {
				store_distance_estimates(&cs_de_report);
			}
		}
	}
}

static void subevent_result_cb(struct bt_conn *conn, struct bt_conn_le_cs_subevent_result *result)
{
	if (dropped_ranging_counter == result->header.procedure_counter) {
		return;
	}

	if (most_recent_local_ranging_counter
		!= bt_ras_rreq_get_ranging_counter(result->header.procedure_counter)) {
		int sem_state = k_sem_take(&sem_local_steps, K_NO_WAIT);

		if (sem_state < 0) {
			dropped_ranging_counter = result->header.procedure_counter;
			// LOG_DBG("Dropped subevent results due to unfinished ranging data request.");
			return;
		}

		most_recent_local_ranging_counter =
			bt_ras_rreq_get_ranging_counter(result->header.procedure_counter);
	}

	if (result->header.subevent_done_status == BT_CONN_LE_CS_SUBEVENT_ABORTED) {
		/* The steps from this subevent will not be used. */
	} else if (result->step_data_buf) {
		if (result->step_data_buf->len <= net_buf_simple_tailroom(&latest_local_steps)) {
			uint16_t len = result->step_data_buf->len;
			uint8_t *step_data = net_buf_simple_pull_mem(result->step_data_buf, len);

			net_buf_simple_add_mem(&latest_local_steps, step_data, len);
		} else {
			LOG_ERR("Not enough memory to store step data. (%d > %d)",
				latest_local_steps.len + result->step_data_buf->len,
				latest_local_steps.size);
			net_buf_simple_reset(&latest_local_steps);
			dropped_ranging_counter = result->header.procedure_counter;
			return;
		}
	}

	dropped_ranging_counter = PROCEDURE_COUNTER_NONE;

	if (result->header.procedure_done_status == BT_CONN_LE_CS_PROCEDURE_COMPLETE) {
		most_recent_local_ranging_counter =
			bt_ras_rreq_get_ranging_counter(result->header.procedure_counter);
	} else if (result->header.procedure_done_status == BT_CONN_LE_CS_PROCEDURE_ABORTED) {
		LOG_WRN("Procedure %u aborted", result->header.procedure_counter);
		net_buf_simple_reset(&latest_local_steps);
		k_sem_give(&sem_local_steps);
	}
}

static void ranging_data_ready_cb(struct bt_conn *conn, uint16_t ranging_counter)
{
	LOG_DBG("Ranging data ready %i", ranging_counter);

	if (ranging_counter == most_recent_local_ranging_counter) {
		int err = bt_ras_rreq_cp_get_ranging_data(conn, &latest_peer_steps,
							  ranging_counter,
							  ranging_data_get_complete_cb);
		if (err) {
			LOG_ERR("Get ranging data failed (err %d)", err);
			net_buf_simple_reset(&latest_local_steps);
			net_buf_simple_reset(&latest_peer_steps);
			k_sem_give(&sem_local_steps);
		}
	}
}

static void ranging_data_overwritten_cb(struct bt_conn *conn, uint16_t ranging_counter)
{
	// LOG_INF("Ranging data overwritten %i", ranging_counter);
}

static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
			    struct bt_gatt_exchange_params *params)
{
	if (err) {
		LOG_ERR("MTU exchange failed (err %d)", err);
		return;
	}

	// LOG_INF("MTU exchange success (%u)", bt_gatt_get_mtu(conn));
	k_sem_give(&sem_mtu_exchange_done);
}

static void discovery_completed_cb(struct bt_gatt_dm *dm, void *context)
{
	int err;

	// LOG_INF("The discovery procedure succeeded");

	struct bt_conn *conn = bt_gatt_dm_conn_get(dm);

	bt_gatt_dm_data_print(dm);

	err = bt_ras_rreq_alloc_and_assign_handles(dm, conn);
	if (err) {
		LOG_ERR("RAS RREQ alloc init failed (err %d)", err);
	}

	err = bt_gatt_dm_data_release(dm);
	if (err) {
		LOG_ERR("Could not release the discovery data (err %d)", err);
	}

	k_sem_give(&sem_discovery_done);
}

static void discovery_service_not_found_cb(struct bt_conn *conn, void *context)
{
	// LOG_INF("The service could not be found during the discovery, disconnecting");
	bt_conn_disconnect(connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
}

static void discovery_error_found_cb(struct bt_conn *conn, int err, void *context)
{
	// LOG_INF("The discovery procedure failed (err %d)", err);
	bt_conn_disconnect(connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
}

static struct bt_gatt_dm_cb discovery_cb = {
	.completed = discovery_completed_cb,
	.service_not_found = discovery_service_not_found_cb,
	.error_found = discovery_error_found_cb,
};

static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	if (err) {
		LOG_ERR("Security failed: %s level %u err %d %s", addr, level, err,
			bt_security_err_to_str(err));
		return;
	}

	// LOG_INF("Security changed: %s level %u", addr, level);
	k_sem_give(&sem_security);
}

static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
{
	/* Ignore peer parameter preferences. */
	return false;
}

static void connected_cb(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));
	// LOG_INF("Connected to %s", addr);

    if (err) {
        LOG_ERR("Connection failed (err 0x%02x)", err);
        bt_conn_unref(conn);
		k_sem_give(&sem_connected);	// NEEDED to get to the error instead of "W: conn failed to establish. RF noise?"
        return;
    }

    // When not in the scanning process we give a semaphore for being connected
    if (!scanning_for_initial_devices) {
        for (int i = 0; i < MAX_DEVICES; i++) {
            if (connections[i] == NULL) {
                connections[i] = bt_conn_ref(conn);
                break;
            }
        }
        dk_set_led_on(CON_STATUS_LED);
        k_sem_give(&sem_connected);
    }

    // When still in the scanning process we disconnect
    if (scanning_for_initial_devices) {
        k_sleep(K_MSEC(200));
        bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
		connection_in_progress = false;
    }
}

static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
{
	char addr[BT_ADDR_LE_STR_LEN];
	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
	// LOG_INF("Disconnected from %s, reason: reason 0x%02X", addr, reason);

	if (reason == 0x3E){
		// LOG_INF("nRF Noise detected");
		k_sem_give(&sem_nrf_noise);
	}

    bt_conn_unref(conn);
    connection = NULL;
    dk_set_led_off(CON_STATUS_LED);

    // Handle disconnection during initial device scan
    if (scanning_for_initial_devices) {
		// LOG_INF("disconnected during scanning phase");
        k_sem_give(&sem_disconnected);
        connection_in_progress = false;

		// When more devices need to get detected we continue scanning
        if (num_found < MAX_DEVICES) {
            bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);

		// When all devices has been found we stop scanning
        } else {
            scanning_for_initial_devices = false;
        }
    } 
	
	// Handle proper disconnection after ranging is done
	if(ranging_done){
		// LOG_INF("ranging is done");
		k_sem_give(&sem_ranging_done);
	}
}

static void remote_capabilities_cb(struct bt_conn *conn,
				   uint8_t status,
				   struct bt_conn_le_cs_capabilities *params)
{
	ARG_UNUSED(conn);
	ARG_UNUSED(params);

	if (status == BT_HCI_ERR_SUCCESS) {
		// LOG_INF("CS capability exchange completed.");
		k_sem_give(&sem_remote_capabilities_obtained);
	} else {
		LOG_WRN("CS capability exchange failed. (HCI status 0x%02x)", status);
	}
}

static void config_create_cb(struct bt_conn *conn,
			     uint8_t status,
			     struct bt_conn_le_cs_config *config)
{
	ARG_UNUSED(conn);

	if (status == BT_HCI_ERR_SUCCESS) {
		// LOG_INF("CS config creation complete. ID: %d", config->id);
		k_sem_give(&sem_config_created);
	} else {
		LOG_WRN("CS config creation failed. (HCI status 0x%02x)", status);
	}
}

static void security_enable_cb(struct bt_conn *conn, uint8_t status)
{
	ARG_UNUSED(conn);

	if (status == BT_HCI_ERR_SUCCESS) {
		// LOG_INF("CS security enabled.");
		k_sem_give(&sem_cs_security_enabled);
	} else {
		LOG_WRN("CS security enable failed. (HCI status 0x%02x)", status);
	}
}

static void procedure_enable_cb(struct bt_conn *conn,
				uint8_t status,
				struct bt_conn_le_cs_procedure_enable_complete *params)
{
	ARG_UNUSED(conn);

	if (status == BT_HCI_ERR_SUCCESS) {
		if (params->state == 1) {
			// LOG_INF("CS procedures enabled:\n"
			// 	" - config ID: %u\n"
			// 	" - antenna configuration index: %u\n"
			// 	" - TX power: %d dbm\n"
			// 	" - subevent length: %u us\n"
			// 	" - subevents per event: %u\n"
			// 	" - subevent interval: %u\n"
			// 	" - event interval: %u\n"
			// 	" - procedure interval: %u\n"
			// 	" - procedure count: %u\n"
			// 	" - maximum procedure length: %u",
			// 	params->config_id, params->tone_antenna_config_selection,
			// 	params->selected_tx_power, params->subevent_len,
			// 	params->subevents_per_event, params->subevent_interval,
			// 	params->event_interval, params->procedure_interval,
			// 	params->procedure_count, params->max_procedure_len);
		} else {
			// LOG_INF("CS procedures disabled.");
		}
	} else {
		LOG_WRN("CS procedures enable failed. (HCI status 0x%02x)", status);
	}
}



static bool ad_parse_cb(struct bt_data *data, void *user_data)
{
    char *name = user_data;

    if (data->type == BT_DATA_NAME_COMPLETE || data->type == BT_DATA_NAME_SHORTENED) {
        size_t len = MIN(data->data_len, NAME_LEN - 1);
        memcpy(name, data->data, len);
        name[len] = '\0';
        return false;
    }

    return true;
}

static void scan_filter_match(struct bt_scan_device_info *device_info,
                              struct bt_scan_filter_match *filter_match, bool connectable)
{
	// Not scanning for devices OR already connected to a device
    if (!scanning_for_initial_devices || connection_in_progress) {
        return;
    }

    // Device has already been detected
    for (int i = 0; i < num_found; i++) {
        if (!bt_addr_le_cmp(&addresses[i], device_info->recv_info->addr)) {
            return;
        }
    }

	// End scanning when ALL devices detected
    if (num_found >= MAX_DEVICES) {
        return;
    }

    // Retreiving data from the scanned device
    struct net_buf_simple ad_copy = *device_info->adv_data;
    snprintf(reflector_names[num_found], NAME_LEN, "(onbekend)");
    bt_data_parse(&ad_copy, ad_parse_cb, reflector_names[num_found]);

    bt_addr_le_copy(&addresses[num_found], device_info->recv_info->addr);


    bt_scan_stop();
    k_msleep(50);

	// Setup a quick connection with the device
    struct bt_conn *conn = NULL;
    const struct bt_conn_le_create_param *create_param = BT_CONN_LE_CREATE_PARAM(BT_CONN_LE_OPT_NONE, 0x0060, 0x0030);
    const struct bt_le_conn_param *conn_param = BT_LE_CONN_PARAM_DEFAULT;
	connection_in_progress = true;

    int err = bt_conn_le_create(&addresses[num_found], create_param, conn_param, &conn);
    if (err) {
        connection_in_progress = false;
        return;
    }

	// LOG the information about the device
    char addr_str[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(&addresses[num_found], addr_str, sizeof(addr_str));

    LOG_INF("Device %d/%d verbonden: \"%s\" (%s)", num_found + 1, MAX_DEVICES, reflector_names[num_found], addr_str);

    num_found++;
}

static void scan_connecting_error(struct bt_scan_device_info *device_info)
{
	int err;

	// LOG_INF("Connecting failed, restarting scanning");

	err = bt_scan_start(BT_SCAN_TYPE_SCAN_PASSIVE);
	if (err) {
		LOG_ERR("Failed to restart scanning (err %i)", err);
		return;
	}
}

static void scan_connecting(struct bt_scan_device_info *device_info, struct bt_conn *conn)
{
	// LOG_INF("Connecting");
}

BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, scan_connecting_error, scan_connecting);

static int scan_init(void)
{
	int err;

	struct bt_scan_init_param param = {
		.scan_param = NULL, 
		.conn_param = BT_LE_CONN_PARAM_DEFAULT,
		.connect_if_match = 0};

	bt_scan_init(&param);
	bt_scan_cb_register(&scan_cb);

	// /** Filter for names. */
	// BT_SCAN_FILTER_TYPE_NAME,

	// /** Filter for short names. */
	// BT_SCAN_FILTER_TYPE_SHORT_NAME,

	// /** Filter for addresses. */
	// BT_SCAN_FILTER_TYPE_ADDR,

	// /** Filter for UUIDs. */
	// BT_SCAN_FILTER_TYPE_UUID,

	// /** Filter for appearances. */
	// BT_SCAN_FILTER_TYPE_APPEARANCE,

	// /** Filter for manufacturer data. */
	// BT_SCAN_FILTER_TYPE_MANUFACTURER_DATA,

	// err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_NAME, TARGET_NAME);
	// if (err) {
	// 	return err;
	// }

	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_RANGING_SERVICE);
	if (err) {
		return err;
	}

	err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, false);	//false: 1 match required | true: ALL matches required
	if (err) {													
		return err;
	}

	return 0;
}

BT_CONN_CB_DEFINE(conn_cb) = {
	.connected = connected_cb,
	.disconnected = disconnected_cb,
	.le_param_req = le_param_req,
	.security_changed = security_changed,
	.le_cs_read_remote_capabilities_complete = remote_capabilities_cb,
	.le_cs_config_complete = config_create_cb,
	.le_cs_security_enable_complete = security_enable_cb,
	.le_cs_procedure_enable_complete = procedure_enable_cb,
	.le_cs_subevent_data_available = subevent_result_cb,
};

int main(void)
{
	int err;

	dk_leds_init();

	err = bt_enable(NULL);
	if (err) {
		LOG_ERR("Bluetooth init failed (err %d)", err);
		return 0;
	}

	err = scan_init();
	if (err) {
		LOG_ERR("Scan init failed (err %d)", err);
		return 0;
	}

	err = bt_scan_start(BT_SCAN_TYPE_SCAN_PASSIVE);
	if (err) {
		LOG_ERR("Scanning failed to start (err %i)", err);
		return 0;
	}

	for (int i = 0; i < MAX_DEVICES; i++) {
		k_sem_take(&sem_disconnected, K_FOREVER);
	}	

	LOG_INF("All devices detected => stop scanning");


	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	/* Reconnect one by one with previously detected devices */
	while (true){
		for (int i = 0; i < MAX_DEVICES; i++) {

			const bt_addr_le_t *peer_addr = &addresses[i];
			char addr_str[BT_ADDR_LE_STR_LEN];
			bt_addr_le_to_str(peer_addr, addr_str, sizeof(addr_str));

			const char *reflector_name = reflector_names[i];
			int device_nr = i+1;

			const struct bt_conn_le_create_param *create_param = BT_CONN_LE_CREATE_PARAM(BT_CONN_LE_OPT_NONE, 0x0060, 0x0030);
			const struct bt_le_conn_param *conn_param = BT_LE_CONN_PARAM_DEFAULT;

			if (connections[i]) {
				bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
				bt_conn_unref(connections[i]);
				connections[i] = NULL;
			}

			// LOG_INF("Connecting with device %s (%s)", reflector_name, addr_str);
			err = bt_conn_le_create(peer_addr, create_param, conn_param, &connections[i]);
			if (err) {
				LOG_ERR("Kon niet verbinden met %s (%s), foutcode: %d", reflector_name, addr_str, err);
				continue;
			}

			/* Check for connection Time out: connection failed */
			if (k_sem_take(&sem_connected, K_SECONDS(4)) != 0) {
				if (connections[i]) {
					bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
					bt_conn_unref(connections[i]);
					connections[i] = NULL;
				}
				continue; // Move on to the next device
			}

			/* Check for nrf Noise: connection succeeds, but disconnects right after  */
			if (k_sem_take(&sem_nrf_noise, K_MSEC(500)) == 0){
				// LOG_INF("Skipping device %d, going to the next device", device_nr);
				if (connections[i]) {
					bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
					connections[i] = NULL;
					k_sleep(K_SECONDS(1));
				}
				continue; // Move on to the next device
			}

			/* To establish a stable connection */
			k_sleep(K_MSEC(200));

			// Set Security
			err = bt_conn_set_security(connections[i], BT_SECURITY_L2);
			if (err) {
				LOG_ERR("Security failed for %s", reflector_name);
				continue;
			}
			k_sem_take(&sem_security, K_FOREVER);

			// MTU Exchange
			static struct bt_gatt_exchange_params mtu_exchange_params = {.func = mtu_exchange_cb};
			bt_gatt_exchange_mtu(connections[i], &mtu_exchange_params);
			k_sem_take(&sem_mtu_exchange_done, K_FOREVER);

			// GATT Discovery
			err = bt_gatt_dm_start(connections[i], BT_UUID_RANGING_SERVICE, &discovery_cb, NULL);
			if (err) {
				LOG_ERR("Discovery failed for %s", reflector_name);
				return 0;
			}
			k_sem_take(&sem_discovery_done, K_FOREVER);

			// // Default settings
			const struct bt_le_cs_set_default_settings_param default_settings = {
				.enable_initiator_role = true,
				.enable_reflector_role = false,
				.cs_sync_antenna_selection = BT_LE_CS_ANTENNA_SELECTION_OPT_REPETITIVE,
				.max_tx_power = BT_HCI_OP_LE_CS_MAX_MAX_TX_POWER,
			};
			err = bt_le_cs_set_default_settings(connections[i], &default_settings);
			if (err) {
				LOG_ERR("Failed to configure default CS settings for %s", reflector_name);
				return 0;
			}

			// Subscriptions
			err  = bt_ras_rreq_rd_overwritten_subscribe(connections[i], ranging_data_overwritten_cb);
			err |= bt_ras_rreq_rd_ready_subscribe(connections[i], ranging_data_ready_cb);
			err |= bt_ras_rreq_on_demand_rd_subscribe(connections[i]);
			err |= bt_ras_rreq_cp_subscribe(connections[i]);
			if (err) {
				LOG_ERR("Subscriptions failed for %s", reflector_name);
				continue;
			}

			// Capabilities
			err = bt_le_cs_read_remote_supported_capabilities(connections[i]);
			if (err) {
				LOG_ERR("Failed to exchange CS capabilities for %s", reflector_name);
				return 0;
			}
			k_sem_take(&sem_remote_capabilities_obtained, K_FOREVER);

			// CS Config
			struct bt_le_cs_create_config_params config_params = {
				.id = CS_CONFIG_ID,
				.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_2,
				.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_1,
				.min_main_mode_steps = 2,
				.max_main_mode_steps = 5,
				.main_mode_repetition = 0,
				.mode_0_steps = NUM_MODE_0_STEPS,
				.role = BT_CONN_LE_CS_ROLE_INITIATOR,
				.rtt_type = BT_CONN_LE_CS_RTT_TYPE_AA_ONLY,
				.cs_sync_phy = BT_CONN_LE_CS_SYNC_1M_PHY,
				.channel_map_repetition = 3,
				.channel_selection_type = BT_CONN_LE_CS_CHSEL_TYPE_3B,
				.ch3c_shape = BT_CONN_LE_CS_CH3C_SHAPE_HAT,
				.ch3c_jump = 2,
			};

			bt_le_cs_set_valid_chmap_bits(config_params.channel_map);
			err = bt_le_cs_create_config(connections[i], &config_params,
							BT_LE_CS_CREATE_CONFIG_CONTEXT_LOCAL_AND_REMOTE);
			if (err) {
				LOG_ERR("Failed to create CS config (err %d)", err);
				return 0;
			}
			k_sem_take(&sem_config_created, K_FOREVER);

			// Enable CS security
			err = bt_le_cs_security_enable(connections[i]);
			if (err) {
				LOG_ERR("Failed to start CS Security for %s", reflector_name);
				return 0;
			}
			k_sem_take(&sem_cs_security_enabled, K_FOREVER);

			// Procedure params
			const struct bt_le_cs_set_procedure_parameters_param procedure_params = {
				.config_id = CS_CONFIG_ID,
				.max_procedure_len = 1000,
				.min_procedure_interval = 10,
				.max_procedure_interval = 10,
				.max_procedure_count = 0,
				.min_subevent_len = 60000,
				.max_subevent_len = 60000,
				.tone_antenna_config_selection = BT_LE_CS_TONE_ANTENNA_CONFIGURATION_A1_B1,
				.phy = BT_LE_CS_PROCEDURE_PHY_1M,
				.tx_power_delta = 0x80,
				.preferred_peer_antenna = BT_LE_CS_PROCEDURE_PREFERRED_PEER_ANTENNA_1,
				.snr_control_initiator = BT_LE_CS_SNR_CONTROL_NOT_USED,
				.snr_control_reflector = BT_LE_CS_SNR_CONTROL_NOT_USED,
			};
			err = bt_le_cs_set_procedure_parameters(connections[i], &procedure_params);
			if (err) {
				LOG_ERR("Failed to set procedure parameters for %s", reflector_name);
				return 0;
			}

			// Enable procedure
			struct bt_le_cs_procedure_enable_param params = {
				.config_id = CS_CONFIG_ID,
				.enable = 1,
			};
			err = bt_le_cs_procedure_enable(connections[i], &params);
			if (err) {
				LOG_ERR("Failed to enable CS procedures for %s", reflector_name);
				return 0;
			}

			////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
			/* Ranging estimates */

			LOG_INF("Device %d: %s", device_nr, reflector_name);

			for (int round = 0; round < RANGING_ROUNDS; round++) {
				k_sleep(K_MSEC(5000));

				if (buffer_num_valid != 0) {
					for (uint8_t ap = 0; ap < MAX_AP; ap++) {
						cs_de_dist_estimates_t distance_on_ap = get_distance(ap);

						LOG_INF("ifft: %f, phase_slope: %f, rtt: %f", 
							(double)distance_on_ap.ifft,
							(double)distance_on_ap.phase_slope,
							(double)distance_on_ap.rtt);
					}
				}
			}

			/* for stable disconnection */
			ranging_done = true;
			bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
			connections[i] = NULL; 

			k_sem_take(&sem_ranging_done, K_FOREVER);
			
			ranging_done = false;
		}
	}
}

Parents
  • So, I have come to solutions myself, but there is only 1 problem left for me:

    PROBLEM: 

    We get this working chronology now, and i already understand all of the functions quite good... But for multiple connections handled sequentially, there is a problem of the counters and that the buffer doesn't get updated correctly. I want to know how to handle this correctly and how to solve this problem.

    The problem is thus, that we don't get in this data_complete function, where we collect the step data from the PEER and LOCAL device to create the cs_de_report and to eventually get our new DISTANCE ESTIMATES:

    I would like this to work by Thursday, so i someone could help i would be very happy.

    Kind regards,

    Nick De Leenheer

    /*
     * Copyright (c) 2024 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    /** @file
     *  @brief Channel Sounding Initiator with Ranging Requestor sample
     */
    
    #include <math.h>
    #include <zephyr/kernel.h>
    #include <zephyr/types.h>
    #include <zephyr/sys/reboot.h>
    #include <zephyr/bluetooth/cs.h>
    #include <zephyr/bluetooth/gatt.h>
    #include <zephyr/bluetooth/conn.h>
    #include <bluetooth/scan.h>
    #include <bluetooth/services/ras.h>
    #include <bluetooth/gatt_dm.h>
    #include <bluetooth/cs_de.h>
    
    #include <dk_buttons_and_leds.h>
    
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(app_main, LOG_LEVEL_INF);
    
    #define CON_STATUS_LED DK_LED1
    
    #define CS_CONFIG_ID	       0
    #define NUM_MODE_0_STEPS       3
    #define PROCEDURE_COUNTER_NONE (-1)
    #define DE_SLIDING_WINDOW_SIZE (10)
    #define MAX_AP		       (CONFIG_BT_RAS_MAX_ANTENNA_PATHS)
    #define MAX_DEVICES 3
    
    // Totale buffer voor maximaal aantal stappen per ranging-procedure voor de LOCAL & PEER (initiator & reflector)
    #define LOCAL_PROCEDURE_MEM                                                                        \
    	((BT_RAS_MAX_STEPS_PER_PROCEDURE * sizeof(struct bt_le_cs_subevent_step)) +                \
    	 (BT_RAS_MAX_STEPS_PER_PROCEDURE * BT_RAS_MAX_STEP_DATA_LEN))
    
    // Buffermaat voor een volledige ontvangen ranging-procedure (inclusief headers, subevent headers, mode info en alle step data)
    #define BT_RAS_PROCEDURE_MEM                                                                       \
    	(BT_RAS_RANGING_HEADER_LEN +                                                               \
    	 (BT_RAS_MAX_SUBEVENTS_PER_PROCEDURE * BT_RAS_SUBEVENT_HEADER_LEN) +                       \
    	 (BT_RAS_MAX_STEPS_PER_PROCEDURE * BT_RAS_STEP_MODE_LEN) +                                 \
    	 (BT_RAS_MAX_STEPS_PER_PROCEDURE * BT_RAS_MAX_STEP_DATA_LEN))
    
    
    static K_SEM_DEFINE(sem_remote_capabilities_obtained, 0, 1);
    static K_SEM_DEFINE(sem_config_created, 0, 1);
    static K_SEM_DEFINE(sem_cs_security_enabled, 0, 1);
    static K_SEM_DEFINE(sem_connected, 0, 1);
    static K_SEM_DEFINE(sem_discovery_done, 0, 1);
    static K_SEM_DEFINE(sem_mtu_exchange_done, 0, 1);
    static K_SEM_DEFINE(sem_security, 0, 1);
    static K_SEM_DEFINE(sem_local_steps, 1, 1);
    static K_SEM_DEFINE(sem_disconnected, 0, 1);
    static K_SEM_DEFINE(sem_ranging_done, 0, 1);
    static K_SEM_DEFINE(sem_nrf_noise, 0, 1);
    
    static K_MUTEX_DEFINE(distance_estimate_buffer_mutex);
    
    
    /* For creating a buffer and a counter to correctly handle the step data */
    NET_BUF_SIMPLE_DEFINE_STATIC(latest_local_steps, LOCAL_PROCEDURE_MEM);
    NET_BUF_SIMPLE_DEFINE_STATIC(latest_peer_steps, BT_RAS_PROCEDURE_MEM);
    static int32_t most_recent_local_ranging_counter = PROCEDURE_COUNTER_NONE;
    static int32_t dropped_ranging_counter = PROCEDURE_COUNTER_NONE;
    
    /* For scanning & connecting with multiple devices */
    static bt_addr_le_t addresses[MAX_DEVICES];
    static int num_found = 0;
    static bool scanning_for_initial_devices = true;
    static bool connection_in_progress = false;
    static struct bt_conn *connection = NULL;
    static struct bt_conn *connections[MAX_DEVICES];
    
    /* For parsing the name of devices */
    #define NAME_LEN 30
    char reflector_names[MAX_DEVICES][NAME_LEN];
    char reflector_name[NAME_LEN] = "(onbekend)";
    
    /* For the ranging process */
    #define RANGING_ROUNDS 5
    static bool ranging_done = false;
    
    /* For buffering Distance estimations */
    static uint8_t buffer_index;
    static uint8_t buffer_num_valid;
    static cs_de_dist_estimates_t distance_estimate_buffer[MAX_AP][DE_SLIDING_WINDOW_SIZE];
    
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    
    // Storen van de distance_estimates van het REPORT => BUFFER
    static void store_distance_estimates(cs_de_report_t *p_report)
    {
    	// buffer wordt vergrendeld zodat geen andere thread of interrupt tegelijk kan lezen of schrijven.
    	int lock_state = k_mutex_lock(&distance_estimate_buffer_mutex, K_FOREVER);
    
    	__ASSERT_NO_MSG(lock_state == 0);
    
    	// buffer wordt gevuld met DISTANCE ESTIMATES mbv het gevulde raport door "cd_de_calc()" in "ranging_data_get_complete_cb()"
    	for (uint8_t ap = 0; ap < p_report->n_ap; ap++) {
    		memcpy(&distance_estimate_buffer[ap][buffer_index],
    		       &p_report->distance_estimates[ap], sizeof(cs_de_dist_estimates_t));
    	}
    
    	buffer_index = (buffer_index + 1) % DE_SLIDING_WINDOW_SIZE;
    
    	if (buffer_num_valid < DE_SLIDING_WINDOW_SIZE) {
    		buffer_num_valid++;
    	}
    
    	// Nu kan men de buffer weer gebruiken voor de get_distance()
    	k_mutex_unlock(&distance_estimate_buffer_mutex);
    }
    
    // Calculate AVERAGE DISTANCE door alle afstanden in de BUFFER WINDOW te averagen(om geen uitschieters te krijgen!)
    static cs_de_dist_estimates_t get_distance(uint8_t ap)
    {
    	cs_de_dist_estimates_t averaged_result = {};
    	uint8_t num_ifft = 0;
    	uint8_t num_phase_slope = 0;
    	uint8_t num_rtt = 0;
    
    	// LOCK de buffer zodat het niet beweegt als we er data uithalen voor averaging 
    	int lock_state = k_mutex_lock(&distance_estimate_buffer_mutex, K_FOREVER);
    
    	__ASSERT_NO_MSG(lock_state == 0);
    
    	for (uint8_t i = 0; i < buffer_num_valid; i++) {
    		if (isfinite(distance_estimate_buffer[ap][i].ifft)) {
    			num_ifft++;
    			averaged_result.ifft += distance_estimate_buffer[ap][i].ifft;
    		}
    		if (isfinite(distance_estimate_buffer[ap][i].phase_slope)) {
    			num_phase_slope++;
    			averaged_result.phase_slope += distance_estimate_buffer[ap][i].phase_slope;
    		}
    		if (isfinite(distance_estimate_buffer[ap][i].rtt)) {
    			num_rtt++;
    			averaged_result.rtt += distance_estimate_buffer[ap][i].rtt;
    		}
    	}
    
    	// UNLOCK de buffer zodat we er weer data kunnen bijvullen voor store_distance_estimates()
    	k_mutex_unlock(&distance_estimate_buffer_mutex);
    
    	if (num_ifft) {
    		averaged_result.ifft /= num_ifft;
    	}
    
    	if (num_phase_slope) {
    		averaged_result.phase_slope /= num_phase_slope;
    	}
    
    	if (num_rtt) {
    		averaged_result.rtt /= num_rtt;
    	}
    
    	return averaged_result;
    }
    
    // De LOCAL en PEER step data worden gecombineerd en verwerkt tot een afstandsrapport en kijkt men naar de kwaliteit
    static void ranging_data_get_complete_cb(struct bt_conn *conn, uint16_t ranging_counter, int err)
    {
    	ARG_UNUSED(conn);
    
    	if (err) {
    		LOG_ERR("Error when getting ranging data with ranging counter %d (err %d)",
    			ranging_counter, err);
    		return;
    	}
    	
    	LOG_INF("ranging_data_get_complete for ranging counter %d", ranging_counter);
    	LOG_DBG("Ranging data get completed for ranging counter %d", ranging_counter);
    
    	/* This struct is static to avoid putting it on the stack (it's very large) */
    	static cs_de_report_t cs_de_report;
    
    	cs_de_populate_report(&latest_local_steps, &latest_peer_steps, BT_CONN_LE_CS_ROLE_INITIATOR, &cs_de_report);
    
    	net_buf_simple_reset(&latest_local_steps);
    	net_buf_simple_reset(&latest_peer_steps);
    	k_sem_give(&sem_local_steps);
    	
    	// HIER WORDEN DE BEREKENINGEN GEDAAN IN "cs_de.c" EN IN ONS cs_de_report GEZET
    	cs_de_quality_t quality = cs_de_calc(&cs_de_report);
    
    	if (quality == CS_DE_QUALITY_OK) {
    		for (uint8_t ap = 0; ap < cs_de_report.n_ap; ap++) {
    			if (cs_de_report.tone_quality[ap] == CS_DE_TONE_QUALITY_OK) {
    				store_distance_estimates(&cs_de_report);	// Afstandsrapport wordt hier bewaard
    			}
    		}
    	}
    }
    
    // MANAGED binnenkomende step data van de LOCAL (initiator) in result
    static void subevent_result_cb(struct bt_conn *conn, struct bt_conn_le_cs_subevent_result *result)
    {
    	// als we deze precedure (result) ooit al hebben "gedropped" door een fout of overlap dan doen we niets met deze data
    	if (dropped_ranging_counter == result->header.procedure_counter) {
    		return;
    	}
    
    	// Indien de local ranging counter nog niet in SYNC is met de huidige ranging counter van de data, updaten we hem
    	if (most_recent_local_ranging_counter != bt_ras_rreq_get_ranging_counter(result->header.procedure_counter)) {
    		int sem_state = k_sem_take(&sem_local_steps, K_NO_WAIT);
    
    		if (sem_state < 0) {
    			dropped_ranging_counter = result->header.procedure_counter;
    			LOG_DBG("Dropped subevent results due to unfinished ranging data request.");
    			return;
    		}
    		// Syncen tussen PEER & LOCAL (initiator & reflector STEP DATA) is nodig om niet geen data door elkaar te hebben
    		most_recent_local_ranging_counter = bt_ras_rreq_get_ranging_counter(result->header.procedure_counter);
    	}
    
    	// Subevent data (bevat mode steps) heeft status "ABORTED" (niet succesvol afgerond) en dus genegeerd
    	if (result->header.subevent_done_status == BT_CONN_LE_CS_SUBEVENT_ABORTED) {
    		/* The steps from this subevent will not be used. */
    	} 
    	// Subevent STEP DATA succesvol afgerond => data in Latest Local Steps (Memory van onze initiator) geplaatst
    	else if (result->step_data_buf) {
    		if (result->step_data_buf->len <= net_buf_simple_tailroom(&latest_local_steps)) {
    			uint16_t len = result->step_data_buf->len;
    			uint8_t *step_data = net_buf_simple_pull_mem(result->step_data_buf, len);
    
    			net_buf_simple_add_mem(&latest_local_steps, step_data, len);
    		} else {
    			LOG_ERR("Not enough memory to store step data. (%d > %d)",
    				latest_local_steps.len + result->step_data_buf->len,
    				latest_local_steps.size);
    			net_buf_simple_reset(&latest_local_steps);
    			// We drop this procedure
    			dropped_ranging_counter = result->header.procedure_counter;
    			return;
    		}
    	}
    
    	dropped_ranging_counter = PROCEDURE_COUNTER_NONE;
    
    	// Procedure COMPLETED :)
    	if (result->header.procedure_done_status == BT_CONN_LE_CS_PROCEDURE_COMPLETE) {
    		most_recent_local_ranging_counter = bt_ras_rreq_get_ranging_counter(result->header.procedure_counter);
    	} 
    	// Procedure ABORTED   :(
    	else if (result->header.procedure_done_status == BT_CONN_LE_CS_PROCEDURE_ABORTED) {
    		LOG_WRN("Procedure %u aborted", result->header.procedure_counter);
    		net_buf_simple_reset(&latest_local_steps);
    		k_sem_give(&sem_local_steps);
    	}
    }
    
    // Haalt de step data van de PEER (reflector) op zodra de LOCAL procedure compleet is
    static void ranging_data_ready_cb(struct bt_conn *conn, uint16_t ranging_counter)
    {
    	LOG_DBG("Ranging data ready %i", ranging_counter);
    	LOG_INF("ranging_data_ready %i", ranging_counter);
    
    	// Enkel alle data ophalen wanneer de lokale huidige ranging counter overeenkomt met de verwachte meetronde
    	if (ranging_counter == most_recent_local_ranging_counter) {
    		int err = bt_ras_rreq_cp_get_ranging_data(conn, &latest_peer_steps,
    							  ranging_counter,
    							  ranging_data_get_complete_cb);
    		if (err) {
    			LOG_ERR("Get ranging data failed (err %d)", err);
    			net_buf_simple_reset(&latest_local_steps);
    			net_buf_simple_reset(&latest_peer_steps);
    			k_sem_give(&sem_local_steps);
    		}
    	}
    }
    
    static void ranging_data_overwritten_cb(struct bt_conn *conn, uint16_t ranging_counter)
    {
    	// LOG_INF("Ranging data overwritten %i", ranging_counter);
    }
    
    static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
    			    struct bt_gatt_exchange_params *params)
    {
    	if (err) {
    		LOG_ERR("MTU exchange failed (err %d)", err);
    		return;
    	}
    
    	// LOG_INF("MTU exchange success (%u)", bt_gatt_get_mtu(conn));
    	k_sem_give(&sem_mtu_exchange_done);
    }
    
    static void discovery_completed_cb(struct bt_gatt_dm *dm, void *context)
    {
    	int err;
    
    	// LOG_INF("The discovery procedure succeeded");
    
    	struct bt_conn *conn = bt_gatt_dm_conn_get(dm);
    
    	bt_gatt_dm_data_print(dm);
    
    	err = bt_ras_rreq_alloc_and_assign_handles(dm, conn);
    	if (err) {
    		LOG_ERR("RAS RREQ alloc init failed (err %d)", err);
    	}
    
    	err = bt_gatt_dm_data_release(dm);
    	if (err) {
    		LOG_ERR("Could not release the discovery data (err %d)", err);
    	}
    
    	k_sem_give(&sem_discovery_done);
    }
    
    static void discovery_service_not_found_cb(struct bt_conn *conn, void *context)
    {
    	// LOG_INF("The service could not be found during the discovery, disconnecting");
    	bt_conn_disconnect(connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    }
    
    static void discovery_error_found_cb(struct bt_conn *conn, int err, void *context)
    {
    	// LOG_INF("The discovery procedure failed (err %d)", err);
    	bt_conn_disconnect(connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    }
    
    static struct bt_gatt_dm_cb discovery_cb = {
    	.completed = discovery_completed_cb,
    	.service_not_found = discovery_service_not_found_cb,
    	.error_found = discovery_error_found_cb,
    };
    
    static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (err) {
    		LOG_ERR("Security failed: %s level %u err %d %s", addr, level, err,
    			bt_security_err_to_str(err));
    		return;
    	}
    
    	// LOG_INF("Security changed: %s level %u", addr, level);
    	k_sem_give(&sem_security);
    }
    
    static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
    {
    	/* Ignore peer parameter preferences. */
    	return false;
    }
    
    static void connected_cb(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));
    	// LOG_INF("Connected to %s", addr);
    
        if (err) {
            LOG_ERR("Connection failed (err 0x%02x)", err);
            bt_conn_unref(conn);
    		k_sem_give(&sem_connected);	// NEEDED to get to the error instead of "W: conn failed to establish. RF noise?"
            return;
        }
    
        // When not in the scanning process we give a semaphore for being connected
        if (!scanning_for_initial_devices) {
            for (int i = 0; i < MAX_DEVICES; i++) {
                if (connections[i] == NULL) {
                    connections[i] = bt_conn_ref(conn);
                    break;
                }
            }
            dk_set_led_on(CON_STATUS_LED);
            k_sem_give(&sem_connected);
        }
    
        // When still in the scanning process we disconnect
        if (scanning_for_initial_devices) {
            k_sleep(K_MSEC(200));
            bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    		connection_in_progress = false;
        }
    }
    
    static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    	// LOG_INF("Disconnected from %s, reason: reason 0x%02X", addr, reason);
    
    	if (reason == 0x3E){
    		// LOG_INF("nRF Noise detected");
    		k_sem_give(&sem_nrf_noise);
    	}
    
        bt_conn_unref(conn);
        connection = NULL;
        dk_set_led_off(CON_STATUS_LED);
    
        // Handle disconnection during initial device scan
        if (scanning_for_initial_devices) {
    		// LOG_INF("disconnected during scanning phase");
            k_sem_give(&sem_disconnected);
            connection_in_progress = false;
    
    		// When more devices need to get detected we continue scanning
            if (num_found < MAX_DEVICES) {
                bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    
    		// When all devices has been found we stop scanning
            } else {
                scanning_for_initial_devices = false;
            }
        } 
    	
    	// Handle proper disconnection after ranging is done
    	if(ranging_done){
    		// LOG_INF("ranging is done");
    		k_sem_give(&sem_ranging_done);
    	}
    }
    
    static void remote_capabilities_cb(struct bt_conn *conn,
    				   uint8_t status,
    				   struct bt_conn_le_cs_capabilities *params)
    {
    	ARG_UNUSED(conn);
    	ARG_UNUSED(params);
    
    	if (status == BT_HCI_ERR_SUCCESS) {
    		// LOG_INF("CS capability exchange completed.");
    		k_sem_give(&sem_remote_capabilities_obtained);
    	} else {
    		LOG_WRN("CS capability exchange failed. (HCI status 0x%02x)", status);
    	}
    }
    
    static void config_create_cb(struct bt_conn *conn,
    			     uint8_t status,
    			     struct bt_conn_le_cs_config *config)
    {
    	ARG_UNUSED(conn);
    
    	if (status == BT_HCI_ERR_SUCCESS) {
    		// LOG_INF("CS config creation complete. ID: %d", config->id);
    		k_sem_give(&sem_config_created);
    	} else {
    		LOG_WRN("CS config creation failed. (HCI status 0x%02x)", status);
    	}
    }
    
    static void security_enable_cb(struct bt_conn *conn, uint8_t status)
    {
    	ARG_UNUSED(conn);
    
    	if (status == BT_HCI_ERR_SUCCESS) {
    		// LOG_INF("CS security enabled.");
    		k_sem_give(&sem_cs_security_enabled);
    	} else {
    		LOG_WRN("CS security enable failed. (HCI status 0x%02x)", status);
    	}
    }
    
    static void procedure_enable_cb(struct bt_conn *conn,
    				uint8_t status,
    				struct bt_conn_le_cs_procedure_enable_complete *params)
    {
    	ARG_UNUSED(conn);
    
    	if (status == BT_HCI_ERR_SUCCESS) {
    		if (params->state == 1) {
    			// LOG_INF("CS procedures enabled:\n"
    			// 	" - config ID: %u\n"
    			// 	" - antenna configuration index: %u\n"
    			// 	" - TX power: %d dbm\n"
    			// 	" - subevent length: %u us\n"
    			// 	" - subevents per event: %u\n"
    			// 	" - subevent interval: %u\n"
    			// 	" - event interval: %u\n"
    			// 	" - procedure interval: %u\n"
    			// 	" - procedure count: %u\n"
    			// 	" - maximum procedure length: %u",
    			// 	params->config_id, params->tone_antenna_config_selection,
    			// 	params->selected_tx_power, params->subevent_len,
    			// 	params->subevents_per_event, params->subevent_interval,
    			// 	params->event_interval, params->procedure_interval,
    			// 	params->procedure_count, params->max_procedure_len);
    		} else {
    			// LOG_INF("CS procedures disabled.");
    		}
    	} else {
    		LOG_WRN("CS procedures enable failed. (HCI status 0x%02x)", status);
    	}
    }
    
    
    
    static bool ad_parse_cb(struct bt_data *data, void *user_data)
    {
        char *name = user_data;
    
        if (data->type == BT_DATA_NAME_COMPLETE || data->type == BT_DATA_NAME_SHORTENED) {
            size_t len = MIN(data->data_len, NAME_LEN - 1);
            memcpy(name, data->data, len);
            name[len] = '\0';
            return false;
        }
    
        return true;
    }
    
    static void scan_filter_match(struct bt_scan_device_info *device_info,
                                  struct bt_scan_filter_match *filter_match, bool connectable)
    {
    	// Not scanning for devices OR already connected to a device
        if (!scanning_for_initial_devices || connection_in_progress) {
            return;
        }
    
        // Device has already been detected
        for (int i = 0; i < num_found; i++) {
            if (!bt_addr_le_cmp(&addresses[i], device_info->recv_info->addr)) {
                return;
            }
        }
    
    	// End scanning when ALL devices detected
        if (num_found >= MAX_DEVICES) {
            return;
        }
    
        // Retreiving data from the scanned device
        struct net_buf_simple ad_copy = *device_info->adv_data;
        snprintf(reflector_names[num_found], NAME_LEN, "(onbekend)");
        bt_data_parse(&ad_copy, ad_parse_cb, reflector_names[num_found]);
    
        bt_addr_le_copy(&addresses[num_found], device_info->recv_info->addr);
    
    
        bt_scan_stop();
        k_msleep(50);
    
    	// Setup a quick connection with the device
        struct bt_conn *conn = NULL;
        const struct bt_conn_le_create_param *create_param = BT_CONN_LE_CREATE_PARAM(BT_CONN_LE_OPT_NONE, 0x0060, 0x0030);
        const struct bt_le_conn_param *conn_param = BT_LE_CONN_PARAM_DEFAULT;
    	connection_in_progress = true;
    
        int err = bt_conn_le_create(&addresses[num_found], create_param, conn_param, &conn);
        if (err) {
            connection_in_progress = false;
            return;
        }
    
    	// LOG the information about the device
        char addr_str[BT_ADDR_LE_STR_LEN];
        bt_addr_le_to_str(&addresses[num_found], addr_str, sizeof(addr_str));
    
        LOG_INF("Device %d/%d verbonden: \"%s\" (%s)", num_found + 1, MAX_DEVICES, reflector_names[num_found], addr_str);
    
        num_found++;
    }
    
    static void scan_connecting_error(struct bt_scan_device_info *device_info)
    {
    	int err;
    
    	// LOG_INF("Connecting failed, restarting scanning");
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_PASSIVE);
    	if (err) {
    		LOG_ERR("Failed to restart scanning (err %i)", err);
    		return;
    	}
    }
    
    static void scan_connecting(struct bt_scan_device_info *device_info, struct bt_conn *conn)
    {
    	// LOG_INF("Connecting");
    }
    
    BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, scan_connecting_error, scan_connecting);
    
    static int scan_init(void)
    {
    	int err;
    
    	struct bt_scan_init_param param = {
    		.scan_param = NULL, 
    		.conn_param = BT_LE_CONN_PARAM_DEFAULT,
    		.connect_if_match = 0};
    
    	bt_scan_init(&param);
    	bt_scan_cb_register(&scan_cb);
    
    	// /** Filter for names. */
    	// BT_SCAN_FILTER_TYPE_NAME,
    
    	// /** Filter for short names. */
    	// BT_SCAN_FILTER_TYPE_SHORT_NAME,
    
    	// /** Filter for addresses. */
    	// BT_SCAN_FILTER_TYPE_ADDR,
    
    	// /** Filter for UUIDs. */
    	// BT_SCAN_FILTER_TYPE_UUID,
    
    	// /** Filter for appearances. */
    	// BT_SCAN_FILTER_TYPE_APPEARANCE,
    
    	// /** Filter for manufacturer data. */
    	// BT_SCAN_FILTER_TYPE_MANUFACTURER_DATA,
    
    	// err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_NAME, TARGET_NAME);
    	// if (err) {
    	// 	return err;
    	// }
    
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_RANGING_SERVICE);
    	if (err) {
    		return err;
    	}
    
    	err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, false);	//false: 1 match required | true: ALL matches required
    	if (err) {													
    		return err;
    	}
    
    	return 0;
    }
    
    BT_CONN_CB_DEFINE(conn_cb) = {
    	.connected = connected_cb,
    	.disconnected = disconnected_cb,
    	.le_param_req = le_param_req,
    	.security_changed = security_changed,
    	.le_cs_read_remote_capabilities_complete = remote_capabilities_cb,
    	.le_cs_config_complete = config_create_cb,
    	.le_cs_security_enable_complete = security_enable_cb,
    	.le_cs_procedure_enable_complete = procedure_enable_cb,
    	.le_cs_subevent_data_available = subevent_result_cb,
    };
    
    int main(void)
    {
    	int err;
    
    	dk_leds_init();
    
    	err = bt_enable(NULL);
    	if (err) {
    		LOG_ERR("Bluetooth init failed (err %d)", err);
    		return 0;
    	}
    
    	err = scan_init();
    	if (err) {
    		LOG_ERR("Scan init failed (err %d)", err);
    		return 0;
    	}
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_PASSIVE);
    	if (err) {
    		LOG_ERR("Scanning failed to start (err %i)", err);
    		return 0;
    	}
    
    	for (int i = 0; i < MAX_DEVICES; i++) {
    		k_sem_take(&sem_disconnected, K_FOREVER);
    	}	
    
    	LOG_INF("All devices detected => stop scanning");
    
    
    	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    	/* Reconnect one by one with previously detected devices */
    	while (true){
    		for (int i = 0; i < MAX_DEVICES; i++) {
    
    			const bt_addr_le_t *peer_addr = &addresses[i];
    			char addr_str[BT_ADDR_LE_STR_LEN];
    			bt_addr_le_to_str(peer_addr, addr_str, sizeof(addr_str));
    
    			const char *reflector_name = reflector_names[i];
    			int device_nr = i+1;
    			int32_t device = i;
    
    			const struct bt_conn_le_create_param *create_param = BT_CONN_LE_CREATE_PARAM(BT_CONN_LE_OPT_NONE, 0x0060, 0x0030);
    			const struct bt_le_conn_param *conn_param = BT_LE_CONN_PARAM_DEFAULT;
    
    			if (connections[i]) {
    				bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    				bt_conn_unref(connections[i]);
    				connections[i] = NULL;
    			}
    
    			// LOG_INF("Connecting with device %s (%s)", reflector_name, addr_str);
    			err = bt_conn_le_create(peer_addr, create_param, conn_param, &connections[i]);
    			if (err) {
    				LOG_ERR("Kon niet verbinden met %s (%s), foutcode: %d", reflector_name, addr_str, err);
    				continue;
    			}
    
    			/* Check for connection Time out: connection failed */
    			if (k_sem_take(&sem_connected, K_SECONDS(4)) != 0) {
    				if (connections[i]) {
    					bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    					bt_conn_unref(connections[i]);
    					connections[i] = NULL;
    				}
    				continue; // Move on to the next device
    			}
    
    			/* Check for nrf Noise: connection succeeds, but disconnects right after  */
    			if (k_sem_take(&sem_nrf_noise, K_MSEC(500)) == 0){
    				// LOG_INF("Skipping device %d, going to the next device", device_nr);
    				if (connections[i]) {
    					bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    					connections[i] = NULL;
    					k_sleep(K_SECONDS(1));
    				}
    				continue; // Move on to the next device
    			}
    
    			/* To establish a stable connection */
    			k_sleep(K_MSEC(200));
    
    			// Set Security
    			err = bt_conn_set_security(connections[i], BT_SECURITY_L2);
    			if (err) {
    				LOG_ERR("Security failed for %s", reflector_name);
    				continue;
    			}
    			k_sem_take(&sem_security, K_FOREVER);
    
    			// MTU Exchange
    			static struct bt_gatt_exchange_params mtu_exchange_params = {.func = mtu_exchange_cb};
    			bt_gatt_exchange_mtu(connections[i], &mtu_exchange_params);
    			k_sem_take(&sem_mtu_exchange_done, K_FOREVER);
    
    			// GATT Discovery
    			err = bt_gatt_dm_start(connections[i], BT_UUID_RANGING_SERVICE, &discovery_cb, NULL);
    			if (err) {
    				LOG_ERR("Discovery failed for %s", reflector_name);
    				return 0;
    			}
    			k_sem_take(&sem_discovery_done, K_FOREVER);
    
    			// // Default settings
    			const struct bt_le_cs_set_default_settings_param default_settings = {
    				.enable_initiator_role = true,
    				.enable_reflector_role = false,
    				.cs_sync_antenna_selection = BT_LE_CS_ANTENNA_SELECTION_OPT_REPETITIVE,
    				.max_tx_power = BT_HCI_OP_LE_CS_MAX_MAX_TX_POWER,
    			};
    			err = bt_le_cs_set_default_settings(connections[i], &default_settings);
    			if (err) {
    				LOG_ERR("Failed to configure default CS settings for %s", reflector_name);
    				return 0;
    			}
    
    			// Subscriptions
    			err  = bt_ras_rreq_rd_overwritten_subscribe(connections[i], ranging_data_overwritten_cb);
    			err |= bt_ras_rreq_rd_ready_subscribe(connections[i], ranging_data_ready_cb);
    			err |= bt_ras_rreq_on_demand_rd_subscribe(connections[i]);
    			err |= bt_ras_rreq_cp_subscribe(connections[i]);
    			if (err) {
    				LOG_ERR("Subscriptions failed for %s", reflector_name);
    				continue;
    			}
    
    			// Capabilities
    			err = bt_le_cs_read_remote_supported_capabilities(connections[i]);
    			if (err) {
    				LOG_ERR("Failed to exchange CS capabilities for %s", reflector_name);
    				return 0;
    			}
    			k_sem_take(&sem_remote_capabilities_obtained, K_FOREVER);
    
    			// CS Config
    			struct bt_le_cs_create_config_params config_params = {
    				.id = CS_CONFIG_ID,
    				.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_2,
    				.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_1,
    				.min_main_mode_steps = 2,
    				.max_main_mode_steps = 5,
    				.main_mode_repetition = 0,
    				.mode_0_steps = NUM_MODE_0_STEPS,
    				.role = BT_CONN_LE_CS_ROLE_INITIATOR,
    				.rtt_type = BT_CONN_LE_CS_RTT_TYPE_AA_ONLY,
    				.cs_sync_phy = BT_CONN_LE_CS_SYNC_1M_PHY,
    				.channel_map_repetition = 3,
    				.channel_selection_type = BT_CONN_LE_CS_CHSEL_TYPE_3B,
    				.ch3c_shape = BT_CONN_LE_CS_CH3C_SHAPE_HAT,
    				.ch3c_jump = 2,
    			};
    			// Dus alle channels MOETEN aanstaan voor IFFT!
    			bt_le_cs_set_valid_chmap_bits(config_params.channel_map);
    			err = bt_le_cs_create_config(connections[i], &config_params,
    							BT_LE_CS_CREATE_CONFIG_CONTEXT_LOCAL_AND_REMOTE);
    			if (err) {
    				LOG_ERR("Failed to create CS config (err %d)", err);
    				return 0;
    			}
    			k_sem_take(&sem_config_created, K_FOREVER);
    
    			// Enable CS security
    			err = bt_le_cs_security_enable(connections[i]);
    			if (err) {
    				LOG_ERR("Failed to start CS Security for %s", reflector_name);
    				return 0;
    			}
    			k_sem_take(&sem_cs_security_enabled, K_FOREVER);
    
    			// Procedure params
    			const struct bt_le_cs_set_procedure_parameters_param procedure_params = {
    				.config_id = CS_CONFIG_ID,
    				.max_procedure_len = 1000,
    				.min_procedure_interval = 10,
    				.max_procedure_interval = 10,
    				.max_procedure_count = 0,
    				.min_subevent_len = 60000,
    				.max_subevent_len = 60000,
    				.tone_antenna_config_selection = BT_LE_CS_TONE_ANTENNA_CONFIGURATION_A1_B1,
    				.phy = BT_LE_CS_PROCEDURE_PHY_1M,
    				.tx_power_delta = 0x80,
    				.preferred_peer_antenna = BT_LE_CS_PROCEDURE_PREFERRED_PEER_ANTENNA_1,
    				.snr_control_initiator = BT_LE_CS_SNR_CONTROL_NOT_USED,
    				.snr_control_reflector = BT_LE_CS_SNR_CONTROL_NOT_USED,
    			};
    			err = bt_le_cs_set_procedure_parameters(connections[i], &procedure_params);
    			if (err) {
    				LOG_ERR("Failed to set procedure parameters for %s", reflector_name);
    				return 0;
    			}
    
    			// Enable procedure
    			struct bt_le_cs_procedure_enable_param params = {
    				.config_id = CS_CONFIG_ID,
    				.enable = 1,
    			};
    			err = bt_le_cs_procedure_enable(connections[i], &params);
    			if (err) {
    				LOG_ERR("Failed to enable CS procedures for %s", reflector_name);
    				return 0;
    			}
    
    			////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    			/* Ranging estimates */
    
    			LOG_INF("Device %d: %s", device_nr, reflector_name);
    
    			for (int round = 0; round < RANGING_ROUNDS; round++) {
    				k_sleep(K_MSEC(500));
    
    				if (buffer_num_valid != 0) {
    					for (uint8_t ap = 0; ap < MAX_AP; ap++) {
    						cs_de_dist_estimates_t distance_on_ap = get_distance(ap);
    
    						LOG_INF("ifft: %f, phase_slope: %f, rtt: %f", 
    							(double)distance_on_ap.ifft,
    							(double)distance_on_ap.phase_slope,
    							(double)distance_on_ap.rtt);
    					}
    				}
    			}
    
    			/* for stable disconnection */
    			ranging_done = true;
    			bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    			connections[i] = NULL; 
    
    			k_sem_take(&sem_ranging_done, K_FOREVER);
    			
    			ranging_done = false;
    		}
    	}
    }
    

Reply
  • So, I have come to solutions myself, but there is only 1 problem left for me:

    PROBLEM: 

    We get this working chronology now, and i already understand all of the functions quite good... But for multiple connections handled sequentially, there is a problem of the counters and that the buffer doesn't get updated correctly. I want to know how to handle this correctly and how to solve this problem.

    The problem is thus, that we don't get in this data_complete function, where we collect the step data from the PEER and LOCAL device to create the cs_de_report and to eventually get our new DISTANCE ESTIMATES:

    I would like this to work by Thursday, so i someone could help i would be very happy.

    Kind regards,

    Nick De Leenheer

    /*
     * Copyright (c) 2024 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    /** @file
     *  @brief Channel Sounding Initiator with Ranging Requestor sample
     */
    
    #include <math.h>
    #include <zephyr/kernel.h>
    #include <zephyr/types.h>
    #include <zephyr/sys/reboot.h>
    #include <zephyr/bluetooth/cs.h>
    #include <zephyr/bluetooth/gatt.h>
    #include <zephyr/bluetooth/conn.h>
    #include <bluetooth/scan.h>
    #include <bluetooth/services/ras.h>
    #include <bluetooth/gatt_dm.h>
    #include <bluetooth/cs_de.h>
    
    #include <dk_buttons_and_leds.h>
    
    #include <zephyr/logging/log.h>
    LOG_MODULE_REGISTER(app_main, LOG_LEVEL_INF);
    
    #define CON_STATUS_LED DK_LED1
    
    #define CS_CONFIG_ID	       0
    #define NUM_MODE_0_STEPS       3
    #define PROCEDURE_COUNTER_NONE (-1)
    #define DE_SLIDING_WINDOW_SIZE (10)
    #define MAX_AP		       (CONFIG_BT_RAS_MAX_ANTENNA_PATHS)
    #define MAX_DEVICES 3
    
    // Totale buffer voor maximaal aantal stappen per ranging-procedure voor de LOCAL & PEER (initiator & reflector)
    #define LOCAL_PROCEDURE_MEM                                                                        \
    	((BT_RAS_MAX_STEPS_PER_PROCEDURE * sizeof(struct bt_le_cs_subevent_step)) +                \
    	 (BT_RAS_MAX_STEPS_PER_PROCEDURE * BT_RAS_MAX_STEP_DATA_LEN))
    
    // Buffermaat voor een volledige ontvangen ranging-procedure (inclusief headers, subevent headers, mode info en alle step data)
    #define BT_RAS_PROCEDURE_MEM                                                                       \
    	(BT_RAS_RANGING_HEADER_LEN +                                                               \
    	 (BT_RAS_MAX_SUBEVENTS_PER_PROCEDURE * BT_RAS_SUBEVENT_HEADER_LEN) +                       \
    	 (BT_RAS_MAX_STEPS_PER_PROCEDURE * BT_RAS_STEP_MODE_LEN) +                                 \
    	 (BT_RAS_MAX_STEPS_PER_PROCEDURE * BT_RAS_MAX_STEP_DATA_LEN))
    
    
    static K_SEM_DEFINE(sem_remote_capabilities_obtained, 0, 1);
    static K_SEM_DEFINE(sem_config_created, 0, 1);
    static K_SEM_DEFINE(sem_cs_security_enabled, 0, 1);
    static K_SEM_DEFINE(sem_connected, 0, 1);
    static K_SEM_DEFINE(sem_discovery_done, 0, 1);
    static K_SEM_DEFINE(sem_mtu_exchange_done, 0, 1);
    static K_SEM_DEFINE(sem_security, 0, 1);
    static K_SEM_DEFINE(sem_local_steps, 1, 1);
    static K_SEM_DEFINE(sem_disconnected, 0, 1);
    static K_SEM_DEFINE(sem_ranging_done, 0, 1);
    static K_SEM_DEFINE(sem_nrf_noise, 0, 1);
    
    static K_MUTEX_DEFINE(distance_estimate_buffer_mutex);
    
    
    /* For creating a buffer and a counter to correctly handle the step data */
    NET_BUF_SIMPLE_DEFINE_STATIC(latest_local_steps, LOCAL_PROCEDURE_MEM);
    NET_BUF_SIMPLE_DEFINE_STATIC(latest_peer_steps, BT_RAS_PROCEDURE_MEM);
    static int32_t most_recent_local_ranging_counter = PROCEDURE_COUNTER_NONE;
    static int32_t dropped_ranging_counter = PROCEDURE_COUNTER_NONE;
    
    /* For scanning & connecting with multiple devices */
    static bt_addr_le_t addresses[MAX_DEVICES];
    static int num_found = 0;
    static bool scanning_for_initial_devices = true;
    static bool connection_in_progress = false;
    static struct bt_conn *connection = NULL;
    static struct bt_conn *connections[MAX_DEVICES];
    
    /* For parsing the name of devices */
    #define NAME_LEN 30
    char reflector_names[MAX_DEVICES][NAME_LEN];
    char reflector_name[NAME_LEN] = "(onbekend)";
    
    /* For the ranging process */
    #define RANGING_ROUNDS 5
    static bool ranging_done = false;
    
    /* For buffering Distance estimations */
    static uint8_t buffer_index;
    static uint8_t buffer_num_valid;
    static cs_de_dist_estimates_t distance_estimate_buffer[MAX_AP][DE_SLIDING_WINDOW_SIZE];
    
    
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    
    // Storen van de distance_estimates van het REPORT => BUFFER
    static void store_distance_estimates(cs_de_report_t *p_report)
    {
    	// buffer wordt vergrendeld zodat geen andere thread of interrupt tegelijk kan lezen of schrijven.
    	int lock_state = k_mutex_lock(&distance_estimate_buffer_mutex, K_FOREVER);
    
    	__ASSERT_NO_MSG(lock_state == 0);
    
    	// buffer wordt gevuld met DISTANCE ESTIMATES mbv het gevulde raport door "cd_de_calc()" in "ranging_data_get_complete_cb()"
    	for (uint8_t ap = 0; ap < p_report->n_ap; ap++) {
    		memcpy(&distance_estimate_buffer[ap][buffer_index],
    		       &p_report->distance_estimates[ap], sizeof(cs_de_dist_estimates_t));
    	}
    
    	buffer_index = (buffer_index + 1) % DE_SLIDING_WINDOW_SIZE;
    
    	if (buffer_num_valid < DE_SLIDING_WINDOW_SIZE) {
    		buffer_num_valid++;
    	}
    
    	// Nu kan men de buffer weer gebruiken voor de get_distance()
    	k_mutex_unlock(&distance_estimate_buffer_mutex);
    }
    
    // Calculate AVERAGE DISTANCE door alle afstanden in de BUFFER WINDOW te averagen(om geen uitschieters te krijgen!)
    static cs_de_dist_estimates_t get_distance(uint8_t ap)
    {
    	cs_de_dist_estimates_t averaged_result = {};
    	uint8_t num_ifft = 0;
    	uint8_t num_phase_slope = 0;
    	uint8_t num_rtt = 0;
    
    	// LOCK de buffer zodat het niet beweegt als we er data uithalen voor averaging 
    	int lock_state = k_mutex_lock(&distance_estimate_buffer_mutex, K_FOREVER);
    
    	__ASSERT_NO_MSG(lock_state == 0);
    
    	for (uint8_t i = 0; i < buffer_num_valid; i++) {
    		if (isfinite(distance_estimate_buffer[ap][i].ifft)) {
    			num_ifft++;
    			averaged_result.ifft += distance_estimate_buffer[ap][i].ifft;
    		}
    		if (isfinite(distance_estimate_buffer[ap][i].phase_slope)) {
    			num_phase_slope++;
    			averaged_result.phase_slope += distance_estimate_buffer[ap][i].phase_slope;
    		}
    		if (isfinite(distance_estimate_buffer[ap][i].rtt)) {
    			num_rtt++;
    			averaged_result.rtt += distance_estimate_buffer[ap][i].rtt;
    		}
    	}
    
    	// UNLOCK de buffer zodat we er weer data kunnen bijvullen voor store_distance_estimates()
    	k_mutex_unlock(&distance_estimate_buffer_mutex);
    
    	if (num_ifft) {
    		averaged_result.ifft /= num_ifft;
    	}
    
    	if (num_phase_slope) {
    		averaged_result.phase_slope /= num_phase_slope;
    	}
    
    	if (num_rtt) {
    		averaged_result.rtt /= num_rtt;
    	}
    
    	return averaged_result;
    }
    
    // De LOCAL en PEER step data worden gecombineerd en verwerkt tot een afstandsrapport en kijkt men naar de kwaliteit
    static void ranging_data_get_complete_cb(struct bt_conn *conn, uint16_t ranging_counter, int err)
    {
    	ARG_UNUSED(conn);
    
    	if (err) {
    		LOG_ERR("Error when getting ranging data with ranging counter %d (err %d)",
    			ranging_counter, err);
    		return;
    	}
    	
    	LOG_INF("ranging_data_get_complete for ranging counter %d", ranging_counter);
    	LOG_DBG("Ranging data get completed for ranging counter %d", ranging_counter);
    
    	/* This struct is static to avoid putting it on the stack (it's very large) */
    	static cs_de_report_t cs_de_report;
    
    	cs_de_populate_report(&latest_local_steps, &latest_peer_steps, BT_CONN_LE_CS_ROLE_INITIATOR, &cs_de_report);
    
    	net_buf_simple_reset(&latest_local_steps);
    	net_buf_simple_reset(&latest_peer_steps);
    	k_sem_give(&sem_local_steps);
    	
    	// HIER WORDEN DE BEREKENINGEN GEDAAN IN "cs_de.c" EN IN ONS cs_de_report GEZET
    	cs_de_quality_t quality = cs_de_calc(&cs_de_report);
    
    	if (quality == CS_DE_QUALITY_OK) {
    		for (uint8_t ap = 0; ap < cs_de_report.n_ap; ap++) {
    			if (cs_de_report.tone_quality[ap] == CS_DE_TONE_QUALITY_OK) {
    				store_distance_estimates(&cs_de_report);	// Afstandsrapport wordt hier bewaard
    			}
    		}
    	}
    }
    
    // MANAGED binnenkomende step data van de LOCAL (initiator) in result
    static void subevent_result_cb(struct bt_conn *conn, struct bt_conn_le_cs_subevent_result *result)
    {
    	// als we deze precedure (result) ooit al hebben "gedropped" door een fout of overlap dan doen we niets met deze data
    	if (dropped_ranging_counter == result->header.procedure_counter) {
    		return;
    	}
    
    	// Indien de local ranging counter nog niet in SYNC is met de huidige ranging counter van de data, updaten we hem
    	if (most_recent_local_ranging_counter != bt_ras_rreq_get_ranging_counter(result->header.procedure_counter)) {
    		int sem_state = k_sem_take(&sem_local_steps, K_NO_WAIT);
    
    		if (sem_state < 0) {
    			dropped_ranging_counter = result->header.procedure_counter;
    			LOG_DBG("Dropped subevent results due to unfinished ranging data request.");
    			return;
    		}
    		// Syncen tussen PEER & LOCAL (initiator & reflector STEP DATA) is nodig om niet geen data door elkaar te hebben
    		most_recent_local_ranging_counter = bt_ras_rreq_get_ranging_counter(result->header.procedure_counter);
    	}
    
    	// Subevent data (bevat mode steps) heeft status "ABORTED" (niet succesvol afgerond) en dus genegeerd
    	if (result->header.subevent_done_status == BT_CONN_LE_CS_SUBEVENT_ABORTED) {
    		/* The steps from this subevent will not be used. */
    	} 
    	// Subevent STEP DATA succesvol afgerond => data in Latest Local Steps (Memory van onze initiator) geplaatst
    	else if (result->step_data_buf) {
    		if (result->step_data_buf->len <= net_buf_simple_tailroom(&latest_local_steps)) {
    			uint16_t len = result->step_data_buf->len;
    			uint8_t *step_data = net_buf_simple_pull_mem(result->step_data_buf, len);
    
    			net_buf_simple_add_mem(&latest_local_steps, step_data, len);
    		} else {
    			LOG_ERR("Not enough memory to store step data. (%d > %d)",
    				latest_local_steps.len + result->step_data_buf->len,
    				latest_local_steps.size);
    			net_buf_simple_reset(&latest_local_steps);
    			// We drop this procedure
    			dropped_ranging_counter = result->header.procedure_counter;
    			return;
    		}
    	}
    
    	dropped_ranging_counter = PROCEDURE_COUNTER_NONE;
    
    	// Procedure COMPLETED :)
    	if (result->header.procedure_done_status == BT_CONN_LE_CS_PROCEDURE_COMPLETE) {
    		most_recent_local_ranging_counter = bt_ras_rreq_get_ranging_counter(result->header.procedure_counter);
    	} 
    	// Procedure ABORTED   :(
    	else if (result->header.procedure_done_status == BT_CONN_LE_CS_PROCEDURE_ABORTED) {
    		LOG_WRN("Procedure %u aborted", result->header.procedure_counter);
    		net_buf_simple_reset(&latest_local_steps);
    		k_sem_give(&sem_local_steps);
    	}
    }
    
    // Haalt de step data van de PEER (reflector) op zodra de LOCAL procedure compleet is
    static void ranging_data_ready_cb(struct bt_conn *conn, uint16_t ranging_counter)
    {
    	LOG_DBG("Ranging data ready %i", ranging_counter);
    	LOG_INF("ranging_data_ready %i", ranging_counter);
    
    	// Enkel alle data ophalen wanneer de lokale huidige ranging counter overeenkomt met de verwachte meetronde
    	if (ranging_counter == most_recent_local_ranging_counter) {
    		int err = bt_ras_rreq_cp_get_ranging_data(conn, &latest_peer_steps,
    							  ranging_counter,
    							  ranging_data_get_complete_cb);
    		if (err) {
    			LOG_ERR("Get ranging data failed (err %d)", err);
    			net_buf_simple_reset(&latest_local_steps);
    			net_buf_simple_reset(&latest_peer_steps);
    			k_sem_give(&sem_local_steps);
    		}
    	}
    }
    
    static void ranging_data_overwritten_cb(struct bt_conn *conn, uint16_t ranging_counter)
    {
    	// LOG_INF("Ranging data overwritten %i", ranging_counter);
    }
    
    static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
    			    struct bt_gatt_exchange_params *params)
    {
    	if (err) {
    		LOG_ERR("MTU exchange failed (err %d)", err);
    		return;
    	}
    
    	// LOG_INF("MTU exchange success (%u)", bt_gatt_get_mtu(conn));
    	k_sem_give(&sem_mtu_exchange_done);
    }
    
    static void discovery_completed_cb(struct bt_gatt_dm *dm, void *context)
    {
    	int err;
    
    	// LOG_INF("The discovery procedure succeeded");
    
    	struct bt_conn *conn = bt_gatt_dm_conn_get(dm);
    
    	bt_gatt_dm_data_print(dm);
    
    	err = bt_ras_rreq_alloc_and_assign_handles(dm, conn);
    	if (err) {
    		LOG_ERR("RAS RREQ alloc init failed (err %d)", err);
    	}
    
    	err = bt_gatt_dm_data_release(dm);
    	if (err) {
    		LOG_ERR("Could not release the discovery data (err %d)", err);
    	}
    
    	k_sem_give(&sem_discovery_done);
    }
    
    static void discovery_service_not_found_cb(struct bt_conn *conn, void *context)
    {
    	// LOG_INF("The service could not be found during the discovery, disconnecting");
    	bt_conn_disconnect(connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    }
    
    static void discovery_error_found_cb(struct bt_conn *conn, int err, void *context)
    {
    	// LOG_INF("The discovery procedure failed (err %d)", err);
    	bt_conn_disconnect(connection, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    }
    
    static struct bt_gatt_dm_cb discovery_cb = {
    	.completed = discovery_completed_cb,
    	.service_not_found = discovery_service_not_found_cb,
    	.error_found = discovery_error_found_cb,
    };
    
    static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (err) {
    		LOG_ERR("Security failed: %s level %u err %d %s", addr, level, err,
    			bt_security_err_to_str(err));
    		return;
    	}
    
    	// LOG_INF("Security changed: %s level %u", addr, level);
    	k_sem_give(&sem_security);
    }
    
    static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
    {
    	/* Ignore peer parameter preferences. */
    	return false;
    }
    
    static void connected_cb(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));
    	// LOG_INF("Connected to %s", addr);
    
        if (err) {
            LOG_ERR("Connection failed (err 0x%02x)", err);
            bt_conn_unref(conn);
    		k_sem_give(&sem_connected);	// NEEDED to get to the error instead of "W: conn failed to establish. RF noise?"
            return;
        }
    
        // When not in the scanning process we give a semaphore for being connected
        if (!scanning_for_initial_devices) {
            for (int i = 0; i < MAX_DEVICES; i++) {
                if (connections[i] == NULL) {
                    connections[i] = bt_conn_ref(conn);
                    break;
                }
            }
            dk_set_led_on(CON_STATUS_LED);
            k_sem_give(&sem_connected);
        }
    
        // When still in the scanning process we disconnect
        if (scanning_for_initial_devices) {
            k_sleep(K_MSEC(200));
            bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    		connection_in_progress = false;
        }
    }
    
    static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    	(void)bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    	// LOG_INF("Disconnected from %s, reason: reason 0x%02X", addr, reason);
    
    	if (reason == 0x3E){
    		// LOG_INF("nRF Noise detected");
    		k_sem_give(&sem_nrf_noise);
    	}
    
        bt_conn_unref(conn);
        connection = NULL;
        dk_set_led_off(CON_STATUS_LED);
    
        // Handle disconnection during initial device scan
        if (scanning_for_initial_devices) {
    		// LOG_INF("disconnected during scanning phase");
            k_sem_give(&sem_disconnected);
            connection_in_progress = false;
    
    		// When more devices need to get detected we continue scanning
            if (num_found < MAX_DEVICES) {
                bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    
    		// When all devices has been found we stop scanning
            } else {
                scanning_for_initial_devices = false;
            }
        } 
    	
    	// Handle proper disconnection after ranging is done
    	if(ranging_done){
    		// LOG_INF("ranging is done");
    		k_sem_give(&sem_ranging_done);
    	}
    }
    
    static void remote_capabilities_cb(struct bt_conn *conn,
    				   uint8_t status,
    				   struct bt_conn_le_cs_capabilities *params)
    {
    	ARG_UNUSED(conn);
    	ARG_UNUSED(params);
    
    	if (status == BT_HCI_ERR_SUCCESS) {
    		// LOG_INF("CS capability exchange completed.");
    		k_sem_give(&sem_remote_capabilities_obtained);
    	} else {
    		LOG_WRN("CS capability exchange failed. (HCI status 0x%02x)", status);
    	}
    }
    
    static void config_create_cb(struct bt_conn *conn,
    			     uint8_t status,
    			     struct bt_conn_le_cs_config *config)
    {
    	ARG_UNUSED(conn);
    
    	if (status == BT_HCI_ERR_SUCCESS) {
    		// LOG_INF("CS config creation complete. ID: %d", config->id);
    		k_sem_give(&sem_config_created);
    	} else {
    		LOG_WRN("CS config creation failed. (HCI status 0x%02x)", status);
    	}
    }
    
    static void security_enable_cb(struct bt_conn *conn, uint8_t status)
    {
    	ARG_UNUSED(conn);
    
    	if (status == BT_HCI_ERR_SUCCESS) {
    		// LOG_INF("CS security enabled.");
    		k_sem_give(&sem_cs_security_enabled);
    	} else {
    		LOG_WRN("CS security enable failed. (HCI status 0x%02x)", status);
    	}
    }
    
    static void procedure_enable_cb(struct bt_conn *conn,
    				uint8_t status,
    				struct bt_conn_le_cs_procedure_enable_complete *params)
    {
    	ARG_UNUSED(conn);
    
    	if (status == BT_HCI_ERR_SUCCESS) {
    		if (params->state == 1) {
    			// LOG_INF("CS procedures enabled:\n"
    			// 	" - config ID: %u\n"
    			// 	" - antenna configuration index: %u\n"
    			// 	" - TX power: %d dbm\n"
    			// 	" - subevent length: %u us\n"
    			// 	" - subevents per event: %u\n"
    			// 	" - subevent interval: %u\n"
    			// 	" - event interval: %u\n"
    			// 	" - procedure interval: %u\n"
    			// 	" - procedure count: %u\n"
    			// 	" - maximum procedure length: %u",
    			// 	params->config_id, params->tone_antenna_config_selection,
    			// 	params->selected_tx_power, params->subevent_len,
    			// 	params->subevents_per_event, params->subevent_interval,
    			// 	params->event_interval, params->procedure_interval,
    			// 	params->procedure_count, params->max_procedure_len);
    		} else {
    			// LOG_INF("CS procedures disabled.");
    		}
    	} else {
    		LOG_WRN("CS procedures enable failed. (HCI status 0x%02x)", status);
    	}
    }
    
    
    
    static bool ad_parse_cb(struct bt_data *data, void *user_data)
    {
        char *name = user_data;
    
        if (data->type == BT_DATA_NAME_COMPLETE || data->type == BT_DATA_NAME_SHORTENED) {
            size_t len = MIN(data->data_len, NAME_LEN - 1);
            memcpy(name, data->data, len);
            name[len] = '\0';
            return false;
        }
    
        return true;
    }
    
    static void scan_filter_match(struct bt_scan_device_info *device_info,
                                  struct bt_scan_filter_match *filter_match, bool connectable)
    {
    	// Not scanning for devices OR already connected to a device
        if (!scanning_for_initial_devices || connection_in_progress) {
            return;
        }
    
        // Device has already been detected
        for (int i = 0; i < num_found; i++) {
            if (!bt_addr_le_cmp(&addresses[i], device_info->recv_info->addr)) {
                return;
            }
        }
    
    	// End scanning when ALL devices detected
        if (num_found >= MAX_DEVICES) {
            return;
        }
    
        // Retreiving data from the scanned device
        struct net_buf_simple ad_copy = *device_info->adv_data;
        snprintf(reflector_names[num_found], NAME_LEN, "(onbekend)");
        bt_data_parse(&ad_copy, ad_parse_cb, reflector_names[num_found]);
    
        bt_addr_le_copy(&addresses[num_found], device_info->recv_info->addr);
    
    
        bt_scan_stop();
        k_msleep(50);
    
    	// Setup a quick connection with the device
        struct bt_conn *conn = NULL;
        const struct bt_conn_le_create_param *create_param = BT_CONN_LE_CREATE_PARAM(BT_CONN_LE_OPT_NONE, 0x0060, 0x0030);
        const struct bt_le_conn_param *conn_param = BT_LE_CONN_PARAM_DEFAULT;
    	connection_in_progress = true;
    
        int err = bt_conn_le_create(&addresses[num_found], create_param, conn_param, &conn);
        if (err) {
            connection_in_progress = false;
            return;
        }
    
    	// LOG the information about the device
        char addr_str[BT_ADDR_LE_STR_LEN];
        bt_addr_le_to_str(&addresses[num_found], addr_str, sizeof(addr_str));
    
        LOG_INF("Device %d/%d verbonden: \"%s\" (%s)", num_found + 1, MAX_DEVICES, reflector_names[num_found], addr_str);
    
        num_found++;
    }
    
    static void scan_connecting_error(struct bt_scan_device_info *device_info)
    {
    	int err;
    
    	// LOG_INF("Connecting failed, restarting scanning");
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_PASSIVE);
    	if (err) {
    		LOG_ERR("Failed to restart scanning (err %i)", err);
    		return;
    	}
    }
    
    static void scan_connecting(struct bt_scan_device_info *device_info, struct bt_conn *conn)
    {
    	// LOG_INF("Connecting");
    }
    
    BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, scan_connecting_error, scan_connecting);
    
    static int scan_init(void)
    {
    	int err;
    
    	struct bt_scan_init_param param = {
    		.scan_param = NULL, 
    		.conn_param = BT_LE_CONN_PARAM_DEFAULT,
    		.connect_if_match = 0};
    
    	bt_scan_init(&param);
    	bt_scan_cb_register(&scan_cb);
    
    	// /** Filter for names. */
    	// BT_SCAN_FILTER_TYPE_NAME,
    
    	// /** Filter for short names. */
    	// BT_SCAN_FILTER_TYPE_SHORT_NAME,
    
    	// /** Filter for addresses. */
    	// BT_SCAN_FILTER_TYPE_ADDR,
    
    	// /** Filter for UUIDs. */
    	// BT_SCAN_FILTER_TYPE_UUID,
    
    	// /** Filter for appearances. */
    	// BT_SCAN_FILTER_TYPE_APPEARANCE,
    
    	// /** Filter for manufacturer data. */
    	// BT_SCAN_FILTER_TYPE_MANUFACTURER_DATA,
    
    	// err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_NAME, TARGET_NAME);
    	// if (err) {
    	// 	return err;
    	// }
    
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_RANGING_SERVICE);
    	if (err) {
    		return err;
    	}
    
    	err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, false);	//false: 1 match required | true: ALL matches required
    	if (err) {													
    		return err;
    	}
    
    	return 0;
    }
    
    BT_CONN_CB_DEFINE(conn_cb) = {
    	.connected = connected_cb,
    	.disconnected = disconnected_cb,
    	.le_param_req = le_param_req,
    	.security_changed = security_changed,
    	.le_cs_read_remote_capabilities_complete = remote_capabilities_cb,
    	.le_cs_config_complete = config_create_cb,
    	.le_cs_security_enable_complete = security_enable_cb,
    	.le_cs_procedure_enable_complete = procedure_enable_cb,
    	.le_cs_subevent_data_available = subevent_result_cb,
    };
    
    int main(void)
    {
    	int err;
    
    	dk_leds_init();
    
    	err = bt_enable(NULL);
    	if (err) {
    		LOG_ERR("Bluetooth init failed (err %d)", err);
    		return 0;
    	}
    
    	err = scan_init();
    	if (err) {
    		LOG_ERR("Scan init failed (err %d)", err);
    		return 0;
    	}
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_PASSIVE);
    	if (err) {
    		LOG_ERR("Scanning failed to start (err %i)", err);
    		return 0;
    	}
    
    	for (int i = 0; i < MAX_DEVICES; i++) {
    		k_sem_take(&sem_disconnected, K_FOREVER);
    	}	
    
    	LOG_INF("All devices detected => stop scanning");
    
    
    	////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    	/* Reconnect one by one with previously detected devices */
    	while (true){
    		for (int i = 0; i < MAX_DEVICES; i++) {
    
    			const bt_addr_le_t *peer_addr = &addresses[i];
    			char addr_str[BT_ADDR_LE_STR_LEN];
    			bt_addr_le_to_str(peer_addr, addr_str, sizeof(addr_str));
    
    			const char *reflector_name = reflector_names[i];
    			int device_nr = i+1;
    			int32_t device = i;
    
    			const struct bt_conn_le_create_param *create_param = BT_CONN_LE_CREATE_PARAM(BT_CONN_LE_OPT_NONE, 0x0060, 0x0030);
    			const struct bt_le_conn_param *conn_param = BT_LE_CONN_PARAM_DEFAULT;
    
    			if (connections[i]) {
    				bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    				bt_conn_unref(connections[i]);
    				connections[i] = NULL;
    			}
    
    			// LOG_INF("Connecting with device %s (%s)", reflector_name, addr_str);
    			err = bt_conn_le_create(peer_addr, create_param, conn_param, &connections[i]);
    			if (err) {
    				LOG_ERR("Kon niet verbinden met %s (%s), foutcode: %d", reflector_name, addr_str, err);
    				continue;
    			}
    
    			/* Check for connection Time out: connection failed */
    			if (k_sem_take(&sem_connected, K_SECONDS(4)) != 0) {
    				if (connections[i]) {
    					bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    					bt_conn_unref(connections[i]);
    					connections[i] = NULL;
    				}
    				continue; // Move on to the next device
    			}
    
    			/* Check for nrf Noise: connection succeeds, but disconnects right after  */
    			if (k_sem_take(&sem_nrf_noise, K_MSEC(500)) == 0){
    				// LOG_INF("Skipping device %d, going to the next device", device_nr);
    				if (connections[i]) {
    					bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    					connections[i] = NULL;
    					k_sleep(K_SECONDS(1));
    				}
    				continue; // Move on to the next device
    			}
    
    			/* To establish a stable connection */
    			k_sleep(K_MSEC(200));
    
    			// Set Security
    			err = bt_conn_set_security(connections[i], BT_SECURITY_L2);
    			if (err) {
    				LOG_ERR("Security failed for %s", reflector_name);
    				continue;
    			}
    			k_sem_take(&sem_security, K_FOREVER);
    
    			// MTU Exchange
    			static struct bt_gatt_exchange_params mtu_exchange_params = {.func = mtu_exchange_cb};
    			bt_gatt_exchange_mtu(connections[i], &mtu_exchange_params);
    			k_sem_take(&sem_mtu_exchange_done, K_FOREVER);
    
    			// GATT Discovery
    			err = bt_gatt_dm_start(connections[i], BT_UUID_RANGING_SERVICE, &discovery_cb, NULL);
    			if (err) {
    				LOG_ERR("Discovery failed for %s", reflector_name);
    				return 0;
    			}
    			k_sem_take(&sem_discovery_done, K_FOREVER);
    
    			// // Default settings
    			const struct bt_le_cs_set_default_settings_param default_settings = {
    				.enable_initiator_role = true,
    				.enable_reflector_role = false,
    				.cs_sync_antenna_selection = BT_LE_CS_ANTENNA_SELECTION_OPT_REPETITIVE,
    				.max_tx_power = BT_HCI_OP_LE_CS_MAX_MAX_TX_POWER,
    			};
    			err = bt_le_cs_set_default_settings(connections[i], &default_settings);
    			if (err) {
    				LOG_ERR("Failed to configure default CS settings for %s", reflector_name);
    				return 0;
    			}
    
    			// Subscriptions
    			err  = bt_ras_rreq_rd_overwritten_subscribe(connections[i], ranging_data_overwritten_cb);
    			err |= bt_ras_rreq_rd_ready_subscribe(connections[i], ranging_data_ready_cb);
    			err |= bt_ras_rreq_on_demand_rd_subscribe(connections[i]);
    			err |= bt_ras_rreq_cp_subscribe(connections[i]);
    			if (err) {
    				LOG_ERR("Subscriptions failed for %s", reflector_name);
    				continue;
    			}
    
    			// Capabilities
    			err = bt_le_cs_read_remote_supported_capabilities(connections[i]);
    			if (err) {
    				LOG_ERR("Failed to exchange CS capabilities for %s", reflector_name);
    				return 0;
    			}
    			k_sem_take(&sem_remote_capabilities_obtained, K_FOREVER);
    
    			// CS Config
    			struct bt_le_cs_create_config_params config_params = {
    				.id = CS_CONFIG_ID,
    				.main_mode_type = BT_CONN_LE_CS_MAIN_MODE_2,
    				.sub_mode_type = BT_CONN_LE_CS_SUB_MODE_1,
    				.min_main_mode_steps = 2,
    				.max_main_mode_steps = 5,
    				.main_mode_repetition = 0,
    				.mode_0_steps = NUM_MODE_0_STEPS,
    				.role = BT_CONN_LE_CS_ROLE_INITIATOR,
    				.rtt_type = BT_CONN_LE_CS_RTT_TYPE_AA_ONLY,
    				.cs_sync_phy = BT_CONN_LE_CS_SYNC_1M_PHY,
    				.channel_map_repetition = 3,
    				.channel_selection_type = BT_CONN_LE_CS_CHSEL_TYPE_3B,
    				.ch3c_shape = BT_CONN_LE_CS_CH3C_SHAPE_HAT,
    				.ch3c_jump = 2,
    			};
    			// Dus alle channels MOETEN aanstaan voor IFFT!
    			bt_le_cs_set_valid_chmap_bits(config_params.channel_map);
    			err = bt_le_cs_create_config(connections[i], &config_params,
    							BT_LE_CS_CREATE_CONFIG_CONTEXT_LOCAL_AND_REMOTE);
    			if (err) {
    				LOG_ERR("Failed to create CS config (err %d)", err);
    				return 0;
    			}
    			k_sem_take(&sem_config_created, K_FOREVER);
    
    			// Enable CS security
    			err = bt_le_cs_security_enable(connections[i]);
    			if (err) {
    				LOG_ERR("Failed to start CS Security for %s", reflector_name);
    				return 0;
    			}
    			k_sem_take(&sem_cs_security_enabled, K_FOREVER);
    
    			// Procedure params
    			const struct bt_le_cs_set_procedure_parameters_param procedure_params = {
    				.config_id = CS_CONFIG_ID,
    				.max_procedure_len = 1000,
    				.min_procedure_interval = 10,
    				.max_procedure_interval = 10,
    				.max_procedure_count = 0,
    				.min_subevent_len = 60000,
    				.max_subevent_len = 60000,
    				.tone_antenna_config_selection = BT_LE_CS_TONE_ANTENNA_CONFIGURATION_A1_B1,
    				.phy = BT_LE_CS_PROCEDURE_PHY_1M,
    				.tx_power_delta = 0x80,
    				.preferred_peer_antenna = BT_LE_CS_PROCEDURE_PREFERRED_PEER_ANTENNA_1,
    				.snr_control_initiator = BT_LE_CS_SNR_CONTROL_NOT_USED,
    				.snr_control_reflector = BT_LE_CS_SNR_CONTROL_NOT_USED,
    			};
    			err = bt_le_cs_set_procedure_parameters(connections[i], &procedure_params);
    			if (err) {
    				LOG_ERR("Failed to set procedure parameters for %s", reflector_name);
    				return 0;
    			}
    
    			// Enable procedure
    			struct bt_le_cs_procedure_enable_param params = {
    				.config_id = CS_CONFIG_ID,
    				.enable = 1,
    			};
    			err = bt_le_cs_procedure_enable(connections[i], &params);
    			if (err) {
    				LOG_ERR("Failed to enable CS procedures for %s", reflector_name);
    				return 0;
    			}
    
    			////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    			/* Ranging estimates */
    
    			LOG_INF("Device %d: %s", device_nr, reflector_name);
    
    			for (int round = 0; round < RANGING_ROUNDS; round++) {
    				k_sleep(K_MSEC(500));
    
    				if (buffer_num_valid != 0) {
    					for (uint8_t ap = 0; ap < MAX_AP; ap++) {
    						cs_de_dist_estimates_t distance_on_ap = get_distance(ap);
    
    						LOG_INF("ifft: %f, phase_slope: %f, rtt: %f", 
    							(double)distance_on_ap.ifft,
    							(double)distance_on_ap.phase_slope,
    							(double)distance_on_ap.rtt);
    					}
    				}
    			}
    
    			/* for stable disconnection */
    			ranging_done = true;
    			bt_conn_disconnect(connections[i], BT_HCI_ERR_REMOTE_USER_TERM_CONN);
    			connections[i] = NULL; 
    
    			k_sem_take(&sem_ranging_done, K_FOREVER);
    			
    			ranging_done = false;
    		}
    	}
    }
    

Children
No Data
Related