Skip to content

Commit 8aac9df

Browse files
eriksandgrennordicjm
authored andcommitted
bluetooth: cs_de: Add basic UTs for cs_de
This commit adds unittests for the cs_de module. Three unittests are added for the `cs_de_calc` function: `test_cs_de_calc_empty_report` and `test_cs_de_calc_bad_tone_quality` tests that the returned result is `CS_DE_QUALITY_DO_NOT_USE` when the input is empty or has bad tone quality. `test_cs_de_calc_with_ideal_iq_data` tests that given ideal measurement data (which is generated by the UT itself) the `cs_de_calc` function can estimate the correct distance using both `ifft` and `phase_slope` algorithm. Signed-off-by: Erik Sandgren <[email protected]>
1 parent c9703ab commit 8aac9df

File tree

6 files changed

+169
-0
lines changed

6 files changed

+169
-0
lines changed

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,7 @@
910910
/tests/subsys/audio/audio_module_template/ @nrfconnect/ncs-audio
911911
/tests/subsys/audio_module/ @nrfconnect/ncs-audio
912912
/tests/subsys/bluetooth/controller/ @nrfconnect/ncs-dragoon
913+
/tests/subsys/bluetooth/cs_de/ @nrfconnect/ncs-dragoon
913914
/tests/subsys/bluetooth/gatt_dm/ @nrfconnect/ncs-si-muffin
914915
/tests/subsys/bluetooth/enocean/ @nrfconnect/ncs-paladin
915916
/tests/subsys/bluetooth/fast_pair/ @nrfconnect/ncs-si-bluebagel

scripts/ci/tags.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,11 @@ ci_tests_subsys_bluetooth_controller:
888888
- nrf/subsys/bluetooth/controller/
889889
- nrf/tests/subsys/bluetooth/controller/
890890

