Since model struct most of member should not change at run time, so mark as const will be suitable and safely. Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
851 lines
23 KiB
C
851 lines
23 KiB
C
/*
|
|
* Copyright (c) 2021 Nordic Semiconductor
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
#include "mesh_test.h"
|
|
#include "mesh/net.h"
|
|
#include "mesh/access.h"
|
|
#include "mesh/foundation.h"
|
|
|
|
#define LOG_MODULE_NAME test_access
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
|
|
|
|
#define GROUP_ADDR 0xc000
|
|
#define UNICAST_ADDR1 0x0001
|
|
#define UNICAST_ADDR2 0x0006
|
|
#define WAIT_TIME 10 /*seconds*/
|
|
|
|
#define TEST_MODEL_ID_1 0x2a2a
|
|
#define TEST_MODEL_ID_2 0x2b2b
|
|
#define TEST_MODEL_ID_3 0x2c2c
|
|
#define TEST_MODEL_ID_4 0x2d2d
|
|
#define TEST_MODEL_ID_5 0x2e2e
|
|
|
|
#define TEST_MESSAGE_OP_1 BT_MESH_MODEL_OP_1(0x11)
|
|
#define TEST_MESSAGE_OP_2 BT_MESH_MODEL_OP_1(0x12)
|
|
#define TEST_MESSAGE_OP_3 BT_MESH_MODEL_OP_1(0x13)
|
|
#define TEST_MESSAGE_OP_4 BT_MESH_MODEL_OP_1(0x14)
|
|
#define TEST_MESSAGE_OP_5 BT_MESH_MODEL_OP_1(0x15)
|
|
#define TEST_MESSAGE_OP_F BT_MESH_MODEL_OP_1(0x1F)
|
|
|
|
#define PUB_PERIOD_COUNT 3
|
|
#define RX_JITTER_MAX (10 + CONFIG_BT_MESH_NETWORK_TRANSMIT_COUNT * \
|
|
(CONFIG_BT_MESH_NETWORK_TRANSMIT_INTERVAL + 10))
|
|
|
|
static int model1_init(const struct bt_mesh_model *model);
|
|
static int model2_init(const struct bt_mesh_model *model);
|
|
static int model3_init(const struct bt_mesh_model *model);
|
|
static int model4_init(const struct bt_mesh_model *model);
|
|
static int model5_init(const struct bt_mesh_model *model);
|
|
static int test_msg_handler(const struct bt_mesh_model *model,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf);
|
|
static int test_msg_ne_handler(const struct bt_mesh_model *model,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf);
|
|
|
|
struct k_poll_signal model_pub_signal;
|
|
|
|
static uint8_t dev_key[16] = { 0xdd };
|
|
static uint8_t app_key[16] = { 0xaa };
|
|
static uint8_t net_key[16] = { 0xcc };
|
|
static struct bt_mesh_prov prov;
|
|
|
|
/* Test vector for periodic publication tests. */
|
|
static const struct {
|
|
uint8_t period;
|
|
uint8_t div;
|
|
int32_t period_ms;
|
|
} test_period[] = {
|
|
{ BT_MESH_PUB_PERIOD_100MS(5), 0, 500 },
|
|
{ BT_MESH_PUB_PERIOD_SEC(2), 0, 2000 },
|
|
{ BT_MESH_PUB_PERIOD_10SEC(1), 0, 10000 },
|
|
{ BT_MESH_PUB_PERIOD_SEC(3), 1, 1500 },
|
|
{ BT_MESH_PUB_PERIOD_10SEC(3), 3, 3750 },
|
|
};
|
|
|
|
/* Test vector for publication retransmissions tests. */
|
|
static const uint8_t test_transmit[] = {
|
|
BT_MESH_PUB_TRANSMIT(4, 50),
|
|
BT_MESH_PUB_TRANSMIT(3, 100),
|
|
BT_MESH_PUB_TRANSMIT(2, 200),
|
|
};
|
|
|
|
/* Test vector for canceling a message publication. */
|
|
static const struct {
|
|
uint8_t period;
|
|
uint8_t transmit;
|
|
uint8_t msgs;
|
|
int32_t sleep;
|
|
int32_t duration;
|
|
} test_cancel[] = {
|
|
/* Test canceling periodic publication. */
|
|
{
|
|
BT_MESH_PUB_PERIOD_SEC(2), 0, 2,
|
|
2000 /* period */ + 100 /* margin */,
|
|
3 /* messages */ * 2000 /* period */
|
|
},
|
|
/* Test canceling publication retransmission. */
|
|
{
|
|
BT_MESH_PUB_PERIOD_SEC(3), BT_MESH_PUB_TRANSMIT(3, 200), 3,
|
|
200 /* retransmission interval */ + 50 /* margin */,
|
|
3000 /* one period */
|
|
},
|
|
};
|
|
|
|
static struct k_sem publish_sem;
|
|
static bool publish_allow;
|
|
|
|
static int model1_update(const struct bt_mesh_model *model)
|
|
{
|
|
model->pub->msg->data[1]++;
|
|
|
|
LOG_DBG("New pub: n: %d t: %d", model->pub->msg->data[1], k_uptime_get_32());
|
|
|
|
return publish_allow ? k_sem_give(&publish_sem), 0 : -1;
|
|
}
|
|
|
|
static int test_msgf_handler(const struct bt_mesh_model *model,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf)
|
|
{
|
|
static uint8_t prev_num;
|
|
uint8_t num = net_buf_simple_pull_u8(buf);
|
|
|
|
LOG_DBG("Recv msg: n: %d t: %u", num, k_uptime_get_32());
|
|
|
|
/* Ensure that payload changes. */
|
|
ASSERT_TRUE(prev_num != num);
|
|
prev_num = num;
|
|
|
|
k_sem_give(&publish_sem);
|
|
return 0;
|
|
}
|
|
|
|
static struct bt_mesh_model_pub model_pub1 = {
|
|
.msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX),
|
|
.update = model1_update,
|
|
};
|
|
|
|
static const struct bt_mesh_model_cb test_model1_cb = {
|
|
.init = model1_init,
|
|
};
|
|
|
|
static const struct bt_mesh_model_cb test_model2_cb = {
|
|
.init = model2_init,
|
|
};
|
|
|
|
static const struct bt_mesh_model_cb test_model3_cb = {
|
|
.init = model3_init,
|
|
};
|
|
|
|
static const struct bt_mesh_model_cb test_model4_cb = {
|
|
.init = model4_init,
|
|
};
|
|
|
|
static const struct bt_mesh_model_cb test_model5_cb = {
|
|
.init = model5_init,
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_op1[] = {
|
|
{ TEST_MESSAGE_OP_1, 0, test_msg_handler },
|
|
{ TEST_MESSAGE_OP_F, 0, test_msgf_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_op2[] = {
|
|
{ TEST_MESSAGE_OP_2, 0, test_msg_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_op3[] = {
|
|
{ TEST_MESSAGE_OP_3, 0, test_msg_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_op4[] = {
|
|
{ TEST_MESSAGE_OP_4, 0, test_msg_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_op5[] = {
|
|
{ TEST_MESSAGE_OP_5, 0, test_msg_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_ne_op1[] = {
|
|
{ TEST_MESSAGE_OP_1, 0, test_msg_ne_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_ne_op2[] = {
|
|
{ TEST_MESSAGE_OP_2, 0, test_msg_ne_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_ne_op3[] = {
|
|
{ TEST_MESSAGE_OP_3, 0, test_msg_ne_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_ne_op4[] = {
|
|
{ TEST_MESSAGE_OP_4, 0, test_msg_ne_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static const struct bt_mesh_model_op model_ne_op5[] = {
|
|
{ TEST_MESSAGE_OP_5, 0, test_msg_ne_handler },
|
|
BT_MESH_MODEL_OP_END
|
|
};
|
|
|
|
static struct bt_mesh_cfg_cli cfg_cli;
|
|
|
|
/* do not change model sequence. it will break pointer arithmetic. */
|
|
static const struct bt_mesh_model models[] = {
|
|
BT_MESH_MODEL_CFG_SRV,
|
|
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_1, model_op1, &model_pub1, NULL, &test_model1_cb),
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_2, model_op2, NULL, NULL, &test_model2_cb),
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_3, model_op3, NULL, NULL, &test_model3_cb),
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_4, model_op4, NULL, NULL, &test_model4_cb),
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_5, model_op5, NULL, NULL, &test_model5_cb),
|
|
};
|
|
|
|
/* do not change model sequence. it will break pointer arithmetic. */
|
|
static const struct bt_mesh_model models_ne[] = {
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_1, model_ne_op1, NULL, NULL, &test_model1_cb),
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_2, model_ne_op2, NULL, NULL, &test_model2_cb),
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_3, model_ne_op3, NULL, NULL, &test_model3_cb),
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_4, model_ne_op4, NULL, NULL, &test_model4_cb),
|
|
BT_MESH_MODEL_CB(TEST_MODEL_ID_5, model_ne_op5, NULL, NULL, &test_model5_cb),
|
|
};
|
|
|
|
static const struct bt_mesh_model vnd_models[] = {};
|
|
|
|
static struct bt_mesh_elem elems[] = {
|
|
BT_MESH_ELEM(0, models, vnd_models),
|
|
BT_MESH_ELEM(1, models_ne, vnd_models),
|
|
};
|
|
|
|
const struct bt_mesh_comp local_comp = {
|
|
.elem = elems,
|
|
.elem_count = ARRAY_SIZE(elems),
|
|
};
|
|
/* extension dependency (basic models are on top)
|
|
*
|
|
* element idx0 element idx1
|
|
*
|
|
* m1 m2 mne2 mne1
|
|
* / \ / | / \
|
|
* / \ / | / \
|
|
* m5 m3------->mne3 mne5
|
|
* | |
|
|
* m4 mne4
|
|
*/
|
|
|
|
static int model1_init(const struct bt_mesh_model *model)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int model2_init(const struct bt_mesh_model *model)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int model3_init(const struct bt_mesh_model *model)
|
|
{
|
|
ASSERT_OK(bt_mesh_model_extend(model, model - 2));
|
|
ASSERT_OK(bt_mesh_model_extend(model, model - 1));
|
|
|
|
if (*(model->elem_idx) == 1) {
|
|
ASSERT_OK(bt_mesh_model_extend(model, &models[4]));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int model4_init(const struct bt_mesh_model *model)
|
|
{
|
|
ASSERT_OK(bt_mesh_model_extend(model, model - 1));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int model5_init(const struct bt_mesh_model *model)
|
|
{
|
|
ASSERT_OK(bt_mesh_model_extend(model, model - 4));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_msg_handler(const struct bt_mesh_model *model,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf)
|
|
{
|
|
LOG_DBG("msg rx model id: %u", model->id);
|
|
k_poll_signal_raise(&model_pub_signal, model->id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int test_msg_ne_handler(const struct bt_mesh_model *model,
|
|
struct bt_mesh_msg_ctx *ctx,
|
|
struct net_buf_simple *buf)
|
|
{
|
|
FAIL("Model %#4x on neighbor element received msg", model->id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void provision(uint16_t addr)
|
|
{
|
|
int err;
|
|
|
|
err = bt_mesh_provision(net_key, 0, 0, 0, addr, dev_key);
|
|
if (err) {
|
|
FAIL("Provisioning failed (err %d)", err);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void common_configure(uint16_t addr)
|
|
{
|
|
uint8_t status;
|
|
int err;
|
|
uint16_t model_ids[] = {TEST_MODEL_ID_1, TEST_MODEL_ID_2,
|
|
TEST_MODEL_ID_3, TEST_MODEL_ID_4, TEST_MODEL_ID_5};
|
|
|
|
err = bt_mesh_cfg_cli_app_key_add(0, addr, 0, 0, app_key, &status);
|
|
if (err || status) {
|
|
FAIL("AppKey add failed (err %d, status %u)", err, status);
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(model_ids); i++) {
|
|
err = bt_mesh_cfg_cli_mod_app_bind(0, addr, addr, 0, model_ids[i], &status);
|
|
if (err || status) {
|
|
FAIL("Model %#4x bind failed (err %d, status %u)",
|
|
model_ids[i], err, status);
|
|
return;
|
|
}
|
|
|
|
err = bt_mesh_cfg_cli_mod_app_bind(0, addr, addr + 1, 0, model_ids[i], &status);
|
|
if (err || status) {
|
|
FAIL("Model %#4x bind failed (err %d, status %u)",
|
|
model_ids[i], err, status);
|
|
return;
|
|
}
|
|
}
|
|
|
|
err = bt_mesh_cfg_cli_net_transmit_set(0, addr, BT_MESH_TRANSMIT(2, 20), &status);
|
|
if (err || status != BT_MESH_TRANSMIT(2, 20)) {
|
|
FAIL("Net transmit set failed (err %d, status %u)", err,
|
|
status);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void subscription_configure(uint16_t addr)
|
|
{
|
|
uint8_t status;
|
|
int err;
|
|
|
|
err = bt_mesh_cfg_cli_mod_sub_add(0, addr, addr, GROUP_ADDR, TEST_MODEL_ID_2, &status);
|
|
|
|
if (err || status) {
|
|
FAIL("Model %#4x subscription configuration failed (err %d, status %u)",
|
|
TEST_MODEL_ID_2, err, status);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void test_tx_ext_model(void)
|
|
{
|
|
bt_mesh_test_cfg_set(NULL, WAIT_TIME);
|
|
bt_mesh_device_setup(&prov, &local_comp);
|
|
provision(UNICAST_ADDR1);
|
|
common_configure(UNICAST_ADDR1);
|
|
|
|
struct bt_mesh_msg_ctx ctx = {
|
|
.net_idx = 0,
|
|
.app_idx = 0,
|
|
.addr = GROUP_ADDR,
|
|
.send_rel = false,
|
|
.send_ttl = BT_MESH_TTL_DEFAULT,
|
|
};
|
|
BT_MESH_MODEL_BUF_DEFINE(msg, TEST_MESSAGE_OP_1, 0);
|
|
|
|
bt_mesh_model_msg_init(&msg, TEST_MESSAGE_OP_1);
|
|
bt_mesh_model_send(&models[2], &ctx, &msg, NULL, NULL);
|
|
|
|
bt_mesh_model_msg_init(&msg, TEST_MESSAGE_OP_2);
|
|
bt_mesh_model_send(&models[3], &ctx, &msg, NULL, NULL);
|
|
|
|
bt_mesh_model_msg_init(&msg, TEST_MESSAGE_OP_3);
|
|
bt_mesh_model_send(&models[4], &ctx, &msg, NULL, NULL);
|
|
|
|
bt_mesh_model_msg_init(&msg, TEST_MESSAGE_OP_4);
|
|
bt_mesh_model_send(&models[5], &ctx, &msg, NULL, NULL);
|
|
|
|
bt_mesh_model_msg_init(&msg, TEST_MESSAGE_OP_5);
|
|
bt_mesh_model_send(&models[6], &ctx, &msg, NULL, NULL);
|
|
|
|
PASS();
|
|
}
|
|
|
|
static void test_sub_ext_model(void)
|
|
{
|
|
k_poll_signal_init(&model_pub_signal);
|
|
|
|
struct k_poll_event events[1] = {
|
|
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
|
|
K_POLL_MODE_NOTIFY_ONLY, &model_pub_signal)
|
|
};
|
|
|
|
bt_mesh_test_cfg_set(NULL, WAIT_TIME);
|
|
bt_mesh_device_setup(&prov, &local_comp);
|
|
provision(UNICAST_ADDR2);
|
|
common_configure(UNICAST_ADDR2);
|
|
subscription_configure(UNICAST_ADDR2);
|
|
|
|
bool m1_fired = false;
|
|
bool m2_fired = false;
|
|
bool m3_fired = false;
|
|
bool m4_fired = false;
|
|
bool m5_fired = false;
|
|
|
|
while (!m1_fired || !m2_fired || !m3_fired || !m4_fired || !m5_fired) {
|
|
ASSERT_OK(k_poll(events, 1, K_SECONDS(3)));
|
|
|
|
switch (model_pub_signal.result) {
|
|
case TEST_MODEL_ID_1:
|
|
ASSERT_FALSE(m1_fired);
|
|
m1_fired = true;
|
|
break;
|
|
case TEST_MODEL_ID_2:
|
|
ASSERT_FALSE(m2_fired);
|
|
m2_fired = true;
|
|
break;
|
|
case TEST_MODEL_ID_3:
|
|
ASSERT_FALSE(m3_fired);
|
|
m3_fired = true;
|
|
break;
|
|
case TEST_MODEL_ID_4:
|
|
ASSERT_FALSE(m4_fired);
|
|
m4_fired = true;
|
|
break;
|
|
case TEST_MODEL_ID_5:
|
|
ASSERT_FALSE(m5_fired);
|
|
m5_fired = true;
|
|
break;
|
|
default:
|
|
FAIL();
|
|
break;
|
|
}
|
|
|
|
events[0].signal->signaled = 0;
|
|
events[0].state = K_POLL_STATE_NOT_READY;
|
|
}
|
|
|
|
|
|
PASS();
|
|
}
|
|
|
|
static void test_sub_capacity_ext_model(void)
|
|
{
|
|
bt_mesh_test_cfg_set(NULL, WAIT_TIME);
|
|
bt_mesh_device_setup(&prov, &local_comp);
|
|
provision(UNICAST_ADDR2);
|
|
common_configure(UNICAST_ADDR2);
|
|
|
|
uint8_t status;
|
|
int i;
|
|
|
|
/* Models in the extension linked list use the subscription list capacity of
|
|
* each other to the full extent. If a model cannot put a subscription address in
|
|
* its own subscription list it looks for the closest empty cell in model
|
|
* in the extension linked list.
|
|
*/
|
|
for (i = 0; i < 5 * CONFIG_BT_MESH_MODEL_GROUP_COUNT; i++) {
|
|
ASSERT_OK_MSG(bt_mesh_cfg_cli_mod_sub_add(0, UNICAST_ADDR2, UNICAST_ADDR2,
|
|
GROUP_ADDR + i, TEST_MODEL_ID_2, &status),
|
|
"Can't deliver subscription on address %#4x", GROUP_ADDR + i);
|
|
|
|
ASSERT_EQUAL(STATUS_SUCCESS, status);
|
|
}
|
|
|
|
uint16_t model_ids[] = {TEST_MODEL_ID_1, TEST_MODEL_ID_2,
|
|
TEST_MODEL_ID_3, TEST_MODEL_ID_4, TEST_MODEL_ID_5};
|
|
|
|
for (int j = 0; j < ARRAY_SIZE(model_ids); j++) {
|
|
ASSERT_OK_MSG(bt_mesh_cfg_cli_mod_sub_add(0, UNICAST_ADDR2, UNICAST_ADDR2,
|
|
GROUP_ADDR + i, model_ids[j], &status),
|
|
"Can't deliver subscription on address %#4x", GROUP_ADDR + i);
|
|
|
|
ASSERT_EQUAL(STATUS_INSUFF_RESOURCES, status);
|
|
}
|
|
|
|
PASS();
|
|
}
|
|
|
|
static void pub_param_set(uint8_t period, uint8_t transmit)
|
|
{
|
|
struct bt_mesh_cfg_cli_mod_pub pub_params = {
|
|
.addr = UNICAST_ADDR2,
|
|
.uuid = NULL,
|
|
.cred_flag = false,
|
|
.app_idx = 0,
|
|
.ttl = 5,
|
|
.period = period,
|
|
.transmit = transmit,
|
|
};
|
|
uint8_t status;
|
|
int err;
|
|
|
|
err = bt_mesh_cfg_cli_mod_pub_set(0, UNICAST_ADDR1, UNICAST_ADDR1, TEST_MODEL_ID_1,
|
|
&pub_params, &status);
|
|
if (err || status) {
|
|
FAIL("Mod pub set failed (err %d, status %u)", err, status);
|
|
}
|
|
}
|
|
|
|
static void msgf_publish(void)
|
|
{
|
|
const struct bt_mesh_model *model = &models[2];
|
|
|
|
bt_mesh_model_msg_init(model->pub->msg, TEST_MESSAGE_OP_F);
|
|
net_buf_simple_add_u8(model->pub->msg, 1);
|
|
bt_mesh_model_publish(model);
|
|
}
|
|
|
|
static void pub_jitter_check(int32_t interval, uint8_t count)
|
|
{
|
|
int64_t timestamp = k_uptime_get();
|
|
int32_t jitter = 0;
|
|
int err;
|
|
|
|
for (size_t j = 0; j < count; j++) {
|
|
/* Every new publication will release semaphore in the update handler and the time
|
|
* between two consecutive publications will be measured.
|
|
*/
|
|
err = k_sem_take(&publish_sem, K_SECONDS(20));
|
|
if (err) {
|
|
FAIL("Send timed out");
|
|
}
|
|
|
|
int32_t time_delta = k_uptime_delta(×tamp);
|
|
int32_t pub_delta = llabs(time_delta - interval);
|
|
|
|
jitter = MAX(pub_delta, jitter);
|
|
|
|
LOG_DBG("Send time: %d delta: %d jitter: %d", (int32_t)timestamp, time_delta,
|
|
jitter);
|
|
}
|
|
|
|
LOG_INF("Send jitter: %d", jitter);
|
|
ASSERT_TRUE(jitter <= 10);
|
|
}
|
|
|
|
static void recv_jitter_check(int32_t interval, uint8_t count)
|
|
{
|
|
int64_t timestamp;
|
|
uint32_t jitter = 0;
|
|
int err;
|
|
|
|
/* The measurement starts by the first received message. */
|
|
err = k_sem_take(&publish_sem, K_SECONDS(20));
|
|
if (err) {
|
|
FAIL("Recv timed out");
|
|
}
|
|
|
|
timestamp = k_uptime_get();
|
|
|
|
for (size_t j = 0; j < count; j++) {
|
|
/* Every new received message will release semaphore in the message handler and
|
|
* the time between two consecutive publications will be measured.
|
|
*/
|
|
err = k_sem_take(&publish_sem, K_SECONDS(20));
|
|
if (err) {
|
|
FAIL("Recv timed out");
|
|
}
|
|
|
|
int32_t time_delta = k_uptime_delta(×tamp);
|
|
int32_t pub_delta = llabs(time_delta - interval);
|
|
|
|
jitter = MAX(pub_delta, jitter);
|
|
|
|
LOG_DBG("Recv time: %d delta: %d jitter: %d", (int32_t)timestamp, time_delta,
|
|
jitter);
|
|
}
|
|
|
|
LOG_INF("Recv jitter: %d", jitter);
|
|
ASSERT_TRUE(jitter <= RX_JITTER_MAX);
|
|
}
|
|
|
|
/* Test publish period states by publishing a message and checking interval between update handler
|
|
* calls.
|
|
*/
|
|
static void test_tx_period(void)
|
|
{
|
|
const struct bt_mesh_model *model = &models[2];
|
|
|
|
bt_mesh_test_cfg_set(NULL, 60);
|
|
bt_mesh_device_setup(&prov, &local_comp);
|
|
provision(UNICAST_ADDR1);
|
|
common_configure(UNICAST_ADDR1);
|
|
|
|
k_sem_init(&publish_sem, 0, 1);
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(test_period); i++) {
|
|
pub_param_set(test_period[i].period, 0);
|
|
|
|
model->pub->fast_period = test_period[i].div > 0;
|
|
model->pub->period_div = test_period[i].div;
|
|
|
|
LOG_INF("Publication period: %d", test_period[i].period_ms);
|
|
|
|
/* Start publishing messages and measure jitter. */
|
|
msgf_publish();
|
|
publish_allow = true;
|
|
pub_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT);
|
|
|
|
/* Disable periodic publication before the next test iteration. */
|
|
publish_allow = false;
|
|
|
|
/* Let the receiver hit the first semaphore. */
|
|
k_sleep(K_SECONDS(1));
|
|
}
|
|
|
|
PASS();
|
|
}
|
|
|
|
/* Receive a periodically published message and check publication period by measuring interval
|
|
* between message handler calls.
|
|
*/
|
|
static void test_rx_period(void)
|
|
{
|
|
bt_mesh_test_cfg_set(NULL, 60);
|
|
bt_mesh_device_setup(&prov, &local_comp);
|
|
provision(UNICAST_ADDR2);
|
|
common_configure(UNICAST_ADDR2);
|
|
|
|
k_sem_init(&publish_sem, 0, 1);
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(test_period); i++) {
|
|
recv_jitter_check(test_period[i].period_ms, PUB_PERIOD_COUNT);
|
|
}
|
|
|
|
PASS();
|
|
}
|
|
|
|
/* Test publish retransmit interval and count states by publishing a message and checking interval
|
|
* between update handler calls.
|
|
*/
|
|
static void test_tx_transmit(void)
|
|
{
|
|
const struct bt_mesh_model *model = &models[2];
|
|
uint8_t status;
|
|
int err;
|
|
|
|
bt_mesh_test_cfg_set(NULL, 60);
|
|
bt_mesh_device_setup(&prov, &local_comp);
|
|
provision(UNICAST_ADDR1);
|
|
common_configure(UNICAST_ADDR1);
|
|
|
|
k_sem_init(&publish_sem, 0, 1);
|
|
|
|
/* Network retransmissions has to be disabled so that the legacy advertiser sleeps for the
|
|
* least possible time, which is 50ms. This will let the access layer publish a message
|
|
* with 50ms retransmission interval.
|
|
*/
|
|
err = bt_mesh_cfg_cli_net_transmit_set(0, UNICAST_ADDR1,
|
|
BT_MESH_TRANSMIT(0, CONFIG_BT_MESH_NETWORK_TRANSMIT_INTERVAL),
|
|
&status);
|
|
if (err || status != BT_MESH_TRANSMIT(0, CONFIG_BT_MESH_NETWORK_TRANSMIT_INTERVAL)) {
|
|
FAIL("Net transmit set failed (err %d, status %u)", err,
|
|
status);
|
|
}
|
|
|
|
publish_allow = true;
|
|
model->pub->retr_update = true;
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(test_transmit); i++) {
|
|
pub_param_set(0, test_transmit[i]);
|
|
|
|
int32_t interval = BT_MESH_PUB_TRANSMIT_INT(test_transmit[i]);
|
|
int count = BT_MESH_PUB_TRANSMIT_COUNT(test_transmit[i]);
|
|
|
|
LOG_INF("Retransmission interval: %d, count: %d", interval, count);
|
|
|
|
/* Start publishing messages and measure jitter. */
|
|
msgf_publish();
|
|
pub_jitter_check(interval, count);
|
|
|
|
/* Let the receiver hit the first semaphore. */
|
|
k_sleep(K_SECONDS(1));
|
|
}
|
|
|
|
PASS();
|
|
}
|
|
|
|
/* Receive a published message and check retransmission interval by measuring interval between
|
|
* message handler calls.
|
|
*/
|
|
static void test_rx_transmit(void)
|
|
{
|
|
bt_mesh_test_cfg_set(NULL, 60);
|
|
bt_mesh_device_setup(&prov, &local_comp);
|
|
provision(UNICAST_ADDR2);
|
|
common_configure(UNICAST_ADDR2);
|
|
|
|
k_sem_init(&publish_sem, 0, 1);
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(test_transmit); i++) {
|
|
int32_t interval = BT_MESH_PUB_TRANSMIT_INT(test_transmit[i]);
|
|
int count = BT_MESH_PUB_TRANSMIT_COUNT(test_transmit[i]);
|
|
|
|
recv_jitter_check(interval, count);
|
|
}
|
|
|
|
PASS();
|
|
}
|
|
|
|
/* Cancel one of messages to be published and check that the next one is published when next period
|
|
* starts.
|
|
*/
|
|
static void test_tx_cancel(void)
|
|
{
|
|
const struct bt_mesh_model *model = &models[2];
|
|
int err;
|
|
|
|
bt_mesh_test_cfg_set(NULL, 20);
|
|
bt_mesh_device_setup(&prov, &local_comp);
|
|
provision(UNICAST_ADDR1);
|
|
common_configure(UNICAST_ADDR1);
|
|
|
|
k_sem_init(&publish_sem, 0, 1);
|
|
|
|
model->pub->retr_update = true;
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(test_cancel); i++) {
|
|
pub_param_set(test_cancel[i].period, test_cancel[i].transmit);
|
|
|
|
msgf_publish();
|
|
publish_allow = true;
|
|
int64_t timestamp = k_uptime_get();
|
|
|
|
/* Send few messages except one that is to be cancelled. */
|
|
for (size_t j = 0; j < test_cancel[i].msgs - 1; j++) {
|
|
err = k_sem_take(&publish_sem, K_SECONDS(20));
|
|
if (err) {
|
|
FAIL("Send timed out");
|
|
}
|
|
}
|
|
|
|
/* Cancel the next publication. */
|
|
publish_allow = false;
|
|
k_sleep(K_MSEC(test_cancel[i].sleep));
|
|
|
|
/* Reenable publication a wait for a next message to be published. */
|
|
publish_allow = true;
|
|
err = k_sem_take(&publish_sem, K_SECONDS(20));
|
|
if (err) {
|
|
FAIL("Send timed out");
|
|
}
|
|
|
|
/* Disable periodic publication before the next test iteration. */
|
|
publish_allow = false;
|
|
|
|
/* If the canceled message is also sent, the semaphore will be released earlier than
|
|
* expected.
|
|
*/
|
|
int32_t time_delta = k_uptime_delta(×tamp);
|
|
int32_t jitter = llabs(time_delta - test_cancel[i].duration);
|
|
|
|
LOG_DBG("Send time: %d delta: %d", (int32_t)timestamp, time_delta);
|
|
LOG_INF("Send jitter: %d", jitter);
|
|
ASSERT_TRUE(jitter <= 10);
|
|
|
|
/* Let the receiver hit the first semaphore. */
|
|
k_sleep(K_SECONDS(1));
|
|
}
|
|
|
|
PASS();
|
|
}
|
|
|
|
/* Receive all published messages and ensure that cancelled message is not received. */
|
|
static void test_rx_cancel(void)
|
|
{
|
|
bt_mesh_test_cfg_set(NULL, 20);
|
|
bt_mesh_device_setup(&prov, &local_comp);
|
|
provision(UNICAST_ADDR2);
|
|
common_configure(UNICAST_ADDR2);
|
|
|
|
k_sem_init(&publish_sem, 0, 1);
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(test_cancel); i++) {
|
|
int64_t timestamp;
|
|
int err;
|
|
|
|
/* Wait for the first published message. */
|
|
err = k_sem_take(&publish_sem, K_SECONDS(20));
|
|
if (err) {
|
|
FAIL("Recv timed out");
|
|
}
|
|
|
|
timestamp = k_uptime_get();
|
|
|
|
/* Wait for the rest messages to be published (incl. the next after cancelled one).
|
|
*/
|
|
for (size_t j = 0; j < test_cancel[i].msgs; j++) {
|
|
err = k_sem_take(&publish_sem, K_SECONDS(20));
|
|
if (err) {
|
|
FAIL("Recv timed out");
|
|
}
|
|
}
|
|
|
|
/* If the canceled message is received, the semaphore will be released earlier than
|
|
* expected.
|
|
*/
|
|
int32_t time_delta = k_uptime_delta(×tamp);
|
|
int32_t jitter = llabs(time_delta - test_cancel[i].duration);
|
|
|
|
LOG_DBG("Recv time: %d delta: %d", (int32_t)timestamp, time_delta);
|
|
LOG_INF("Recv jitter: %d", jitter);
|
|
ASSERT_TRUE(jitter <= RX_JITTER_MAX);
|
|
}
|
|
|
|
PASS();
|
|
}
|
|
|
|
#define TEST_CASE(role, name, description) \
|
|
{ \
|
|
.test_id = "access_" #role "_" #name, \
|
|
.test_descr = description, \
|
|
.test_tick_f = bt_mesh_test_timeout, \
|
|
.test_main_f = test_##role##_##name, \
|
|
}
|
|
|
|
static const struct bst_test_instance test_access[] = {
|
|
TEST_CASE(tx, ext_model, "Access: tx data of extended models"),
|
|
TEST_CASE(sub, ext_model, "Access: data subscription of extended models"),
|
|
TEST_CASE(sub_capacity, ext_model, "Access: subscription capacity of extended models"),
|
|
TEST_CASE(tx, period, "Access: Publish a message periodically"),
|
|
TEST_CASE(rx, period, "Access: Receive periodically published message"),
|
|
TEST_CASE(tx, transmit, "Access: Publish and retransmit message"),
|
|
TEST_CASE(rx, transmit, "Access: Receive retransmitted messages"),
|
|
TEST_CASE(tx, cancel, "Access: Cancel a message during publication"),
|
|
TEST_CASE(rx, cancel, "Access: Receive published messages except cancelled"),
|
|
|
|
BSTEST_END_MARKER
|
|
};
|
|
|
|
struct bst_test_list *test_access_install(struct bst_test_list *tests)
|
|
{
|
|
tests = bst_add_tests(tests, test_access);
|
|
return tests;
|
|
}
|