From a94c7e3a23fc1225aec9f13c1e37cc2853f70c82 Mon Sep 17 00:00:00 2001 From: Pavel Vasilyev Date: Wed, 24 Mar 2021 17:38:03 +0100 Subject: [PATCH] Bluetooth: Mesh: Introduce acknowledged message API The implementation of blocking calls is common for all the client models. This change reduces the code duplication by introducing new API that helps to manage acknowledged messages. Signed-off-by: Pavel Vasilyev --- doc/reference/bluetooth/mesh.rst | 1 + doc/reference/bluetooth/mesh/msg.rst | 14 ++ include/bluetooth/mesh.h | 1 + include/bluetooth/mesh/access.h | 87 -------- include/bluetooth/mesh/cfg_cli.h | 5 +- include/bluetooth/mesh/health_cli.h | 4 +- include/bluetooth/mesh/msg.h | 226 ++++++++++++++++++++ subsys/bluetooth/mesh/CMakeLists.txt | 1 + subsys/bluetooth/mesh/access.c | 25 --- subsys/bluetooth/mesh/cfg_cli.c | 301 ++++++++++++--------------- subsys/bluetooth/mesh/health_cli.c | 106 ++++------ subsys/bluetooth/mesh/msg.c | 84 ++++++++ 12 files changed, 494 insertions(+), 361 deletions(-) create mode 100644 doc/reference/bluetooth/mesh/msg.rst create mode 100644 include/bluetooth/mesh/msg.h create mode 100644 subsys/bluetooth/mesh/msg.c diff --git a/doc/reference/bluetooth/mesh.rst b/doc/reference/bluetooth/mesh.rst index c131fadd4cb..d22ad0ecbc0 100644 --- a/doc/reference/bluetooth/mesh.rst +++ b/doc/reference/bluetooth/mesh.rst @@ -16,6 +16,7 @@ Read more about Bluetooth Mesh on the mesh/core.rst mesh/access.rst mesh/models.rst + mesh/msg.rst mesh/provisioning.rst mesh/proxy.rst mesh/heartbeat.rst diff --git a/doc/reference/bluetooth/mesh/msg.rst b/doc/reference/bluetooth/mesh/msg.rst new file mode 100644 index 00000000000..8f0acd6b83d --- /dev/null +++ b/doc/reference/bluetooth/mesh/msg.rst @@ -0,0 +1,14 @@ +.. _bluetooth_mesh_msg: + +Message API +########### + +The Bluetooth Mesh message API provides set of structures, macros and functions +used for preparing message buffers, managing message and acknowledged message contexts. + +API reference +************* + +.. doxygengroup:: bt_mesh_msg + :project: Zephyr + :members: diff --git a/include/bluetooth/mesh.h b/include/bluetooth/mesh.h index 48797e37cd9..49d42ce7ed9 100644 --- a/include/bluetooth/mesh.h +++ b/include/bluetooth/mesh.h @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/include/bluetooth/mesh/access.h b/include/bluetooth/mesh/access.h index 493bbfc5cbd..47e6ddbd917 100644 --- a/include/bluetooth/mesh/access.h +++ b/include/bluetooth/mesh/access.h @@ -160,33 +160,6 @@ struct bt_mesh_elem { #define BT_MESH_MODEL_ID_LIGHT_LC_SETUPSRV 0x1310 #define BT_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 -/** Message sending context. */ -struct bt_mesh_msg_ctx { - /** NetKey Index of the subnet to send the message on. */ - uint16_t net_idx; - - /** AppKey Index to encrypt the message with. */ - uint16_t app_idx; - - /** Remote address. */ - uint16_t addr; - - /** Destination address of a received message. Not used for sending. */ - uint16_t recv_dst; - - /** RSSI of received packet. Not used for sending. */ - int8_t recv_rssi; - - /** Received TTL value. Not used for sending. */ - uint8_t recv_ttl; - - /** Force sending reliably by using segment acknowledgement */ - bool send_rel; - - /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ - uint8_t send_ttl; -}; - /** Model opcode handler. */ struct bt_mesh_model_op { /** OpCode encoded using the BT_MESH_MODEL_OP_* macros */ @@ -220,56 +193,6 @@ struct bt_mesh_model_op { /** Helper to define an empty model array */ #define BT_MESH_MODEL_NONE ((struct bt_mesh_model []){}) -/** Length of a short Mesh MIC. */ -#define BT_MESH_MIC_SHORT 4 -/** Length of a long Mesh MIC. */ -#define BT_MESH_MIC_LONG 8 - -/** @def BT_MESH_MODEL_OP_LEN - * - * @brief Helper to determine the length of an opcode. - * - * @param _op Opcode. - */ -#define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3) - -/** @def BT_MESH_MODEL_BUF_LEN - * - * @brief Helper for model message buffer length. - * - * Returns the length of a Mesh model message buffer, including the opcode - * length and a short MIC. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model payload. - */ -#define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \ - (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT) - -/** @def BT_MESH_MODEL_BUF_LEN_LONG_MIC - * - * @brief Helper for model message buffer length. - * - * Returns the length of a Mesh model message buffer, including the opcode - * length and a long MIC. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model payload. - */ -#define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \ - (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG) - -/** @def BT_MESH_MODEL_BUF_DEFINE - * - * @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE_DEFINE. - * - * @param _buf Buffer name. - * @param _op Opcode of the message. - * @param _payload_len Length of the model message payload. - */ -#define BT_MESH_MODEL_BUF_DEFINE(_buf, _op, _payload_len) \ - NET_BUF_SIMPLE_DEFINE(_buf, BT_MESH_MODEL_BUF_LEN(_op, (_payload_len))) - /** @def BT_MESH_MODEL_CB * * @brief Composition data SIG model entry with callback functions. @@ -600,16 +523,6 @@ struct bt_mesh_send_cb { }; -/** @brief Initialize a model message. - * - * Clears the message buffer contents, and encodes the given opcode. - * The message buffer will be ready for filling in payload data. - * - * @param msg Message buffer. - * @param opcode Opcode to encode. - */ -void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode); - /** Special TTL value to request using configured default TTL */ #define BT_MESH_TTL_DEFAULT 0xff diff --git a/include/bluetooth/mesh/cfg_cli.h b/include/bluetooth/mesh/cfg_cli.h index 1618c4f41d3..0658e21fb37 100644 --- a/include/bluetooth/mesh/cfg_cli.h +++ b/include/bluetooth/mesh/cfg_cli.h @@ -27,10 +27,7 @@ struct bt_mesh_cfg_cli { struct bt_mesh_model *model; /* Internal parameters for tracking message responses. */ - struct k_sem op_sync; - uint32_t op_pending; - void *op_param; - uint16_t op_addr; + struct bt_mesh_msg_ack_ctx ack_ctx; }; /** @def BT_MESH_MODEL_CFG_CLI diff --git a/include/bluetooth/mesh/health_cli.h b/include/bluetooth/mesh/health_cli.h index 66c2aa6adf1..eb647aa547a 100644 --- a/include/bluetooth/mesh/health_cli.h +++ b/include/bluetooth/mesh/health_cli.h @@ -46,9 +46,7 @@ struct bt_mesh_health_cli { size_t fault_count); /* Internal parameters for tracking message responses. */ - struct k_sem op_sync; - uint32_t op_pending; - void *op_param; + struct bt_mesh_msg_ack_ctx ack_ctx; }; diff --git a/include/bluetooth/mesh/msg.h b/include/bluetooth/mesh/msg.h new file mode 100644 index 00000000000..e8ba1e9ef9a --- /dev/null +++ b/include/bluetooth/mesh/msg.h @@ -0,0 +1,226 @@ +/** @file + * @brief Bluetooth Mesh Message APIs. + */ + +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ + +/** + * @brief Bluetooth Mesh Message API + * @defgroup bt_mesh_msg Bluetooth Mesh Message API + * @ingroup bt_mesh + * @{ + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Length of a short Mesh MIC. */ +#define BT_MESH_MIC_SHORT 4 +/** Length of a long Mesh MIC. */ +#define BT_MESH_MIC_LONG 8 + +/** @def BT_MESH_MODEL_OP_LEN + * + * @brief Helper to determine the length of an opcode. + * + * @param _op Opcode. + */ +#define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3) + +/** @def BT_MESH_MODEL_BUF_LEN + * + * @brief Helper for model message buffer length. + * + * Returns the length of a Mesh model message buffer, including the opcode + * length and a short MIC. + * + * @param _op Opcode of the message. + * @param _payload_len Length of the model payload. + */ +#define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \ + (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT) + +/** @def BT_MESH_MODEL_BUF_LEN_LONG_MIC + * + * @brief Helper for model message buffer length. + * + * Returns the length of a Mesh model message buffer, including the opcode + * length and a long MIC. + * + * @param _op Opcode of the message. + * @param _payload_len Length of the model payload. + */ +#define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \ + (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG) + +/** @def BT_MESH_MODEL_BUF_DEFINE + * + * @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE_DEFINE. + * + * @param _buf Buffer name. + * @param _op Opcode of the message. + * @param _payload_len Length of the model message payload. + */ +#define BT_MESH_MODEL_BUF_DEFINE(_buf, _op, _payload_len) \ + NET_BUF_SIMPLE_DEFINE(_buf, BT_MESH_MODEL_BUF_LEN(_op, (_payload_len))) + +/** Message sending context. */ +struct bt_mesh_msg_ctx { + /** NetKey Index of the subnet to send the message on. */ + uint16_t net_idx; + + /** AppKey Index to encrypt the message with. */ + uint16_t app_idx; + + /** Remote address. */ + uint16_t addr; + + /** Destination address of a received message. Not used for sending. */ + uint16_t recv_dst; + + /** RSSI of received packet. Not used for sending. */ + int8_t recv_rssi; + + /** Received TTL value. Not used for sending. */ + uint8_t recv_ttl; + + /** Force sending reliably by using segment acknowledgment */ + bool send_rel; + + /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ + uint8_t send_ttl; +}; + +/** @brief Initialize a model message. + * + * Clears the message buffer contents, and encodes the given opcode. + * The message buffer will be ready for filling in payload data. + * + * @param msg Message buffer. + * @param opcode Opcode to encode. + */ +void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode); + +/** + * Acknowledged message context for tracking the status of model messages pending a response. + */ +struct bt_mesh_msg_ack_ctx { + struct k_sem sem; /**< Sync semaphore. */ + uint32_t op; /**< Opcode we're waiting for. */ + uint16_t dst; /**< Address of the node that should respond. */ + void *user_data; /**< User specific parameter. */ +}; + +/** @brief Initialize an acknowledged message context. + * + * Initializes semaphore used for synchronization between @ref bt_mesh_msg_ack_ctx_wait and + * @ref bt_mesh_msg_ack_ctx_rx calls. Call this function before using @ref bt_mesh_msg_ack_ctx. + * + * @param ack Acknowledged message context to initialize. + */ +static inline void bt_mesh_msg_ack_ctx_init(struct bt_mesh_msg_ack_ctx *ack) +{ + k_sem_init(&ack->sem, 0, 1); +} + +/** @brief Reset the synchronization semaphore in an acknowledged message context. + * + * This function aborts call to @ref bt_mesh_msg_ack_ctx_wait. + * + * @param ack Acknowledged message context to be reset. + */ +static inline void bt_mesh_msg_ack_ctx_reset(struct bt_mesh_msg_ack_ctx *ack) +{ + k_sem_reset(&ack->sem); +} + +/** @brief Clear parameters of an acknowledged message context. + * + * This function clears the opcode, remote address and user data set + * by @ref bt_mesh_msg_ack_ctx_prepare. + * + * @param ack Acknowledged message context to be cleared. + */ +void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack); + +/** @brief Prepare an acknowledged message context for the incoming message to wait. + * + * This function sets the opcode, remote address of the incoming message and stores the user data. + * Use this function before calling @ref bt_mesh_msg_ack_ctx_wait. + * + * @param ack Acknowledged message context to prepare. + * @param op The message OpCode. + * @param dst Destination address of the message. + * @param user_data User data for the acknowledged message context. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t dst, void *user_data); + +/** @brief Check if the acknowledged message context is initialized with an opcode. + * + * @param ack Acknowledged message context. + * + * @return true if the acknowledged message context is initialized with an opcode, + * false otherwise. + */ +static inline bool bt_mesh_msg_ack_ctx_busy(struct bt_mesh_msg_ack_ctx *ack) +{ + return (ack->op != 0); +} + +/** @brief Wait for a message acknowledge. + * + * This function blocks execution until @ref bt_mesh_msg_ack_ctx_rx is called or by timeout. + * + * @param ack Acknowledged message context of the message to wait for. + * @param timeout Wait timeout. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, k_timeout_t timeout); + +/** @brief Mark a message as acknowledged. + * + * This function unblocks call to @ref bt_mesh_msg_ack_ctx_wait. + * + * @param ack Context of a message to be acknowledged. + */ +static inline void bt_mesh_msg_ack_ctx_rx(struct bt_mesh_msg_ack_ctx *ack) +{ + k_sem_give(&ack->sem); +} + +/** @brief Check if an opcode and address of a message matches the expected one. + * + * @param ack Acknowledged message context to be checked. + * @param op OpCode of the incoming message. + * @param addr Source address of the incoming message. + * @param user_data If not NULL, returns a user data stored in the acknowledged message context + * by @ref bt_mesh_msg_ack_ctx_prepare. + * + * @return true if the incoming message matches the expected one, false otherwise. + */ +bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t addr, void **user_data); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ */ diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 716d14cd30d..6bcb3b15aae 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH heartbeat.c crypto.c access.c + msg.c cfg_srv.c health_srv.c ) diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 550880a994f..dcc9adc7b3b 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -630,31 +630,6 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } } -void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) -{ - net_buf_simple_init(msg, 0); - - switch (BT_MESH_MODEL_OP_LEN(opcode)) { - case 1: - net_buf_simple_add_u8(msg, opcode); - break; - case 2: - net_buf_simple_add_be16(msg, opcode); - break; - case 3: - net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); - /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 - * will declare the opcode in this way. - */ - net_buf_simple_add_le16(msg, opcode & 0xffff); - break; - default: - BT_WARN("Unknown opcode format"); - break; - } -} - static int model_send(struct bt_mesh_model *model, struct bt_mesh_net_tx *tx, bool implicit_bind, struct net_buf_simple *msg, diff --git a/subsys/bluetooth/mesh/cfg_cli.c b/subsys/bluetooth/mesh/cfg_cli.c index a8509f59c24..18de391632e 100644 --- a/subsys/bluetooth/mesh/cfg_cli.c +++ b/subsys/bluetooth/mesh/cfg_cli.c @@ -40,11 +40,6 @@ static int32_t msg_timeout; static struct bt_mesh_cfg_cli *cli; -static inline bool cli_response_check(uint32_t resp_opcode, uint16_t resp_addr) -{ - return cli->op_pending == resp_opcode && cli->op_addr == resp_addr; -} - static void comp_data_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) @@ -56,13 +51,11 @@ static void comp_data_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_DEV_COMP_DATA_STATUS, ctx->addr)) { - BT_WARN("Unexpected Composition Data Status"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_DEV_COMP_DATA_STATUS, ctx->addr, + (void **)¶m)) { return; } - param = cli->op_param; - if (param->page) { *(param->page) = net_buf_simple_pull_u8(buf); } @@ -70,7 +63,7 @@ static void comp_data_status(struct bt_mesh_model *model, to_copy = MIN(net_buf_simple_tailroom(param->comp), buf->len); net_buf_simple_add_mem(param->comp, buf->data, to_copy); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } static void state_status_u8(struct bt_mesh_model *model, @@ -84,16 +77,14 @@ static void state_status_u8(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(expect_status, ctx->addr)) { - BT_WARN("Unexpected Status (0x%08x != 0x%08x)", - cli->op_pending, expect_status); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, expect_status, ctx->addr, + (void **)&status)) { return; } - status = cli->op_param; *status = net_buf_simple_pull_u8(buf); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } static void beacon_status(struct bt_mesh_model *model, @@ -139,16 +130,15 @@ static void relay_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_RELAY_STATUS, ctx->addr)) { - BT_WARN("Unexpected Relay Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_RELAY_STATUS, ctx->addr, + (void **)¶m)) { return; } - param = cli->op_param; *param->status = net_buf_simple_pull_u8(buf); *param->transmit = net_buf_simple_pull_u8(buf); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } static void net_transmit_status(struct bt_mesh_model *model, @@ -161,15 +151,14 @@ static void net_transmit_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_NET_TRANSMIT_STATUS, ctx->addr)) { - BT_WARN("Unexpected Net Transmit Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_TRANSMIT_STATUS, ctx->addr, + (void **)&status)) { return; } - status = cli->op_param; *status = net_buf_simple_pull_u8(buf); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } struct net_key_param { @@ -189,15 +178,14 @@ static void net_key_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_NET_KEY_STATUS, ctx->addr)) { - BT_WARN("Unexpected Net Key Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_KEY_STATUS, ctx->addr, + (void **)¶m)) { return; } status = net_buf_simple_pull_u8(buf); net_idx = net_buf_simple_pull_le16(buf) & 0xfff; - param = cli->op_param; if (param->net_idx != net_idx) { BT_WARN("Net Key Status key index does not match"); return; @@ -207,7 +195,7 @@ static void net_key_status(struct bt_mesh_model *model, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } struct net_key_list_param { @@ -226,13 +214,11 @@ static void net_key_list(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_NET_KEY_LIST, ctx->addr)) { - BT_WARN("Unexpected Net Key List message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_KEY_LIST, ctx->addr, + (void **)¶m)) { return; } - param = cli->op_param; - for (i = 0; i < *param->key_cnt && buf->len >= 3; i += 2) { key_idx_unpack(buf, ¶m->keys[i], ¶m->keys[i + 1]); } @@ -243,7 +229,7 @@ static void net_key_list(struct bt_mesh_model *model, *param->key_cnt = i; - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } static void node_reset_status(struct bt_mesh_model *model, @@ -253,17 +239,15 @@ static void node_reset_status(struct bt_mesh_model *model, BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x", ctx->net_idx, ctx->app_idx, ctx->addr); - if (!cli_response_check(OP_NODE_RESET_STATUS, ctx->addr)) { - BT_WARN("Unexpected Node Reset Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NODE_RESET_STATUS, ctx->addr, + (void **)¶m)) { return; } - param = cli->op_param; - if (param) { *param = true; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } struct app_key_param { @@ -284,15 +268,14 @@ static void app_key_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_APP_KEY_STATUS, ctx->addr)) { - BT_WARN("Unexpected App Key Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_APP_KEY_STATUS, ctx->addr, + (void **)¶m)) { return; } status = net_buf_simple_pull_u8(buf); key_idx_unpack(buf, &net_idx, &app_idx); - param = cli->op_param; if (param->net_idx != net_idx || param->app_idx != app_idx) { BT_WARN("App Key Status key indices did not match"); return; @@ -302,7 +285,7 @@ static void app_key_status(struct bt_mesh_model *model, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } struct app_key_list_param { @@ -325,15 +308,14 @@ static void app_key_list(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_APP_KEY_LIST, ctx->addr)) { - BT_WARN("Unexpected App Key List message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_APP_KEY_LIST, ctx->addr, + (void **)¶m)) { return; } status = net_buf_simple_pull_u8(buf); net_idx = net_buf_simple_pull_le16(buf) & 0xfff; - param = cli->op_param; if (param->net_idx != net_idx) { BT_WARN("App Key List Net Key index did not match"); return; @@ -352,7 +334,7 @@ static void app_key_list(struct bt_mesh_model *model, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } struct mod_app_param { @@ -375,8 +357,8 @@ static void mod_app_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_MOD_APP_STATUS, ctx->addr)) { - BT_WARN("Unexpected Model App Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_APP_STATUS, ctx->addr, + (void **)¶m)) { return; } @@ -392,7 +374,6 @@ static void mod_app_status(struct bt_mesh_model *model, mod_id = net_buf_simple_pull_le16(buf); - param = cli->op_param; if (param->elem_addr != elem_addr || param->mod_app_idx != mod_app_idx || param->mod_id != mod_id || param->cid != cid) { @@ -404,7 +385,7 @@ static void mod_app_status(struct bt_mesh_model *model, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } struct mod_member_list_param { @@ -417,9 +398,9 @@ struct mod_member_list_param { }; static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, - struct net_buf_simple *buf, bool vnd) + struct net_buf_simple *buf, bool vnd, + struct mod_member_list_param *param) { - struct mod_member_list_param *param; uint16_t elem_addr, mod_id, cid; uint8_t status; int i; @@ -432,7 +413,6 @@ static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, mod_id = net_buf_simple_pull_le16(buf); - param = cli->op_param; if (param->elem_addr != elem_addr || param->mod_id != mod_id || (vnd && param->cid != cid)) { BT_WARN("Model Member List parameters did not match"); @@ -453,39 +433,43 @@ static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } static void mod_app_list(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_SIG_MOD_APP_LIST, ctx->addr)) { - BT_WARN("Unexpected Model App List message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_SIG_MOD_APP_LIST, ctx->addr, + (void **)¶m)) { return; } - mod_member_list_handle(ctx, buf, false); + mod_member_list_handle(ctx, buf, false, param); } static void mod_app_list_vnd(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_VND_MOD_APP_LIST, ctx->addr)) { - BT_WARN("Unexpected Model App List Vendor message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_VND_MOD_APP_LIST, ctx->addr, + (void **)¶m)) { return; } - mod_member_list_handle(ctx, buf, true); + mod_member_list_handle(ctx, buf, true, param); } struct mod_pub_param { @@ -508,12 +492,11 @@ static void mod_pub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_MOD_PUB_STATUS, ctx->addr)) { - BT_WARN("Unexpected Model Pub Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_PUB_STATUS, ctx->addr, + (void **)¶m)) { return; } - param = cli->op_param; if (param->cid != CID_NVAL) { if (buf->len < 14) { BT_WARN("Unexpected Mod Pub Status with SIG Model"); @@ -560,7 +543,7 @@ static void mod_pub_status(struct bt_mesh_model *model, param->pub->transmit = net_buf_simple_pull_u8(buf); } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } struct mod_sub_param { @@ -584,8 +567,8 @@ static void mod_sub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_MOD_SUB_STATUS, ctx->addr)) { - BT_WARN("Unexpected Model Subscription Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_SUB_STATUS, ctx->addr, + (void **)¶m)) { return; } @@ -601,7 +584,6 @@ static void mod_sub_status(struct bt_mesh_model *model, mod_id = net_buf_simple_pull_le16(buf); - param = cli->op_param; if (param->elem_addr != elem_addr || param->mod_id != mod_id || (param->expect_sub && *param->expect_sub != sub_addr) || param->cid != cid) { @@ -617,39 +599,43 @@ static void mod_sub_status(struct bt_mesh_model *model, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } static void mod_sub_list(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_MOD_SUB_LIST, ctx->addr)) { - BT_WARN("Unexpected Model Subscription List message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_SUB_LIST, ctx->addr, + (void **)¶m)) { return; } - mod_member_list_handle(ctx, buf, false); + mod_member_list_handle(ctx, buf, false, param); } static void mod_sub_list_vnd(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_MOD_SUB_LIST_VND, ctx->addr)) { - BT_WARN("Unexpected Model Subscription List Vendor message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_SUB_LIST_VND, ctx->addr, + (void **)¶m)) { return; } - mod_member_list_handle(ctx, buf, true); + mod_member_list_handle(ctx, buf, true, param); } struct hb_sub_param { @@ -667,13 +653,11 @@ static void hb_sub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_HEARTBEAT_SUB_STATUS, ctx->addr)) { - BT_WARN("Unexpected Heartbeat Subscription Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_HEARTBEAT_SUB_STATUS, ctx->addr, + (void **)¶m)) { return; } - param = cli->op_param; - *param->status = net_buf_simple_pull_u8(buf); param->sub->src = net_buf_simple_pull_le16(buf); @@ -683,7 +667,7 @@ static void hb_sub_status(struct bt_mesh_model *model, param->sub->min = net_buf_simple_pull_u8(buf); param->sub->max = net_buf_simple_pull_u8(buf); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } struct hb_pub_param { @@ -701,13 +685,11 @@ static void hb_pub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (!cli_response_check(OP_HEARTBEAT_PUB_STATUS, ctx->addr)) { - BT_WARN("Unexpected Heartbeat Publication Status message"); + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_HEARTBEAT_PUB_STATUS, ctx->addr, + (void **)¶m)) { return; } - param = cli->op_param; - *param->status = net_buf_simple_pull_u8(buf); if (param->pub) { @@ -719,7 +701,7 @@ static void hb_pub_status(struct bt_mesh_model *model, param->pub->net_idx = net_buf_simple_pull_u8(buf); } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); } const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { @@ -769,7 +751,7 @@ static int cfg_cli_init(struct bt_mesh_model *model) */ model->keys[0] = BT_MESH_KEY_DEV_ANY; - k_sem_init(&cli->op_sync, 0, 1); + bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); return 0; } @@ -785,34 +767,7 @@ static int cli_prepare(void *param, uint32_t op, uint16_t addr) return -EINVAL; } - if (cli->op_pending) { - BT_WARN("Another synchronous operation pending"); - return -EBUSY; - } - - cli->op_param = param; - cli->op_pending = op; - cli->op_addr = addr; - - return 0; -} - -static void cli_reset(void) -{ - cli->op_pending = 0U; - cli->op_param = NULL; - cli->op_addr = BT_MESH_ADDR_UNASSIGNED; -} - -static int cli_wait(void) -{ - int err; - - err = k_sem_take(&cli->op_sync, SYS_TIMEOUT_MS(msg_timeout)); - - cli_reset(); - - return err; + return bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, op, addr, param); } int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, @@ -842,11 +797,11 @@ int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } static int get_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t rsp, @@ -871,11 +826,11 @@ static int get_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t r err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } static int set_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t rsp, @@ -901,11 +856,11 @@ static int set_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t r err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_beacon_get(uint16_t net_idx, uint16_t addr, uint8_t *status) @@ -998,11 +953,11 @@ int bt_mesh_cfg_relay_get(uint16_t net_idx, uint16_t addr, uint8_t *status, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_relay_set(uint16_t net_idx, uint16_t addr, uint8_t new_relay, @@ -1033,11 +988,11 @@ int bt_mesh_cfg_relay_set(uint16_t net_idx, uint16_t addr, uint8_t new_relay, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_net_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, @@ -1068,16 +1023,16 @@ int bt_mesh_cfg_net_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_id err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys, @@ -1106,11 +1061,11 @@ int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr, @@ -1140,16 +1095,16 @@ int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_app_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, @@ -1182,16 +1137,16 @@ int bt_mesh_cfg_app_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_id err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status) @@ -1220,16 +1175,16 @@ int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status) err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_app_key_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, @@ -1261,11 +1216,11 @@ int bt_mesh_cfg_app_key_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_id err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr, @@ -1296,16 +1251,16 @@ int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } static int mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, @@ -1346,16 +1301,16 @@ static int mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, @@ -1415,16 +1370,16 @@ static int mod_app_unbind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_mod_app_unbind(uint16_t net_idx, uint16_t addr, @@ -1490,11 +1445,11 @@ static int mod_member_list_get(uint32_t op, uint32_t expect_op, uint16_t net_idx err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_mod_app_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, @@ -1556,16 +1511,16 @@ static int mod_sub(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t elem_a err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_mod_sub_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, @@ -1667,16 +1622,16 @@ static int mod_sub_va(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t ele err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_mod_sub_va_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, @@ -1801,16 +1756,16 @@ static int mod_pub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_mod_pub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, @@ -1875,16 +1830,16 @@ static int mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, @@ -1935,16 +1890,16 @@ int bt_mesh_cfg_hb_sub_set(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_hb_sub_get(uint16_t net_idx, uint16_t addr, @@ -1973,16 +1928,16 @@ int bt_mesh_cfg_hb_sub_get(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr, @@ -2016,16 +1971,16 @@ int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr, @@ -2054,16 +2009,16 @@ int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int32_t bt_mesh_cfg_cli_timeout_get(void) diff --git a/subsys/bluetooth/mesh/health_cli.c b/subsys/bluetooth/mesh/health_cli.c index 8a83238305f..30516b79453 100644 --- a/subsys/bluetooth/mesh/health_cli.c +++ b/subsys/bluetooth/mesh/health_cli.c @@ -49,13 +49,11 @@ static void health_fault_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (health_cli->op_pending != OP_HEALTH_FAULT_STATUS) { - BT_WARN("Unexpected Health Fault Status message"); + if (!bt_mesh_msg_ack_ctx_match(&health_cli->ack_ctx, OP_HEALTH_FAULT_STATUS, ctx->addr, + (void **)¶m)) { return; } - param = health_cli->op_param; - test_id = net_buf_simple_pull_u8(buf); if (param->expect_test_id && test_id != *param->expect_test_id) { BT_WARN("Health fault with unexpected Test ID"); @@ -80,7 +78,7 @@ static void health_fault_status(struct bt_mesh_model *model, memcpy(param->faults, buf->data, *param->fault_count); - k_sem_give(&health_cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&health_cli->ack_ctx); } static void health_current_status(struct bt_mesh_model *model, @@ -123,16 +121,14 @@ static void health_period_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (health_cli->op_pending != OP_HEALTH_PERIOD_STATUS) { - BT_WARN("Unexpected Health Period Status message"); + if (!bt_mesh_msg_ack_ctx_match(&health_cli->ack_ctx, OP_HEALTH_PERIOD_STATUS, ctx->addr, + (void **)¶m)) { return; } - param = health_cli->op_param; - *param->divisor = net_buf_simple_pull_u8(buf); - k_sem_give(&health_cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&health_cli->ack_ctx); } struct health_attention_param { @@ -149,18 +145,16 @@ static void health_attention_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->len, bt_hex(buf->data, buf->len)); - if (health_cli->op_pending != OP_ATTENTION_STATUS) { - BT_WARN("Unexpected Health Attention Status message"); + if (!bt_mesh_msg_ack_ctx_match(&health_cli->ack_ctx, OP_ATTENTION_STATUS, ctx->addr, + (void **)¶m)) { return; } - param = health_cli->op_param; - if (param->attention) { *param->attention = net_buf_simple_pull_u8(buf); } - k_sem_give(&health_cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&health_cli->ack_ctx); } const struct bt_mesh_model_op bt_mesh_health_cli_op[] = { @@ -171,39 +165,14 @@ const struct bt_mesh_model_op bt_mesh_health_cli_op[] = { BT_MESH_MODEL_OP_END, }; -static int cli_prepare(void *param, uint32_t op) +static int cli_prepare(void *param, uint32_t op, uint16_t addr) { if (!health_cli) { BT_ERR("No available Health Client context!"); return -EINVAL; } - if (health_cli->op_pending) { - BT_WARN("Another synchronous operation pending"); - return -EBUSY; - } - - health_cli->op_param = param; - health_cli->op_pending = op; - - return 0; -} - -static void cli_reset(void) -{ - health_cli->op_pending = 0U; - health_cli->op_param = NULL; -} - -static int cli_wait(void) -{ - int err; - - err = k_sem_take(&health_cli->op_sync, SYS_TIMEOUT_MS(msg_timeout)); - - cli_reset(); - - return err; + return bt_mesh_msg_ack_ctx_prepare(&health_cli->ack_ctx, op, addr, param); } int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *attention) @@ -219,7 +188,7 @@ int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *atten }; int err; - err = cli_prepare(¶m, OP_ATTENTION_STATUS); + err = cli_prepare(¶m, OP_ATTENTION_STATUS, addr); if (err) { return err; } @@ -229,11 +198,11 @@ int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *atten err = bt_mesh_model_send(health_cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attention, @@ -250,7 +219,7 @@ int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attent }; int err; - err = cli_prepare(¶m, OP_ATTENTION_STATUS); + err = cli_prepare(¶m, OP_ATTENTION_STATUS, addr); if (err) { return err; } @@ -266,16 +235,16 @@ int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attent err = bt_mesh_model_send(health_cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return err; } if (!updated_attention) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor) @@ -291,7 +260,7 @@ int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor) }; int err; - err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS); + err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS, addr); if (err) { return err; } @@ -301,11 +270,11 @@ int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor) err = bt_mesh_model_send(health_cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor, @@ -322,7 +291,7 @@ int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor, }; int err; - err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS); + err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS, addr); if (err) { return err; } @@ -338,16 +307,16 @@ int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor, err = bt_mesh_model_send(health_cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return err; } if (!updated_divisor) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid, @@ -368,7 +337,7 @@ int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid, }; int err; - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); + err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS, addr); if (err) { return err; } @@ -385,16 +354,16 @@ int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid, err = bt_mesh_model_send(health_cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return err; } if (!faults) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid, @@ -415,7 +384,7 @@ int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid, }; int err; - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); + err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS, addr); if (err) { return err; } @@ -431,16 +400,16 @@ int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid, err = bt_mesh_model_send(health_cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return err; } if (!test_id) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return 0; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid, @@ -461,7 +430,7 @@ int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid, }; int err; - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); + err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS, addr); if (err) { return err; } @@ -472,11 +441,11 @@ int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid, err = bt_mesh_model_send(health_cli->model, &ctx, &msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); return err; } - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); } int32_t bt_mesh_health_cli_timeout_get(void) @@ -516,13 +485,12 @@ static int health_cli_init(struct bt_mesh_model *model) cli = model->user_data; cli->model = model; - k_sem_init(&cli->op_sync, 0, 1); - /* Set the default health client pointer */ if (!health_cli) { health_cli = cli; } + bt_mesh_msg_ack_ctx_init(&health_cli->ack_ctx); return 0; } diff --git a/subsys/bluetooth/mesh/msg.c b/subsys/bluetooth/mesh/msg.c new file mode 100644 index 00000000000..ff9f16ff409 --- /dev/null +++ b/subsys/bluetooth/mesh/msg.c @@ -0,0 +1,84 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_ACCESS) +#define LOG_MODULE_NAME bt_mesh_msg +#include "common/log.h" + +void bt_mesh_model_msg_init(struct net_buf_simple *msg, uint32_t opcode) +{ + net_buf_simple_init(msg, 0); + + switch (BT_MESH_MODEL_OP_LEN(opcode)) { + case 1: + net_buf_simple_add_u8(msg, opcode); + break; + case 2: + net_buf_simple_add_be16(msg, opcode); + break; + case 3: + net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); + /* Using LE for the CID since the model layer is defined as + * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 + * will declare the opcode in this way. + */ + net_buf_simple_add_le16(msg, opcode & 0xffff); + break; + default: + BT_WARN("Unknown opcode format"); + break; + } +} + +void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack) +{ + ack->op = 0U; + ack->user_data = NULL; + ack->dst = BT_MESH_ADDR_UNASSIGNED; +} + +int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t dst, void *user_data) +{ + if (ack->op) { + BT_WARN("Another synchronous operation pending"); + return -EBUSY; + } + + ack->op = op; + ack->user_data = user_data; + ack->dst = dst; + + return 0; +} + +int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, k_timeout_t timeout) +{ + int err; + + err = k_sem_take(&ack->sem, timeout); + bt_mesh_msg_ack_ctx_clear(ack); + + return err; +} + +bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t addr, void **user_data) +{ + if (ack->op != op || (BT_MESH_ADDR_IS_UNICAST(ack->dst) && ack->dst != addr)) { + return false; + } + + if (user_data != NULL) { + *user_data = ack->user_data; + } + + return true; +}