/** @file * @brief 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 Message * @defgroup bt_mesh_msg Message * @ingroup bt_mesh * @{ */ #include #include #ifdef __cplusplus extern "C" { #endif 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 /** * @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) /** * @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) /** * @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) /** * @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; /** Label UUID if Remote address is Virtual address, or NULL otherwise. */ const uint8_t *uuid; /** 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; /** Send message with a random delay according to the Access layer transmitting rules. */ bool rnd_delay; /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ uint8_t send_ttl; }; /** * @brief Helper for bt_mesh_msg_ctx structure initialization. * * @note If @c dst is a Virtual Address, Label UUID shall be initialized separately. * * @param net_key_idx NetKey Index of the subnet to send the message on. Only used if * @c app_key_idx points to devkey. * @param app_key_idx AppKey Index to encrypt the message with. * @param dst Remote addr. * @param ttl Time To Live. */ #define BT_MESH_MSG_CTX_INIT(net_key_idx, app_key_idx, dst, ttl) \ { \ .net_idx = (net_key_idx), \ .app_idx = (app_key_idx), \ .addr = (dst), \ .send_ttl = (ttl), \ } /** * @brief Helper for bt_mesh_msg_ctx structure initialization secured with Application Key. * * @param app_key_idx AppKey Index to encrypt the message with. * @param dst Remote addr. */ #define BT_MESH_MSG_CTX_INIT_APP(app_key_idx, dst) \ BT_MESH_MSG_CTX_INIT(0, app_key_idx, dst, BT_MESH_TTL_DEFAULT) /** * @brief Helper for bt_mesh_msg_ctx structure initialization secured with Device Key of a remote * device. * * @param net_key_idx NetKey Index of the subnet to send the message on. * @param dst Remote addr. */ #define BT_MESH_MSG_CTX_INIT_DEV(net_key_idx, dst) \ BT_MESH_MSG_CTX_INIT(net_key_idx, BT_MESH_KEY_DEV_REMOTE, dst, BT_MESH_TTL_DEFAULT) /** * @brief Helper for bt_mesh_msg_ctx structure initialization using Model Publication context. * * @param pub Pointer to a model publication context. */ #define BT_MESH_MSG_CTX_INIT_PUB(pub) \ { \ .app_idx = (pub)->key, \ .addr = (pub)->addr, \ .send_ttl = (pub)->ttl, \ .uuid = (pub)->uuid, \ } /** @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_ */