From c2c05c916a404c38e6ce0c231edd3b57fcc6f0da Mon Sep 17 00:00:00 2001 From: Trond Einar Snekvik Date: Mon, 19 Aug 2019 10:05:36 +0200 Subject: [PATCH] Bluetooth: Mesh: Add model callback structure Adds a structure of callbacks for each model instance. This allows for more flexible model implementations, that can interact with the Mesh stack without going through the application. For now, only an init callback is added, replacing the init mechanism in the foundation models. The init callback does not provide the primary flag that used to be in the foundation model callbacks, but replaces this with an inline function in access.h. Signed-off-by: Trond Einar Snekvik --- include/bluetooth/mesh/access.h | 81 ++++++++++++++++++++++++++++- include/bluetooth/mesh/cfg_cli.h | 7 +-- include/bluetooth/mesh/cfg_srv.h | 7 +-- include/bluetooth/mesh/health_cli.h | 7 +-- include/bluetooth/mesh/health_srv.h | 7 +-- subsys/bluetooth/mesh/access.c | 24 +-------- subsys/bluetooth/mesh/cfg_cli.c | 52 +++++++++--------- subsys/bluetooth/mesh/cfg_srv.c | 11 +++- subsys/bluetooth/mesh/foundation.h | 6 --- subsys/bluetooth/mesh/health_cli.c | 8 ++- subsys/bluetooth/mesh/health_srv.c | 10 ++-- 11 files changed, 147 insertions(+), 73 deletions(-) diff --git a/include/bluetooth/mesh/access.h b/include/bluetooth/mesh/access.h index 8ae18a7aa49..64f47dc6066 100644 --- a/include/bluetooth/mesh/access.h +++ b/include/bluetooth/mesh/access.h @@ -174,7 +174,18 @@ struct bt_mesh_model_op { /** Helper to define an empty model array */ #define BT_MESH_MODEL_NONE ((struct bt_mesh_model []){}) -#define BT_MESH_MODEL(_id, _op, _pub, _user_data) \ + +/** @def BT_MESH_MODEL_CB + * + * @brief Composition data SIG model entry with callback functions. + * + * @param _id Model ID. + * @param _op Array of model opcode handlers. + * @param _pub Model publish parameters. + * @param _user_data User data for the model. + * @param _cb Callback structure, or NULL to keep no callbacks. + */ +#define BT_MESH_MODEL_CB(_id, _op, _pub, _user_data, _cb) \ { \ .id = (_id), \ .op = _op, \ @@ -184,9 +195,21 @@ struct bt_mesh_model_op { .groups = { [0 ... (CONFIG_BT_MESH_MODEL_GROUP_COUNT - 1)] = \ BT_MESH_ADDR_UNASSIGNED }, \ .user_data = _user_data, \ + .cb = _cb, \ } -#define BT_MESH_MODEL_VND(_company, _id, _op, _pub, _user_data) \ +/** @def BT_MESH_MODEL_VND_CB + * + * @brief Composition data vendor model entry with callback functions. + * + * @param _company Company ID. + * @param _id Model ID. + * @param _op Array of model opcode handlers. + * @param _pub Model publish parameters. + * @param _user_data User data for the model. + * @param _cb Callback structure, or NULL to keep no callbacks. + */ +#define BT_MESH_MODEL_VND_CB(_company, _id, _op, _pub, _user_data, _cb) \ { \ .vnd.company = (_company), \ .vnd.id = (_id), \ @@ -197,8 +220,35 @@ struct bt_mesh_model_op { .groups = { [0 ... (CONFIG_BT_MESH_MODEL_GROUP_COUNT - 1)] = \ BT_MESH_ADDR_UNASSIGNED }, \ .user_data = _user_data, \ + .cb = _cb, \ } + +/** @def BT_MESH_MODEL + * + * @brief Composition data SIG model entry. + * + * @param _id Model ID. + * @param _op Array of model opcode handlers. + * @param _pub Model publish parameters. + * @param _user_data User data for the model. + */ +#define BT_MESH_MODEL(_id, _op, _pub, _user_data) \ + BT_MESH_MODEL_CB(_id, _op, _pub, _user_data, NULL) + +/** @def BT_MESH_MODEL_VND + * + * @brief Composition data vendor model entry. + * + * @param _company Company ID. + * @param _id Model ID. + * @param _op Array of model opcode handlers. + * @param _pub Model publish parameters. + * @param _user_data User data for the model. + */ +#define BT_MESH_MODEL_VND(_company, _id, _op, _pub, _user_data) \ + BT_MESH_MODEL_VND_CB(_company, _id, _op, _pub, _user_data, NULL) + /** @def BT_MESH_TRANSMIT * * @brief Encode transmission count & interval steps. @@ -330,6 +380,19 @@ struct bt_mesh_model_pub { .msg = &bt_mesh_pub_msg_##_name, \ } +/** Model callback functions. */ +struct bt_mesh_model_cb { + /** @brief Model init callback. + * + * Called on every model instance during mesh initialization. + * + * @param model Model to be initialized. + * + * @return 0 on success, error otherwise. + */ + int (*const init)(struct bt_mesh_model *model); +}; + /** Abstraction that describes a Mesh Model instance */ struct bt_mesh_model { union { @@ -356,6 +419,9 @@ struct bt_mesh_model { const struct bt_mesh_model_op * const op; + /* Model callback structure. */ + const struct bt_mesh_model_cb * const cb; + /* Model-specific user data */ void *user_data; }; @@ -438,6 +504,17 @@ struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem, struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, u16_t company, u16_t id); +/** @brief Get whether the model is in the primary element of the device. + * + * @param mod Mesh model. + * + * @return true if the model is on the primary element, false otherwise. + */ +static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod) +{ + return (mod->elem_idx == 0); +} + /** Node Composition */ struct bt_mesh_comp { u16_t cid; diff --git a/include/bluetooth/mesh/cfg_cli.h b/include/bluetooth/mesh/cfg_cli.h index 96e47e1e2e7..84fc7802dfb 100644 --- a/include/bluetooth/mesh/cfg_cli.h +++ b/include/bluetooth/mesh/cfg_cli.h @@ -31,10 +31,11 @@ struct bt_mesh_cfg_cli { }; extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb; -#define BT_MESH_MODEL_CFG_CLI(cli_data) \ - BT_MESH_MODEL(BT_MESH_MODEL_ID_CFG_CLI, \ - bt_mesh_cfg_cli_op, NULL, cli_data) +#define BT_MESH_MODEL_CFG_CLI(cli_data) \ + BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_CFG_CLI, bt_mesh_cfg_cli_op, NULL, \ + cli_data, &bt_mesh_cfg_cli_cb) int bt_mesh_cfg_comp_data_get(u16_t net_idx, u16_t addr, u8_t page, u8_t *status, struct net_buf_simple *comp); diff --git a/include/bluetooth/mesh/cfg_srv.h b/include/bluetooth/mesh/cfg_srv.h index a28efdeafae..06b5d46b044 100644 --- a/include/bluetooth/mesh/cfg_srv.h +++ b/include/bluetooth/mesh/cfg_srv.h @@ -61,10 +61,11 @@ struct bt_mesh_cfg_srv { }; extern const struct bt_mesh_model_op bt_mesh_cfg_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb; -#define BT_MESH_MODEL_CFG_SRV(srv_data) \ - BT_MESH_MODEL(BT_MESH_MODEL_ID_CFG_SRV, \ - bt_mesh_cfg_srv_op, NULL, srv_data) +#define BT_MESH_MODEL_CFG_SRV(srv_data) \ + BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_op, NULL, \ + srv_data, &bt_mesh_cfg_srv_cb) #ifdef __cplusplus } diff --git a/include/bluetooth/mesh/health_cli.h b/include/bluetooth/mesh/health_cli.h index 8ebd8012b1d..80701abcb19 100644 --- a/include/bluetooth/mesh/health_cli.h +++ b/include/bluetooth/mesh/health_cli.h @@ -35,10 +35,11 @@ struct bt_mesh_health_cli { }; extern const struct bt_mesh_model_op bt_mesh_health_cli_op[]; +extern const struct bt_mesh_model_cb bt_mesh_health_cli_cb; -#define BT_MESH_MODEL_HEALTH_CLI(cli_data) \ - BT_MESH_MODEL(BT_MESH_MODEL_ID_HEALTH_CLI, \ - bt_mesh_health_cli_op, NULL, cli_data) +#define BT_MESH_MODEL_HEALTH_CLI(cli_data) \ + BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_CLI, bt_mesh_health_cli_op, \ + NULL, cli_data, &bt_mesh_health_cli_cb) int bt_mesh_health_cli_set(struct bt_mesh_model *model); diff --git a/include/bluetooth/mesh/health_srv.h b/include/bluetooth/mesh/health_srv.h index 2215ae0f6fe..60b507f5960 100644 --- a/include/bluetooth/mesh/health_srv.h +++ b/include/bluetooth/mesh/health_srv.h @@ -70,6 +70,7 @@ struct bt_mesh_health_srv { int bt_mesh_fault_update(struct bt_mesh_elem *elem); extern const struct bt_mesh_model_op bt_mesh_health_srv_op[]; +extern const struct bt_mesh_model_cb bt_mesh_health_srv_cb; /** @def BT_MESH_MODEL_HEALTH_SRV * @@ -83,9 +84,9 @@ extern const struct bt_mesh_model_op bt_mesh_health_srv_op[]; * * @return New mesh model instance. */ -#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \ - BT_MESH_MODEL(BT_MESH_MODEL_ID_HEALTH_SRV, \ - bt_mesh_health_srv_op, pub, srv) +#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \ + BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_op, \ + pub, srv, &bt_mesh_health_srv_cb) #ifdef __cplusplus } diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index cfcf9858603..902c6cdc784 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -30,20 +30,6 @@ static const struct bt_mesh_comp *dev_comp; static u16_t dev_primary_addr; -static const struct { - const u16_t id; - int (*const init)(struct bt_mesh_model *model, bool primary); -} model_init[] = { - { BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_init }, - { BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_init }, -#if defined(CONFIG_BT_MESH_CFG_CLI) - { BT_MESH_MODEL_ID_CFG_CLI, bt_mesh_cfg_cli_init }, -#endif -#if defined(CONFIG_BT_MESH_HEALTH_CLI) - { BT_MESH_MODEL_ID_HEALTH_CLI, bt_mesh_health_cli_init }, -#endif -}; - void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, @@ -302,14 +288,8 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, mod->mod_idx = mod - elem->models; } - if (vnd) { - return; - } - - for (i = 0; i < ARRAY_SIZE(model_init); i++) { - if (model_init[i].id == mod->id) { - model_init[i].init(mod, primary); - } + if (mod->cb && mod->cb->init) { + mod->cb->init(mod); } } diff --git a/subsys/bluetooth/mesh/cfg_cli.c b/subsys/bluetooth/mesh/cfg_cli.c index a6414a39429..fd1a8fdaf70 100644 --- a/subsys/bluetooth/mesh/cfg_cli.c +++ b/subsys/bluetooth/mesh/cfg_cli.c @@ -487,6 +487,33 @@ const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { BT_MESH_MODEL_OP_END, }; +static int cfg_cli_init(struct bt_mesh_model *model) +{ + if (!bt_mesh_model_in_primary(model)) { + BT_ERR("Configuration Client only allowed in primary element"); + return -EINVAL; + } + + if (!model->user_data) { + BT_ERR("No Configuration Client context provided"); + return -EINVAL; + } + + cli = model->user_data; + cli->model = model; + + /* Configuration Model security is device-key based */ + model->keys[0] = BT_MESH_KEY_DEV; + + k_sem_init(&cli->op_sync, 0, 1); + + return 0; +} + +const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb = { + .init = cfg_cli_init, +}; + static int cli_prepare(void *param, u32_t op) { if (!cli) { @@ -1417,28 +1444,3 @@ void bt_mesh_cfg_cli_timeout_set(s32_t timeout) { msg_timeout = timeout; } - -int bt_mesh_cfg_cli_init(struct bt_mesh_model *model, bool primary) -{ - BT_DBG("primary %u", primary); - - if (!primary) { - BT_ERR("Configuration Client only allowed in primary element"); - return -EINVAL; - } - - if (!model->user_data) { - BT_ERR("No Configuration Client context provided"); - return -EINVAL; - } - - cli = model->user_data; - cli->model = model; - - /* Configuration Model security is device-key based */ - model->keys[0] = BT_MESH_KEY_DEV; - - k_sem_init(&cli->op_sync, 0, 1); - - return 0; -} diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index ce0b3b06b1b..7a002a4213a 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -3233,10 +3233,15 @@ static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg) return true; } -int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary) +static int cfg_srv_init(struct bt_mesh_model *model) { struct bt_mesh_cfg_srv *cfg = model->user_data; + if (!bt_mesh_model_in_primary(model)) { + BT_ERR("Configuration Server only allowed in primary element"); + return -EINVAL; + } + if (!cfg) { BT_ERR("No Configuration Server context provided"); return -EINVAL; @@ -3273,6 +3278,10 @@ int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary) return 0; } +const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb = { + .init = cfg_srv_init, +}; + static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { diff --git a/subsys/bluetooth/mesh/foundation.h b/subsys/bluetooth/mesh/foundation.h index 000087dd6e7..25c24c0685d 100644 --- a/subsys/bluetooth/mesh/foundation.h +++ b/subsys/bluetooth/mesh/foundation.h @@ -112,12 +112,6 @@ #define STATUS_UNSPECIFIED 0x10 #define STATUS_INVALID_BINDING 0x11 -int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary); -int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary); - -int bt_mesh_cfg_cli_init(struct bt_mesh_model *model, bool primary); -int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary); - void bt_mesh_cfg_reset(void); void bt_mesh_heartbeat(u16_t src, u16_t dst, u8_t hops, u16_t feat); diff --git a/subsys/bluetooth/mesh/health_cli.c b/subsys/bluetooth/mesh/health_cli.c index d286231dd76..1ac5d06a287 100644 --- a/subsys/bluetooth/mesh/health_cli.c +++ b/subsys/bluetooth/mesh/health_cli.c @@ -510,11 +510,11 @@ int bt_mesh_health_cli_set(struct bt_mesh_model *model) return 0; } -int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary) +static int health_cli_init(struct bt_mesh_model *model) { struct bt_mesh_health_cli *cli = model->user_data; - BT_DBG("primary %u", primary); + BT_DBG("primary %u", bt_mesh_model_in_primary(model)); if (!cli) { BT_ERR("No Health Client context provided"); @@ -533,3 +533,7 @@ int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary) return 0; } + +const struct bt_mesh_model_cb bt_mesh_health_cli_cb = { + .init = health_cli_init, +}; diff --git a/subsys/bluetooth/mesh/health_srv.c b/subsys/bluetooth/mesh/health_srv.c index 93e5888b54b..91767977a04 100644 --- a/subsys/bluetooth/mesh/health_srv.c +++ b/subsys/bluetooth/mesh/health_srv.c @@ -384,12 +384,12 @@ static void attention_off(struct k_work *work) } } -int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary) +static int health_srv_init(struct bt_mesh_model *model) { struct bt_mesh_health_srv *srv = model->user_data; if (!srv) { - if (!primary) { + if (!bt_mesh_model_in_primary(model)) { return 0; } @@ -408,13 +408,17 @@ int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary) srv->model = model; - if (primary) { + if (bt_mesh_model_in_primary(model)) { health_srv = srv; } return 0; } +const struct bt_mesh_model_cb bt_mesh_health_srv_cb = { + .init = health_srv_init, +}; + void bt_mesh_attention(struct bt_mesh_model *model, u8_t time) { struct bt_mesh_health_srv *srv;