891+
ci_tests_subsys_bluetooth_cs_de:
892+
files:
893+
- nrf/subsys/bluetooth/cs_de/
894+
- nrf/tests/subsys/bluetooth/cs_de/
895+
891896
ci_tests_subsys_mpsl:
892897
files:
893898
- nrf/subsys/mpsl/
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
project(cs_de_test)
11+
12+
# Generate runner for the test
13+
test_runner_generate(src/cs_de_test.c)
14+
# Add test source file
15+
target_sources(app PRIVATE src/cs_de_test.c)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
# Enable Unity testing framework
8+
CONFIG_UNITY=y
9+
10+
# Enable Bluetooth support
11+
CONFIG_BT=y
12+
CONFIG_BT_HCI=y
13+
CONFIG_BT_CENTRAL=y
14+
15+
# Enable Bluetooth Channel Sounding
16+
CONFIG_BT_CHANNEL_SOUNDING=y
17+
18+
# Enable CS Distance Estimation
19+
CONFIG_BT_CS_DE=y
20+
CONFIG_BT_CS_DE_LOG_LEVEL_INF=y
21+
22+
# Enable RAS service
23+
CONFIG_BT_RAS=y
24+
CONFIG_BT_RAS_RREQ=y
25+
CONFIG_BT_RAS_MAX_ANTENNA_PATHS=4
26+
# Enable FPU support for float operations
27+
CONFIG_FPU=y
28+
29+
# Increase stack sizes for floating point operations
30+
CONFIG_MAIN_STACK_SIZE=4096
31+
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include <unity.h>
8+
#include <stdbool.h>
9+
#include <string.h>
10+
#include <math.h>
11+
12+
#include <bluetooth/cs_de.h>
13+
14+
#define NUM_CHANNELS (75)
15+
#define CHANNEL_SPACING_HZ (1e6f)
16+
#define PI (3.14159265358979f)
17+
#define SPEED_OF_LIGHT_M_PER_S (299792458.0f)
18+
19+
/* The unity_main is not declared in any header file. It is only defined in the generated test
20+
* runner because of ncs' unity configuration. It is therefore declared here to avoid a compiler
21+
* warning.
22+
*/
23+
extern int unity_main(void);
24+
25+
/* Generate ideal IQ data for a given distance in meters.*/
26+
static void generate_ideal_iq_data(float distance, cs_de_iq_tones_t *iq_tones)
27+
{
28+
float rotation_per_channel =
29+
2 * PI * CHANNEL_SPACING_HZ * distance / SPEED_OF_LIGHT_M_PER_S;
30+
for (int i = 0; i < NUM_CHANNELS; i++) {
31+
iq_tones->i_local[i] = 100 * cosf(-rotation_per_channel * i);
32+
iq_tones->q_local[i] = 100 * sinf(-rotation_per_channel * i);
33+
iq_tones->i_remote[i] = 100 * cosf(-rotation_per_channel * i);
34+
iq_tones->q_remote[i] = 100 * sinf(-rotation_per_channel * i);
35+
}
36+
}
37+
38+
void test_cs_de_calc_empty_report(void)
39+
{
40+
cs_de_report_t test_report;
41+
cs_de_quality_t result;
42+
43+
/* Setup: Initialize report with no antenna paths */
44+
test_report.n_ap = 0;
45+
46+
/* Execute */
47+
result = cs_de_calc(&test_report);
48+
49+
/* Verify: Should return DO_NOT_USE quality */
50+
TEST_ASSERT_EQUAL(CS_DE_QUALITY_DO_NOT_USE, result);
51+
}
52+
53+
void test_cs_de_calc_bad_tone_quality(void)
54+
{
55+
cs_de_report_t test_report;
56+
cs_de_quality_t result;
57+
/* Setup: Initialize report with 1 antenna path but bad tone quality */
58+
test_report.n_ap = 1;
59+
test_report.tone_quality[0] = CS_DE_TONE_QUALITY_BAD;
60+
61+
/* Execute */
62+
result = cs_de_calc(&test_report);
63+
64+
/* Verify: Should return DO_NOT_USE quality due to bad tone quality */
65+
TEST_ASSERT_EQUAL(CS_DE_QUALITY_DO_NOT_USE, result);
66+
}
67+
68+
void test_cs_de_calc_with_ideal_iq_data(void)
69+
{
70+
for (uint8_t n_ap = 1; n_ap <= CONFIG_BT_RAS_MAX_ANTENNA_PATHS; n_ap++) {
71+
for (float distance = 0.0f; distance < 74.5f; distance += 0.1f) {
72+
cs_de_report_t test_report;
73+
cs_de_quality_t result;
74+
75+
test_report.n_ap = n_ap;
76+
77+
for (uint8_t ap = 0; ap < n_ap; ap++) {
78+
test_report.tone_quality[ap] = CS_DE_TONE_QUALITY_OK;
79+
generate_ideal_iq_data(distance, &test_report.iq_tones[ap]);
80+
}
81+
82+
result = cs_de_calc(&test_report);
83+
TEST_ASSERT_TRUE(result == CS_DE_QUALITY_OK);
84+
85+
for (uint8_t ap = 0; ap < n_ap; ap++) {
86+
/* Verify that the estimated distance is within 1 cm of the distance
87+
* used to generate the ideal IQ data.
88+
*/
89+
TEST_ASSERT_FLOAT_WITHIN(0.01f,
90+
distance,
91+
test_report.distance_estimates[ap].ifft);
92+
TEST_ASSERT_FLOAT_WITHIN(0.01f,
93+
distance,
94+
test_report.distance_estimates[ap].phase_slope);
95+
TEST_ASSERT_EQUAL_FLOAT(test_report.distance_estimates[ap].ifft,
96+
test_report.distance_estimates[ap].best);
97+
}
98+
}
99+
}
100+
}
101+
102+
/* Main test entry point */
103+
int main(void)
104+
{
105+
(void)unity_main();
106+
107+
return 0;
108+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tests:
2+
subsys.bluetooth.cs_de:
3+
platform_allow:
4+
- native_sim
5+
integration_platforms:
6+
- native_sim
7+
tags:
8+
- unittest
9+
- ci_tests_subsys_bluetooth_cs_de

0 commit comments

Comments
 (0)