diff --git a/samples/bluetooth/peripheral/prj.conf b/samples/bluetooth/peripheral/prj.conf index 7973a614458..dd695046076 100644 --- a/samples/bluetooth/peripheral/prj.conf +++ b/samples/bluetooth/peripheral/prj.conf @@ -1,3 +1,6 @@ +# Incresed stack due to settings API usage +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + CONFIG_BT=y CONFIG_BT_DEBUG_LOG=y CONFIG_BT_SMP=y @@ -7,3 +10,11 @@ CONFIG_BT_ATT_PREPARE_COUNT=2 CONFIG_BT_PRIVACY=y CONFIG_BT_DEVICE_NAME="Test peripheral" CONFIG_BT_DEVICE_APPEARANCE=833 + +CONFIG_BT_SETTINGS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y +CONFIG_FCB=y +CONFIG_SETTINGS=y +CONFIG_SETTINGS_FCB=y diff --git a/samples/bluetooth/peripheral/src/main.c b/samples/bluetooth/peripheral/src/main.c index 365c0312154..bf8d3c5187a 100644 --- a/samples/bluetooth/peripheral/src/main.c +++ b/samples/bluetooth/peripheral/src/main.c @@ -14,6 +14,8 @@ #include #include +#include + #include #include #include @@ -242,6 +244,10 @@ static void bt_ready(int err) dis_init(CONFIG_SOC, "Manufacturer"); bt_gatt_service_register(&vnd_svc); + if (IS_ENABLED(CONFIG_SETTINGS)) { + settings_load(); + } + err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (err) { diff --git a/subsys/bluetooth/host/CMakeLists.txt b/subsys/bluetooth/host/CMakeLists.txt index 856cb1585f5..b560e2c0610 100644 --- a/subsys/bluetooth/host/CMakeLists.txt +++ b/subsys/bluetooth/host/CMakeLists.txt @@ -13,6 +13,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_A2DP a2dp.c) zephyr_library_sources_ifdef(CONFIG_BT_AVDTP avdtp.c) zephyr_library_sources_ifdef(CONFIG_BT_RFCOMM rfcomm.c) zephyr_library_sources_ifdef(CONFIG_BT_TESTING testing.c) +zephyr_library_sources_ifdef(CONFIG_BT_SETTINGS settings.c) zephyr_library_sources_ifdef( CONFIG_BT_BREDR diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index c69f9c810f2..5a594188f67 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -95,6 +95,7 @@ config BT_RX_STACK_SIZE int "Size of the receiving thread stack" depends on BT_HCI_HOST || BT_RECV_IS_RX_THREAD default 1024 + default 2048 if BT_SETTINGS default 2048 if BT_MESH default 512 if BT_HCI_RAW range 512 65536 if BT_HCI_RAW @@ -130,6 +131,23 @@ config BT_HOST_CRYPTO select TINYCRYPT_SHA256_HMAC select TINYCRYPT_SHA256_HMAC_PRNG +config BT_SETTINGS + bool "Store Bluetooth state and configuration persistently" + depends on SETTINGS + select MPU_ALLOW_FLASH_WRITE if ARM_MPU + help + When selected, the Bluetooth stack will take care of storing + (and restoring) the Bluetooth state (e.g. pairing keys) and + configuration persistently in flash. + + When this option has been enabled, it's important that the + application makes a call to settings_load() after having done + all necessary initialization (e.g. calling bt_enable). The + reason settings_load() is handled externally to the stack, is + that there may be other subsystems using the settings API, in + which case it's more efficient to load all settings in one go, + instead of each subsystem doing it independently. + config BT_INTERNAL_STORAGE bool "Use an internal persistent storage handler" depends on FILE_SYSTEM @@ -350,6 +368,12 @@ config BT_TINYCRYPT_ECC Connections so that Hosts can make use of those. if BT_DEBUG +config BT_DEBUG_SETTINGS + bool "Bluetooth storage debug" + depends on BT_SETTINGS + help + This option enables debug support for Bluetooth storage. + config BT_DEBUG_HCI_CORE bool "Bluetooth HCI core debug" help diff --git a/subsys/bluetooth/host/hci_core.c b/subsys/bluetooth/host/hci_core.c index 1faad4b10c2..d5af97f21fb 100644 --- a/subsys/bluetooth/host/hci_core.c +++ b/subsys/bluetooth/host/hci_core.c @@ -41,6 +41,7 @@ #include "l2cap_internal.h" #include "smp.h" #include "crypto.h" +#include "settings.h" /* Peripheral timeout to initialize Connection Parameter Update procedure */ #define CONN_UPDATE_TIMEOUT K_SECONDS(5) @@ -4143,7 +4144,7 @@ static const char *ver_str(u8_t ver) return "unknown"; } -static void show_dev_info(void) +void bt_dev_show_info(void) { BT_INFO("Identity: %s", bt_addr_le_str(&bt_dev.id_addr)); BT_INFO("HCI: version %s (0x%02x) revision 0x%04x, manufacturer 0x%04x", @@ -4154,7 +4155,7 @@ static void show_dev_info(void) bt_dev.lmp_subversion); } #else -static inline void show_dev_info(void) +void bt_dev_show_info(void) { } #endif /* CONFIG_BT_DEBUG */ @@ -4320,7 +4321,9 @@ static int hci_init(void) } } - show_dev_info(); + if (!IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_dev_show_info(); + } return 0; } @@ -4549,6 +4552,13 @@ int bt_enable(bt_ready_cb_t cb) return -EALREADY; } + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + err = bt_settings_init(); + if (err) { + return err; + } + } + ready_cb = cb; /* TX thread */ diff --git a/subsys/bluetooth/host/hci_core.h b/subsys/bluetooth/host/hci_core.h index 06f08f17443..91544a751bb 100644 --- a/subsys/bluetooth/host/hci_core.h +++ b/subsys/bluetooth/host/hci_core.h @@ -190,3 +190,5 @@ u16_t bt_hci_get_cmd_opcode(struct net_buf *buf); struct bt_keys; int bt_id_add(struct bt_keys *keys); int bt_id_del(struct bt_keys *keys); + +void bt_dev_show_info(void); diff --git a/subsys/bluetooth/host/settings.c b/subsys/bluetooth/host/settings.c new file mode 100644 index 00000000000..64f7c6164fe --- /dev/null +++ b/subsys/bluetooth/host/settings.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +#include +#include + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_SETTINGS) +#include "common/log.h" + +#include "hci_core.h" +#include "settings.h" + +static int set(int argc, char **argv, char *val) +{ + int len; + + BT_DBG("argc %d argv[0] %s val %s", argc, argv[0], val); + + if (argc != 1) { + return -ENOENT; + } + + if (!strcmp(argv[0], "id")) { + len = sizeof(bt_dev.id_addr); + settings_bytes_from_str(val, &bt_dev.id_addr, &len); + BT_DBG("ID Addr set to %s", bt_addr_le_str(&bt_dev.id_addr)); + return 0; + } + +#if defined(CONFIG_BT_PRIVACY) + if (!strcmp(argv[0], "irk")) { + len = sizeof(bt_dev.irk); + settings_bytes_from_str(val, bt_dev.irk, &len); + BT_DBG("IRK set to %s", bt_hex(bt_dev.irk, 16)); + return 0; + } +#endif /* CONFIG_BT_PRIVACY */ + + return 0; +} + +static void generate_static_addr(void) +{ + char buf[13]; + char *str; + + BT_DBG("Generating new static random address"); + + if (bt_addr_le_create_static(&bt_dev.id_addr)) { + BT_ERR("Failed to generate static addr"); + return; + } + + atomic_set_bit(bt_dev.flags, BT_DEV_ID_STATIC_RANDOM); + + BT_DBG("New ID Addr: %s", bt_addr_le_str(&bt_dev.id_addr)); + + str = settings_str_from_bytes(&bt_dev.id_addr, sizeof(bt_dev.id_addr), + buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode ID Addr as value"); + return; + } + + BT_DBG("Saving ID addr as value %s", str); + settings_save_one("bt/id", str); +} + +#if defined(CONFIG_BT_PRIVACY) +static void generate_irk(void) +{ + char buf[25]; + char *str; + + BT_DBG("Generating new IRK"); + + if (bt_rand(bt_dev.irk, sizeof(bt_dev.irk))) { + BT_ERR("Failed to generate IRK"); + return; + } + + BT_DBG("New local IRK: %s", bt_hex(bt_dev.irk, 16)); + + str = settings_str_from_bytes(bt_dev.irk, 16, buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode IRK as value"); + return; + } + + BT_DBG("Saving IRK as value %s", str); + settings_save_one("bt/irk", str); +} +#endif /* CONFIG_BT_PRIVACY */ + +static int commit(void) +{ + BT_DBG(""); + + if (!bt_addr_le_cmp(&bt_dev.id_addr, BT_ADDR_LE_ANY) || + !bt_addr_le_cmp(&bt_dev.id_addr, BT_ADDR_LE_NONE)) { + generate_static_addr(); + } + +#if defined(CONFIG_BT_PRIVACY) + { + u8_t zero[16] = { 0 }; + + if (!memcmp(bt_dev.irk, zero, 16)) { + generate_irk(); + } + } +#endif /* CONFIG_BT_PRIVACY */ + + bt_dev_show_info(); + + return 0; +} + +static struct settings_handler bt_settings = { + .name = "bt", + .h_set = set, + .h_commit = commit, +}; + +int bt_settings_init(void) +{ + int err; + + BT_DBG(""); + + err = settings_subsys_init(); + if (err) { + BT_ERR("settings_subsys_init failed (err %d)", err); + return err; + } + + err = settings_register(&bt_settings); + if (err) { + BT_ERR("settings_register failed (err %d)", err); + return err; + } + + return 0; +} diff --git a/subsys/bluetooth/host/settings.h b/subsys/bluetooth/host/settings.h new file mode 100644 index 00000000000..6f14f32a1ab --- /dev/null +++ b/subsys/bluetooth/host/settings.h @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +int bt_settings_init(void);