blob: 0224e986ff4d6d05fb2a0320cc7f24abf35319e5 [file] [log] [blame]
/*
* Copyright (c) 2019-2020, Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/drivers/entropy.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include <hal/nrf_clock.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(test);
#define TEST_TIME_MS 10000
#define HF_STARTUP_TIME_US 400
static bool test_end;
static const struct device *const entropy = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy));
static const struct device *const clock_dev = DEVICE_DT_GET_ONE(nordic_nrf_clock);
static struct onoff_manager *hf_mgr;
static struct onoff_client cli;
static uint32_t iteration;
static void *setup(void)
{
zassert_true(device_is_ready(entropy));
zassert_true(device_is_ready(clock_dev));
hf_mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
zassert_true(hf_mgr);
return NULL;
}
static void bt_timeout_handler(struct k_timer *timer)
{
static bool on;
if (on) {
on = false;
z_nrf_clock_bt_ctlr_hf_release();
} else {
on = true;
z_nrf_clock_bt_ctlr_hf_request();
}
if (!(test_end && !on)) {
k_timeout_t timeout;
static bool long_timeout;
if (!on) {
timeout = K_USEC(200);
} else {
timeout = long_timeout ? K_USEC(300) : K_USEC(100);
long_timeout = !long_timeout;
}
k_timer_start(timer, timeout, K_NO_WAIT);
}
}
K_TIMER_DEFINE(timer1, bt_timeout_handler, NULL);
static void check_hf_status(const struct device *dev, bool exp_on,
bool sw_check)
{
nrf_clock_hfclk_t type;
nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_HFCLK, &type);
zassert_equal(type, exp_on ? NRF_CLOCK_HFCLK_HIGH_ACCURACY :
NRF_CLOCK_HFCLK_LOW_ACCURACY,
"%d: Clock expected to be %s",
iteration, exp_on ? "on" : "off");
if (sw_check) {
enum clock_control_status status =
clock_control_get_status(dev, CLOCK_CONTROL_NRF_SUBSYS_HF);
zassert_equal(status, exp_on ? CLOCK_CONTROL_STATUS_ON :
CLOCK_CONTROL_STATUS_OFF,
"%d: Unexpected status: %d", iteration, status);
}
}
/* Test controls HF clock from two contexts: thread and timer interrupt.
* In thread context clock is requested and released through standard onoff
* API and in the timeout handler it is requested and released using API
* dedicated to be used by Bluetooth Controller.
*
* Test runs in the loop to eventually lead to cases when clock controlling is
* preempted by timeout handler. At certain points clock status is validated.
*/
ZTEST(nrf_onoff_and_bt, test_onoff_interrupted)
{
uint64_t start_time = k_uptime_get();
uint64_t elapsed;
uint64_t checkpoint = 1000;
int err;
uint8_t rand;
int backoff;
iteration = 0;
test_end = false;
k_timer_start(&timer1, K_MSEC(1), K_NO_WAIT);
do {
iteration++;
err = entropy_get_entropy(entropy, &rand, 1);
zassert_equal(err, 0);
backoff = 3 * rand;
sys_notify_init_spinwait(&cli.notify);
err = onoff_request(hf_mgr, &cli);
zassert_true(err >= 0);
k_busy_wait(backoff);
if (backoff > HF_STARTUP_TIME_US) {
check_hf_status(clock_dev, true, true);
}
err = onoff_cancel_or_release(hf_mgr, &cli);
zassert_true(err >= 0);
elapsed = k_uptime_get() - start_time;
if (elapsed > checkpoint) {
printk("test continues\n");
checkpoint += 1000;
}
} while (elapsed <= TEST_TIME_MS);
test_end = true;
k_msleep(100);
check_hf_status(clock_dev, false, true);
}
static void onoff_timeout_handler(struct k_timer *timer)
{
static bool on;
static uint32_t cnt;
int err;
cnt++;
if (on) {
on = false;
err = onoff_cancel_or_release(hf_mgr, &cli);
zassert_true(err >= 0);
} else {
on = true;
sys_notify_init_spinwait(&cli.notify);
err = onoff_request(hf_mgr, &cli);
zassert_true(err >= 0, "%d: Unexpected err: %d", cnt, err);
}
if (!(test_end && !on)) {
k_timeout_t timeout;
static bool long_timeout;
if (!on) {
timeout = K_USEC(200);
} else {
timeout = long_timeout ? K_USEC(300) : K_USEC(100);
long_timeout = !long_timeout;
}
k_timer_start(timer, timeout, K_NO_WAIT);
}
}
K_TIMER_DEFINE(timer2, onoff_timeout_handler, NULL);
/* Test controls HF clock from two contexts: thread and timer interrupt.
* In thread context clock is requested and released through API
* dedicated to be used by Bluetooth Controller and in the timeout handler it is
* requested and released using standard onoffAPI .
*
* Test runs in the loop to eventually lead to cases when clock controlling is
* preempted by timeout handler. At certain points clock status is validated.
*/
ZTEST(nrf_onoff_and_bt, test_bt_interrupted)
{
uint64_t start_time = k_uptime_get();
uint64_t elapsed;
uint64_t checkpoint = 1000;
int err;
uint8_t rand;
int backoff;
iteration = 0;
test_end = false;
k_timer_start(&timer2, K_MSEC(1), K_NO_WAIT);
do {
iteration++;
err = entropy_get_entropy(entropy, &rand, 1);
zassert_equal(err, 0);
backoff = 3 * rand;
z_nrf_clock_bt_ctlr_hf_request();
k_busy_wait(backoff);
if (backoff > HF_STARTUP_TIME_US) {
check_hf_status(clock_dev, true, false);
}
z_nrf_clock_bt_ctlr_hf_release();
elapsed = k_uptime_get() - start_time;
if (elapsed > checkpoint) {
printk("test continues\n");
checkpoint += 1000;
}
} while (elapsed <= TEST_TIME_MS);
test_end = true;
k_msleep(100);
check_hf_status(clock_dev, false, true);
}
ZTEST_SUITE(nrf_onoff_and_bt, NULL, setup, NULL, NULL, NULL);