diff --git a/subsys/bluetooth/host/mesh/cfg_srv.c b/subsys/bluetooth/host/mesh/cfg_srv.c index c4884647cfa..4ab0a8b60d5 100644 --- a/subsys/bluetooth/host/mesh/cfg_srv.c +++ b/subsys/bluetooth/host/mesh/cfg_srv.c @@ -692,6 +692,10 @@ static void beacon_set(struct bt_mesh_model *model, if (buf->data[0] != cfg->beacon) { cfg->beacon = buf->data[0]; + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_cfg(); + } + if (cfg->beacon) { bt_mesh_beacon_enable(); } else { @@ -745,7 +749,13 @@ static void default_ttl_set(struct bt_mesh_model *model, if (!cfg) { BT_WARN("No Configuration Server context available"); } else if (buf->data[0] <= BT_MESH_TTL_MAX && buf->data[0] != 0x01) { - cfg->default_ttl = buf->data[0]; + if (cfg->default_ttl != buf->data[0]) { + cfg->default_ttl = buf->data[0]; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_cfg(); + } + } } else { BT_WARN("Prohibited Default TTL value 0x%02x", buf->data[0]); return; @@ -817,6 +827,11 @@ static void gatt_proxy_set(struct bt_mesh_model *model, } cfg->gatt_proxy = buf->data[0]; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_cfg(); + } + if (cfg->gatt_proxy == BT_MESH_GATT_PROXY_DISABLED) { int i; @@ -889,6 +904,10 @@ static void net_transmit_set(struct bt_mesh_model *model, BT_WARN("No Configuration Server context available"); } else { cfg->net_transmit = buf->data[0]; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_cfg(); + } } bt_mesh_model_msg_init(&msg, OP_NET_TRANSMIT_STATUS); @@ -943,6 +962,10 @@ static void relay_set(struct bt_mesh_model *model, change = (cfg->relay != buf->data[0]); cfg->relay = buf->data[0]; cfg->relay_retransmit = buf->data[1]; + + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_cfg(); + } } BT_DBG("Relay 0x%02x (%s) xmit 0x%02x (count %u interval %u)", @@ -2591,6 +2614,10 @@ static void friend_set(struct bt_mesh_model *model, if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { cfg->frnd = buf->data[0]; + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_store_cfg(); + } + if (cfg->frnd == BT_MESH_FRIEND_DISABLED) { bt_mesh_friend_clear_net_idx(BT_MESH_KEY_ANY); } @@ -3351,6 +3378,11 @@ struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void) return &conf->hb_pub; } +struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void) +{ + return conf; +} + void bt_mesh_subnet_del(struct bt_mesh_subnet *sub) { int i; diff --git a/subsys/bluetooth/host/mesh/foundation.h b/subsys/bluetooth/host/mesh/foundation.h index 79aae6d3356..59cbd8ebb71 100644 --- a/subsys/bluetooth/host/mesh/foundation.h +++ b/subsys/bluetooth/host/mesh/foundation.h @@ -127,6 +127,7 @@ void bt_mesh_attention(struct bt_mesh_model *model, u8_t time); u8_t *bt_mesh_label_uuid_get(u16_t addr); struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void); +struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void); u8_t bt_mesh_net_transmit_get(void); u8_t bt_mesh_relay_get(void); diff --git a/subsys/bluetooth/host/mesh/net.h b/subsys/bluetooth/host/mesh/net.h index 502345f04a6..74467827de7 100644 --- a/subsys/bluetooth/host/mesh/net.h +++ b/subsys/bluetooth/host/mesh/net.h @@ -205,6 +205,7 @@ enum { BT_MESH_IV_PENDING, BT_MESH_SEQ_PENDING, BT_MESH_HB_PUB_PENDING, + BT_MESH_CFG_PENDING, BT_MESH_MOD_PENDING, /* Don't touch - intentionally last */ diff --git a/subsys/bluetooth/host/mesh/settings.c b/subsys/bluetooth/host/mesh/settings.c index ee036cf0162..4793aa2afa7 100644 --- a/subsys/bluetooth/host/mesh/settings.c +++ b/subsys/bluetooth/host/mesh/settings.c @@ -68,6 +68,17 @@ struct hb_pub_val { indefinite:1; }; +/* Miscelaneous configuration server model states */ +struct cfg_val { + u8_t net_transmit; + u8_t relay; + u8_t relay_retransmit; + u8_t beacon; + u8_t gatt_proxy; + u8_t frnd; + u8_t default_ttl; +}; + /* IV Index & IV Update storage */ struct iv_val { u32_t iv_index; @@ -104,6 +115,14 @@ struct mod_pub_val { cred:1; }; +/* We need this so we don't overwrite app-hardcoded values in case FCB + * contains a history of changes but then has a NULL at the end. + */ +static struct { + bool valid; + struct cfg_val cfg; +} stored_cfg; + static int net_set(int argc, char **argv, char *val) { struct net_val net; @@ -482,6 +501,42 @@ static int hb_pub_set(int argc, char **argv, char *val) return 0; } +static int cfg_set(int argc, char **argv, char *val) +{ + struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); + int len, err; + + BT_DBG("val %s", val ? val : "(null)"); + + if (!cfg) { + return -ENOENT; + } + + if (!val) { + stored_cfg.valid = false; + BT_DBG("Cleared configuration state"); + return 0; + } + + len = sizeof(stored_cfg.cfg); + err = settings_bytes_from_str(val, &stored_cfg.cfg, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(stored_cfg.cfg)) { + BT_ERR("Unexpected value length (%d != %zu)", len, + sizeof(stored_cfg.cfg)); + return -EINVAL; + } + + stored_cfg.valid = true; + BT_DBG("Restored configuration state"); + + return 0; +} + static int mod_set_bind(struct bt_mesh_model *mod, char *val) { int len, err, i; @@ -642,6 +697,7 @@ const struct mesh_setting { { "NetKey", net_key_set }, { "AppKey", app_key_set }, { "HBPub", hb_pub_set }, + { "Cfg", cfg_set }, { "s", sig_mod_set }, { "v", vnd_mod_set }, }; @@ -718,6 +774,7 @@ static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, static int mesh_commit(void) { struct bt_mesh_hb_pub *hb_pub; + struct bt_mesh_cfg_srv *cfg; int i; BT_DBG("sub[0].net_idx 0x%03x", bt_mesh.sub[0].net_idx); @@ -763,6 +820,17 @@ static int mesh_commit(void) k_work_submit(&hb_pub->timer.work); } + cfg = bt_mesh_cfg_get(); + if (cfg && stored_cfg.valid) { + cfg->net_transmit = stored_cfg.cfg.net_transmit; + cfg->relay = stored_cfg.cfg.relay; + cfg->relay_retransmit = stored_cfg.cfg.relay_retransmit; + cfg->beacon = stored_cfg.cfg.beacon; + cfg->gatt_proxy = stored_cfg.cfg.gatt_proxy; + cfg->frnd = stored_cfg.cfg.frnd; + cfg->default_ttl = stored_cfg.cfg.default_ttl; + } + bt_mesh.valid = 1; bt_mesh_net_start(); @@ -986,6 +1054,41 @@ static void store_pending_hb_pub(void) settings_save_one("bt/mesh/HBPub", str); } +static void store_pending_cfg(void) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct cfg_val))]; + struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); + struct cfg_val val; + char *str; + + if (!cfg) { + return; + } + + val.net_transmit = cfg->net_transmit; + val.relay = cfg->relay; + val.relay_retransmit = cfg->relay_retransmit; + val.beacon = cfg->beacon; + val.gatt_proxy = cfg->gatt_proxy; + val.frnd = cfg->frnd; + val.default_ttl = cfg->default_ttl; + + str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode configuration as value"); + return; + } + + BT_DBG("Saving configuration as value %s", str); + settings_save_one("bt/mesh/Cfg", str); +} + +static void clear_cfg(void) +{ + BT_DBG("Clearing configuration"); + settings_save_one("bt/mesh/Cfg", NULL); +} + static void clear_app_key(u16_t app_idx) { char path[20]; @@ -1273,6 +1376,14 @@ static void store_pending(struct k_work *work) store_pending_hb_pub(); } + if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_CFG_PENDING)) { + if (bt_mesh.valid) { + store_pending_cfg(); + } else { + clear_cfg(); + } + } + if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_MOD_PENDING)) { bt_mesh_model_foreach(store_pending_mod, NULL); } @@ -1370,10 +1481,16 @@ void bt_mesh_store_hb_pub(void) schedule_store(BT_MESH_HB_PUB_PENDING); } +void bt_mesh_store_cfg(void) +{ + schedule_store(BT_MESH_CFG_PENDING); +} + void bt_mesh_clear_net(void) { schedule_store(BT_MESH_NET_PENDING); schedule_store(BT_MESH_IV_PENDING); + schedule_store(BT_MESH_CFG_PENDING); } void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub) diff --git a/subsys/bluetooth/host/mesh/settings.h b/subsys/bluetooth/host/mesh/settings.h index 6b186094d71..862e42e3f19 100644 --- a/subsys/bluetooth/host/mesh/settings.h +++ b/subsys/bluetooth/host/mesh/settings.h @@ -11,6 +11,7 @@ void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl); void bt_mesh_store_subnet(struct bt_mesh_subnet *sub); void bt_mesh_store_app_key(struct bt_mesh_app_key *key); void bt_mesh_store_hb_pub(void); +void bt_mesh_store_cfg(void); void bt_mesh_store_mod_bind(struct bt_mesh_model *mod); void bt_mesh_store_mod_sub(struct bt_mesh_model *mod); void bt_mesh_store_mod_pub(struct bt_mesh_model *mod);