From 0d71cef1f205a209f316ff712b5fdce1c29b195c Mon Sep 17 00:00:00 2001 From: Mariusz Skamra Date: Wed, 27 Dec 2017 20:26:50 +0100 Subject: [PATCH] Bluetooth: tester: Add BTP Mesh Model Send command implementation This command will be used to test if model can properly send segmented and unsegmented messages to a given destination address. Signed-off-by: Mariusz Skamra --- include/bluetooth/testing.h | 4 + subsys/bluetooth/host/mesh/cfg_srv.c | 10 +++ subsys/bluetooth/host/testing.c | 27 +++++++ subsys/bluetooth/host/testing.h | 15 ++++ tests/bluetooth/tester/btp_spec.txt | 11 +++ tests/bluetooth/tester/src/bttester.h | 8 ++ tests/bluetooth/tester/src/mesh.c | 106 +++++++++++++++++++++++++- 7 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 subsys/bluetooth/host/testing.h diff --git a/include/bluetooth/testing.h b/include/bluetooth/testing.h index 6b32c77c34e..7159a9e641c 100644 --- a/include/bluetooth/testing.h +++ b/include/bluetooth/testing.h @@ -30,6 +30,10 @@ extern "C" { struct bt_test_cb { void (*mesh_net_recv)(u8_t ttl, u8_t ctl, u16_t src, u16_t dst, const void *payload, size_t payload_len); + void (*mesh_model_bound)(u16_t addr, struct bt_mesh_model *model, + u16_t key_idx); + void (*mesh_model_unbound)(u16_t addr, struct bt_mesh_model *model, + u16_t key_idx); sys_snode_t node; }; diff --git a/subsys/bluetooth/host/mesh/cfg_srv.c b/subsys/bluetooth/host/mesh/cfg_srv.c index 456ddad2c48..e7e33e181e4 100644 --- a/subsys/bluetooth/host/mesh/cfg_srv.c +++ b/subsys/bluetooth/host/mesh/cfg_srv.c @@ -21,6 +21,8 @@ #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_MODEL) #include "common/log.h" +#include "../testing.h" + #include "mesh.h" #include "adv.h" #include "net.h" @@ -2305,6 +2307,10 @@ static void mod_app_bind(struct bt_mesh_model *model, status = mod_bind(mod, key_app_idx); + if (IS_ENABLED(CONFIG_BT_TESTING) && status == STATUS_SUCCESS) { + bt_test_mesh_model_bound(ctx->addr, mod, key_app_idx); + } + send_status: BT_DBG("status 0x%02x", status); create_mod_app_status(msg, mod, vnd, elem_addr, key_app_idx, status, @@ -2346,6 +2352,10 @@ static void mod_app_unbind(struct bt_mesh_model *model, status = mod_unbind(mod, key_app_idx); + if (IS_ENABLED(CONFIG_BT_TESTING) && status == STATUS_SUCCESS) { + bt_test_mesh_model_unbound(ctx->addr, mod, key_app_idx); + } + send_status: BT_DBG("status 0x%02x", status); create_mod_app_status(msg, mod, vnd, elem_addr, key_app_idx, status, diff --git a/subsys/bluetooth/host/testing.c b/subsys/bluetooth/host/testing.c index f3a636cbf71..3e5dc596811 100644 --- a/subsys/bluetooth/host/testing.c +++ b/subsys/bluetooth/host/testing.c @@ -7,8 +7,11 @@ #include #include +#include #include +#include "testing.h" + static sys_slist_t cb_slist; void bt_test_cb_register(struct bt_test_cb *cb) @@ -33,3 +36,27 @@ void bt_test_mesh_net_recv(u8_t ttl, u8_t ctl, u16_t src, u16_t dst, } } } + +void bt_test_mesh_model_bound(u16_t addr, struct bt_mesh_model *model, + u16_t key_idx) +{ + struct bt_test_cb *cb; + + SYS_SLIST_FOR_EACH_CONTAINER(&cb_slist, cb, node) { + if (cb->mesh_model_bound) { + cb->mesh_model_bound(addr, model, key_idx); + } + } +} + +void bt_test_mesh_model_unbound(u16_t addr, struct bt_mesh_model *model, + u16_t key_idx) +{ + struct bt_test_cb *cb; + + SYS_SLIST_FOR_EACH_CONTAINER(&cb_slist, cb, node) { + if (cb->mesh_model_unbound) { + cb->mesh_model_unbound(addr, model, key_idx); + } + } +} diff --git a/subsys/bluetooth/host/testing.h b/subsys/bluetooth/host/testing.h new file mode 100644 index 00000000000..9474985f4b2 --- /dev/null +++ b/subsys/bluetooth/host/testing.h @@ -0,0 +1,15 @@ +/** + * @file testing.h + * @brief Internal API for Bluetooth testing. + */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +void bt_test_mesh_model_bound(u16_t addr, struct bt_mesh_model *model, + u16_t key_idx); +void bt_test_mesh_model_unbound(u16_t addr, struct bt_mesh_model *model, + u16_t key_idx); diff --git a/tests/bluetooth/tester/btp_spec.txt b/tests/bluetooth/tester/btp_spec.txt index 798047bea85..a5c7ad9595a 100644 --- a/tests/bluetooth/tester/btp_spec.txt +++ b/tests/bluetooth/tester/btp_spec.txt @@ -1507,6 +1507,17 @@ Commands and responses: In case of an error, the error response will be returned. + Opcode 0x0f - Model Send + Controller Index: + Command parameters: SRC (2 octets) + DST (2 octets) + Payload_Len (1 octet) + Payload (variable) + + This command is used to send Mesh model message. + + In case of an error, the error response will be returned. + Events: Opcode 0x80 - Output number action Event diff --git a/tests/bluetooth/tester/src/bttester.h b/tests/bluetooth/tester/src/bttester.h index 3e59a92dfc7..32e63e10135 100644 --- a/tests/bluetooth/tester/src/bttester.h +++ b/tests/bluetooth/tester/src/bttester.h @@ -747,6 +747,14 @@ struct mesh_lpn_set_cmd { #define MESH_LPN_POLL 0x0e +#define MESH_MODEL_SEND 0x0f +struct mesh_model_send_cmd { + u16_t src; + u16_t dst; + u8_t payload_len; + u8_t payload[0]; +} __packed; + /* events */ #define MESH_EV_OUT_NUMBER_ACTION 0x80 struct mesh_out_number_action_ev { diff --git a/tests/bluetooth/tester/src/mesh.c b/tests/bluetooth/tester/src/mesh.c index b277e3d8172..09ee964c2e8 100644 --- a/tests/bluetooth/tester/src/mesh.c +++ b/tests/bluetooth/tester/src/mesh.c @@ -41,6 +41,15 @@ static u8_t static_auth[16]; /* Vendor Model data */ #define VND_MODEL_ID_1 0x1234 +/* Model send data */ +#define MODEL_BOUNDS_MAX 2 + +static struct model_data { + struct bt_mesh_model *model; + u16_t addr; + u16_t appkey_idx; +} model_bound[MODEL_BOUNDS_MAX]; + static struct { u16_t local; u16_t dst; @@ -66,7 +75,6 @@ static void supported_commands(u8_t *data, u16_t len) tester_set_bit(buf->data, MESH_INPUT_NUMBER); tester_set_bit(buf->data, MESH_INPUT_STRING); /* 2nd octet */ - memset(net_buf_simple_add(buf, 1), 0, 1); tester_set_bit(buf->data, MESH_IVU_TEST_MODE); tester_set_bit(buf->data, MESH_IVU_TOGGLE_STATE); tester_set_bit(buf->data, MESH_NET_SEND); @@ -74,6 +82,7 @@ static void supported_commands(u8_t *data, u16_t len) tester_set_bit(buf->data, MESH_HEALTH_CLEAR_FAULTS); tester_set_bit(buf->data, MESH_LPN); tester_set_bit(buf->data, MESH_LPN_POLL); + tester_set_bit(buf->data, MESH_MODEL_SEND); tester_send(BTP_SERVICE_ID_MESH, MESH_READ_SUPPORTED_COMMANDS, CONTROLLER_INDEX, buf->data, buf->len); @@ -602,6 +611,54 @@ static void health_clear_faults(u8_t *data, u16_t len) CONTROLLER_INDEX, BTP_STATUS_SUCCESS); } +static void model_send(u8_t *data, u16_t len) +{ + struct mesh_model_send_cmd *cmd = (void *) data; + struct net_buf_simple *msg = NET_BUF_SIMPLE(UINT8_MAX); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net.net_idx, + .app_idx = BT_MESH_KEY_DEV, + .addr = sys_le16_to_cpu(cmd->dst), + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct bt_mesh_model *model = NULL; + int err, i; + u16_t src = sys_le16_to_cpu(cmd->src); + + /* Lookup source address */ + for (i = 0; i < ARRAY_SIZE(model_bound); i++) { + if (model_bound[i].model->elem->addr == src) { + model = model_bound[i].model; + ctx.app_idx = model_bound[i].appkey_idx; + + break; + } + } + + if (!model) { + SYS_LOG_ERR("Model not found"); + err = -EINVAL; + + goto fail; + } + + SYS_LOG_DBG("src 0x%04x dst 0x%04x model %p payload_len %d", src, + ctx.addr, model, cmd->payload_len); + + net_buf_simple_init(msg, 0); + + net_buf_simple_add_mem(msg, cmd->payload, cmd->payload_len); + + err = bt_mesh_model_send(model, &ctx, msg, NULL, NULL); + if (err) { + SYS_LOG_ERR("Failed to send (err %d)", err); + } + +fail: + tester_rsp(BTP_SERVICE_ID_MESH, MESH_MODEL_SEND, CONTROLLER_INDEX, + err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); +} + void tester_handle_mesh(u8_t opcode, u8_t index, u8_t *data, u16_t len) { switch (opcode) { @@ -647,6 +704,9 @@ void tester_handle_mesh(u8_t opcode, u8_t index, u8_t *data, u16_t len) case MESH_HEALTH_CLEAR_FAULTS: health_clear_faults(data, len); break; + case MESH_MODEL_SEND: + model_send(data, len); + break; default: tester_rsp(BTP_SERVICE_ID_MESH, opcode, index, BTP_STATUS_UNKNOWN_CMD); @@ -683,8 +743,52 @@ void net_recv_ev(u8_t ttl, u8_t ctl, u16_t src, u16_t dst, const void *payload, buf->data, buf->len); } +static void model_bound_cb(u16_t addr, struct bt_mesh_model *model, + u16_t key_idx) +{ + int i; + + SYS_LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p", + addr, key_idx, model); + + for (i = 0; i < ARRAY_SIZE(model_bound); i++) { + if (!model_bound[i].model) { + model_bound[i].model = model; + model_bound[i].addr = addr; + model_bound[i].appkey_idx = key_idx; + + return; + } + } + + SYS_LOG_ERR("model_bound is full"); +} + +static void model_unbound_cb(u16_t addr, struct bt_mesh_model *model, + u16_t key_idx) +{ + int i; + + SYS_LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p", + addr, key_idx, model); + + for (i = 0; i < ARRAY_SIZE(model_bound); i++) { + if (model_bound[i].model == model) { + model_bound[i].model = NULL; + model_bound[i].addr = 0x0000; + model_bound[i].appkey_idx = BT_MESH_KEY_UNUSED; + + return; + } + } + + SYS_LOG_INF("model not found"); +} + static struct bt_test_cb bt_test_cb = { .mesh_net_recv = net_recv_ev, + .mesh_model_bound = model_bound_cb, + .mesh_model_unbound = model_unbound_cb, }; u8_t tester_init_mesh(void)