diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 7437becf6..44d7b1ad5 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -276,6 +276,19 @@ build_example_bluetooth_ble_services_ble_uds: variables: EXAMPLE_DIR: examples/bluetooth/ble_services/ble_uds +build_example_bluetooth_ble_services_ble_wss: + extends: + - .build_examples_template + - .rules:build:example_bluetooth_ble_services + parallel: + matrix: + - IMAGE: espressif/idf:release-v4.4 + - IMAGE: espressif/idf:release-v5.0 + - IMAGE: espressif/idf:release-v5.1 + - IMAGE: espressif/idf:release-v5.2 + variables: + EXAMPLE_DIR: examples/bluetooth/ble_services/ble_wss + build_example_bluetooth_ble_ota: extends: - .build_examples_template diff --git a/components/bluetooth/ble_services/CHANGELOG.md b/components/bluetooth/ble_services/CHANGELOG.md index e3222ea4e..fce73ec8e 100644 --- a/components/bluetooth/ble_services/CHANGELOG.md +++ b/components/bluetooth/ble_services/CHANGELOG.md @@ -1,3 +1,10 @@ +## v1.0.0 - 2024.12.27 + +Features: +- BCS: Support Body Composition Service +- CTS: Support Body Composition Service +- UDS: Support Body Composition Service + ## v0.2.0 - 2024.10.31 Features: diff --git a/components/bluetooth/ble_services/CMakeLists.txt b/components/bluetooth/ble_services/CMakeLists.txt index dea8a10b2..03ab1d456 100644 --- a/components/bluetooth/ble_services/CMakeLists.txt +++ b/components/bluetooth/ble_services/CMakeLists.txt @@ -49,6 +49,11 @@ list(APPEND srcs "cts/src/esp_cts.c") list(APPEND include "cts/include") endif() +if(CONFIG_BLE_WSS) +list(APPEND srcs "wss/src/esp_wss.c") +list(APPEND include "wss/include") +endif() + list(APPEND req "ble_conn_mgr") idf_component_register(SRCS "${srcs}" diff --git a/components/bluetooth/ble_services/Kconfig b/components/bluetooth/ble_services/Kconfig index 4e3157322..ee1245727 100644 --- a/components/bluetooth/ble_services/Kconfig +++ b/components/bluetooth/ble_services/Kconfig @@ -9,5 +9,6 @@ menu "BLE Standard Services" orsource "./hts/Kconfig.in" orsource "./tps/Kconfig.in" orsource "./uds/Kconfig.in" + orsource "./wss/Kconfig.in" endmenu diff --git a/components/bluetooth/ble_services/README.md b/components/bluetooth/ble_services/README.md index a66414f01..40b07d747 100644 --- a/components/bluetooth/ble_services/README.md +++ b/components/bluetooth/ble_services/README.md @@ -35,6 +35,7 @@ The example will be downloaded to the current folder. You can navigate into it f 7. [ble_hts](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_hts) 8. [ble_tps](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_tps) 9. [ble_uds](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_uds) +10. [ble_wss](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_wss) ### Q&A diff --git a/components/bluetooth/ble_services/idf_component.yml b/components/bluetooth/ble_services/idf_component.yml index ace4cca50..0e1e5fd02 100644 --- a/components/bluetooth/ble_services/idf_component.yml +++ b/components/bluetooth/ble_services/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.2.0" +version: "1.0.0" description: BLE standard GATT services support url: https://github.com/espressif/esp-iot-solution/tree/master/components/bluetooth/ble_services issues: https://github.com/espressif/esp-iot-solution/issues diff --git a/components/bluetooth/ble_services/wss/Kconfig.in b/components/bluetooth/ble_services/wss/Kconfig.in new file mode 100644 index 000000000..018aef27d --- /dev/null +++ b/components/bluetooth/ble_services/wss/Kconfig.in @@ -0,0 +1,8 @@ +# Weight Scale Service + +menuconfig BLE_WSS + bool "GATT Weight Scale Service" + +if BLE_WSS + +endif # BLE_WSS diff --git a/components/bluetooth/ble_services/wss/include/esp_wss.h b/components/bluetooth/ble_services/wss/include/esp_wss.h new file mode 100644 index 000000000..2c4f5b717 --- /dev/null +++ b/components/bluetooth/ble_services/wss/include/esp_wss.h @@ -0,0 +1,137 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include + +#include "esp_err.h" +#include "esp_event_base.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* 16 Bit Weight Scale Service UUID */ +#define BLE_WSS_UUID16 0x181D + +/* 16 Bit Weight Scale Characteristics UUID */ +#define BLE_WSS_CHR_UUID16_WEIGHT_FEATURE 0x2A9E +#define BLE_WSS_CHR_UUID16_WEIGHT_MEASUREMENT 0x2A9D + +/* Weight Scale Feature masks */ +#define BLE_WSS_TIMESTAMP_MASK (1 << 0) +#define BLE_WSS_MULTI_USER_MASK (1 << 1) +#define BLE_WSS_BMI_MASK (1 << 2) + +/* Weight resolution offset*/ +#define BLE_WSS_WEIGHT_RESOLUTION_OFSET (3) + +#define BLE_WSS_WEIGHT_RESOLUTION_NONE (0x0) +#define BLE_WSS_WEIGHT_RESOLUTION_0P5_KG (0x1) +#define BLE_WSS_WEIGHT_RESOLUTION_0P2_KG (0x2) +#define BLE_WSS_WEIGHT_RESOLUTION_0P1_KG (0x3) +#define BLE_WSS_WEIGHT_RESOLUTION_0P05_KG (0x4) +#define BLE_WSS_WEIGHT_RESOLUTION_0P02_KG (0x5) +#define BLE_WSS_WEIGHT_RESOLUTION_0P01_KG (0x6) +#define BLE_WSS_WEIGHT_RESOLUTION_0P005_KG (0x7) + +/* Height resolution offset*/ +#define BLE_WSS_HEIGHT_RESOLUTION_OFSET (6) + +#define BLE_WSS_HEIGHT_RESOLUTION_NONE (0x0) +#define BLE_WSS_HEIGHT_RESOLUTION_0P01_M (0x1) +#define BLE_WSS_HEIGHT_RESOLUTION_0P005_M (0x2) +#define BLE_WSS_HEIGHT_RESOLUTION_0P001_M (0x3) + +/* Weight Scale Measurement Flag */ +#define BLE_WSS_MEASUREMENT_UINTS_FLAG (1 << 0) +#define BLE_WSS_TIME_STAMP_FLAG (1 << 1) +#define BLE_WSS_USER_ID_FLAG (1 << 2) +#define BLE_WSS_BMI_FLAG (1 << 3) + +/** + * @brief Weight Scale Feature + */ +typedef struct { + uint32_t timestamp: 1; /*!< 0: Don't Support, 1: Support */ + uint32_t user_id: 1; /*!< 0: Don't Support, 1: Support */ + uint32_t bmi: 1; /*!< 0: Don't Support, 1: Support */ + uint32_t weight: 1; /*!< 0: Don't Support, 1: Support */ + uint32_t w_resolution: 3; /*!< If weight support, this filed should present */ + uint32_t height: 1; /*!< 0: Don't Support, 1: Support */ + uint32_t h_resolution: 2; /*!< If height support, this filed should present */ +} esp_ble_wss_feature_t; /*!< The structure of the weight scale feature field */ + +/** + * @brief weight Measurement + */ +typedef struct { + struct { + uint32_t measurement_unit: 1; /*!< 0: Kg & meter, 1: reference to weight and height resolution */ + uint32_t time_present: 1; /*!< 0: Don't contain time information, 1: time stamp present */ + uint32_t user_present: 1; /*!< 0: Don't contain user index, 1: contain user index */ + uint32_t bmi_height_present: 1; /*!< 0: Don't contain BMI and height, 1: contain BMI and height */ + } flag; /*!< Flag */ + + uint16_t weight; /*!< weight */ + + struct { + uint16_t year; /*!< Year as defined by the Gregorian calendar, Valid range 1582 to 9999 */ + uint8_t month; /*!< Month of the year as defined by the Gregorian calendar, Valid range 1 (January) to 12 (December) */ + uint8_t day; /*!< Day of the month as defined by the Gregorian calendar, Valid range 1 to 31 */ + uint8_t hours; /*!< Number of hours past midnight, Valid range 0 to 23 */ + uint8_t minutes; /*!< Number of minutes since the start of the hour. Valid range 0 to 59 */ + uint8_t seconds; /*!< Number of seconds since the start of the minute. Valid range 0 to 59 */ + } __attribute__((packed)) timestamp; /*!< The date and time */ + + uint8_t user_id; /*!< User index */ + uint8_t bmi; /*!< BMI */ + uint16_t height; /*!< Height */ + uint8_t weight_resolution; /*!< Weight resolution */ + uint8_t height_resolution; /*!< Height resolution */ +} __attribute__((packed)) esp_ble_wss_measurement_t; + +/** + * @brief Read the weight measurement characteristic value. + * + * @param[in] out_val The pointer to store the weight measurement value. + * + * @return + * - ESP_OK on successful + * - ESP_ERR_INVALID_ARG on wrong parameter + */ +esp_err_t esp_ble_wss_get_measurement(esp_ble_wss_measurement_t *out_val); + +/** + * @brief Set the weight measurement characteristic value. + * + * @param[in] in_val The pointer to store the weight measurement. + * + * @param[in] need_send send the weight measurement information to remote client. + * + * @return + * - ESP_OK on successful + * - ESP_ERR_INVALID_ARG on wrong initialization + * - ESP_FAIL on error + */ +esp_err_t esp_ble_wss_set_measurement(esp_ble_wss_measurement_t *in_val, bool need_send); + +/** + * @brief Initialization Weight Scale Service + * + * @return + * - ESP_OK on successful + * - ESP_ERR_INVALID_ARG on wrong initialization + * - ESP_FAIL on error + */ +esp_err_t esp_ble_wss_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/bluetooth/ble_services/wss/src/esp_wss.c b/components/bluetooth/ble_services/wss/src/esp_wss.c new file mode 100644 index 000000000..17b7a9208 --- /dev/null +++ b/components/bluetooth/ble_services/wss/src/esp_wss.c @@ -0,0 +1,172 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Weight Scale Service(WSS) + */ + +#include + +#include "esp_ble_conn_mgr.h" +#include "esp_wss.h" + +#define BLE_WSS_MAX_VAL_LEN 20 + +typedef struct { + uint8_t len; + uint8_t buf[BLE_WSS_MAX_VAL_LEN]; +} indicate_buf_t; + +/* Weight Scale Feature value */ +static esp_ble_wss_feature_t s_wss_feature = { + .timestamp = 1, + .user_id = 1, + .bmi = 1, + .weight = 1, + .w_resolution = 1, + .height = 1, + .h_resolution = 1 +}; + +static esp_ble_wss_measurement_t s_wss_measurement; + +static void build_wss_ind_buf(esp_ble_wss_measurement_t *in_val, indicate_buf_t *out_buf) +{ + uint32_t offset = 0; + + /* Add Flag */ + memcpy(out_buf->buf + offset, &(in_val->flag), sizeof(uint32_t)); + offset += sizeof(uint32_t); + + /* Add weight */ + memcpy(out_buf->buf + offset, &(in_val->weight), sizeof(uint16_t)); + offset += sizeof(uint32_t); + + if (in_val->flag.time_present == 1) { + memcpy(out_buf->buf + offset, &(in_val->timestamp), sizeof(in_val->timestamp)); + offset += sizeof(in_val->timestamp); // timestamp length + } + + if (in_val->flag.user_present == 1) { + memcpy(out_buf->buf + offset, &(in_val->user_id), sizeof(uint8_t)); + offset += sizeof(uint8_t); // user id length + } + + if (in_val->flag.bmi_height_present == 1) { + memcpy(out_buf->buf + offset, &(in_val->bmi), sizeof(uint8_t)); + offset += sizeof(uint8_t); // bmi length + + memcpy(out_buf->buf + offset, &(in_val->height), sizeof(uint16_t)); + offset += sizeof(uint16_t); // height length + } + + out_buf->len = offset; + + return; +} + +esp_err_t esp_ble_wss_get_measurement(esp_ble_wss_measurement_t *out_val) +{ + if (!out_val) { + return ESP_ERR_INVALID_ARG; + } + + memcpy(out_val, &s_wss_measurement, sizeof(esp_ble_wss_measurement_t)); + + return ESP_OK; +} + +esp_err_t esp_ble_wss_set_measurement(esp_ble_wss_measurement_t *in_val, bool need_send) +{ + if (in_val == NULL) { + return ESP_ERR_INVALID_ARG; + } + + memcpy(&s_wss_measurement, in_val, sizeof(esp_ble_wss_measurement_t)); + + /* Set Weight Scale Feature Bit Masks */ + memset(&s_wss_feature, 0x0, sizeof(esp_ble_wss_feature_t)); + s_wss_feature.weight = 1; + + if (in_val->flag.measurement_unit == 0x1) { + s_wss_feature.w_resolution = in_val->weight_resolution; + s_wss_feature.h_resolution = in_val->height_resolution; + } + + if (in_val->flag.time_present == 0x1) { + s_wss_feature.timestamp = 1; + } + + if (in_val->flag.user_present == 0x1) { + s_wss_feature.user_id = 1; + } + + if (in_val->flag.bmi_height_present == 0x1) { + s_wss_feature.bmi = 1; + s_wss_feature.height = 1; + } + + indicate_buf_t out_buf; + + /* Build Body Composition Measurement value */ + build_wss_ind_buf(in_val, &out_buf); + + esp_ble_conn_data_t conn_data = { + .type = BLE_CONN_UUID_TYPE_16, + .uuid = { + .uuid16 = BLE_WSS_CHR_UUID16_WEIGHT_MEASUREMENT, + }, + .data = out_buf.buf, + .data_len = out_buf.len, + }; + + return esp_ble_conn_write(&conn_data); +} + +static esp_err_t wss_feature_cb(const uint8_t *inbuf, uint16_t inlen, + uint8_t **outbuf, uint16_t *outlen, void *priv_data) +{ + uint8_t len = sizeof(s_wss_feature); + + if (inbuf || !outbuf || !outlen) { + return ESP_ERR_INVALID_ARG; + } + + *outbuf = calloc(1, len); + if (!(*outbuf)) { + return ESP_ERR_NO_MEM; + } + + memcpy(*outbuf, &s_wss_feature, len); + *outlen = len; + + return ESP_OK; +} + +static const esp_ble_conn_character_t nu_lookup_table[] = { + { + "weight feature", BLE_CONN_UUID_TYPE_16, BLE_CONN_GATT_CHR_READ + , { BLE_WSS_CHR_UUID16_WEIGHT_FEATURE }, wss_feature_cb + }, + { + "weight measurement", BLE_CONN_UUID_TYPE_16, BLE_CONN_GATT_CHR_INDICATE + , { BLE_WSS_CHR_UUID16_WEIGHT_MEASUREMENT }, NULL + }, +}; + +static const esp_ble_conn_svc_t svc = { + .type = BLE_CONN_UUID_TYPE_16, + .uuid = { + .uuid16 = BLE_WSS_UUID16, + }, + .nu_lookup_count = sizeof(nu_lookup_table) / sizeof(nu_lookup_table[0]), + .nu_lookup = (esp_ble_conn_character_t *)nu_lookup_table +}; + +esp_err_t esp_ble_wss_init(void) +{ + return esp_ble_conn_add_svc(&svc); +} diff --git a/docs/Doxyfile b/docs/Doxyfile index 2105e2b3a..dec8137ec 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -38,6 +38,7 @@ INPUT = \ $(PROJECT_PATH)/components/bluetooth/ble_services/hts/include/esp_hts.h \ $(PROJECT_PATH)/components/bluetooth/ble_services/tps/include/esp_tps.h \ $(PROJECT_PATH)/components/bluetooth/ble_services/uds/include/esp_uds.h \ + $(PROJECT_PATH)/components/bluetooth/ble_services/wss/include/esp_wss.h \ $(PROJECT_PATH)/components/bus/include/i2s_lcd_driver.h \ $(PROJECT_PATH)/components/button/include/iot_button.h \ $(PROJECT_PATH)/components/display/screen/interface_driver/scr_interface_driver.h \ diff --git a/docs/en/bluetooth/ble_services.rst b/docs/en/bluetooth/ble_services.rst index 7c31632bc..f9bed180b 100644 --- a/docs/en/bluetooth/ble_services.rst +++ b/docs/en/bluetooth/ble_services.rst @@ -14,3 +14,4 @@ BLE Services Health Thermometer Service TX Power Service User Data Service + Weight Scale Service diff --git a/docs/en/bluetooth/ble_wss.rst b/docs/en/bluetooth/ble_wss.rst new file mode 100644 index 000000000..2a2bae388 --- /dev/null +++ b/docs/en/bluetooth/ble_wss.rst @@ -0,0 +1,15 @@ +Weight Scale Service +============================== +:link_to_translation:`zh_CN:[中文]` + +This Weight Scale Service exposes weight and related data from a weight scale intended for consumer healthcare and sports/fitness applications. + +Examples +-------------- + +:example:`bluetooth/ble_services/ble_wss`. + +API Reference +----------------- + +.. include-build-file:: inc/esp_wss.inc diff --git a/docs/sphinx-known-warnings.txt b/docs/sphinx-known-warnings.txt index 5d7c3bb3a..248b97deb 100644 --- a/docs/sphinx-known-warnings.txt +++ b/docs/sphinx-known-warnings.txt @@ -4,7 +4,7 @@ Declaration is '.. cpp:member:: lightbulb_color_mapping_data_t * table'. lightbulb.inc:line: WARNING: Duplicate C++ declaration, also defined at electrical_lighting_solution/lightbulb_driver:line. -Declaration is '.. cpp:member:: struct lightbulb_config_t::@43::@47 precise'. +Declaration is '.. cpp:member:: struct lightbulb_config_t::@45::@49 precise'. lightbulb.inc:line: WARNING: Duplicate C++ declaration, also defined at electrical_lighting_solution/lightbulb_driver:line. diff --git a/docs/zh_CN/bluetooth/ble_services.rst b/docs/zh_CN/bluetooth/ble_services.rst index 1254d6ca3..125e5d2b4 100644 --- a/docs/zh_CN/bluetooth/ble_services.rst +++ b/docs/zh_CN/bluetooth/ble_services.rst @@ -14,3 +14,4 @@ BLE 服务 健康温度计服务 TX 电源服务 用户数据服务 + 体重秤服务 diff --git a/docs/zh_CN/bluetooth/ble_wss.rst b/docs/zh_CN/bluetooth/ble_wss.rst new file mode 100644 index 000000000..a0c46a51e --- /dev/null +++ b/docs/zh_CN/bluetooth/ble_wss.rst @@ -0,0 +1,15 @@ +体重秤服务 +============================== +:link_to_translation:`en:[English]` + +体重秤服务用于从健康和体育健身的体重秤中获取体重相关数据。 + +示例 +-------------- + +:example:`bluetooth/ble_services/ble_wss`. + +API 参考 +----------------- + +.. include-build-file:: inc/esp_wss.inc diff --git a/examples/.build-rules.yml b/examples/.build-rules.yml index 1a507d54f..e5a8f1410 100644 --- a/examples/.build-rules.yml +++ b/examples/.build-rules.yml @@ -114,6 +114,13 @@ examples/bluetooth/ble_services/ble_uds: - if: IDF_TARGET in ["esp32","esp32s3","esp32c2","esp32c3"] and (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR == 0) - if: IDF_TARGET in ["esp32","esp32s3","esp32c2","esp32c3","esp32c6","esp32h2"] and (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR == 1) +examples/bluetooth/ble_services/ble_wss: + enable: + - if: IDF_TARGET in ["esp32","esp32c3"] and (IDF_VERSION_MAJOR == 4 and IDF_VERSION_MINOR == 3) + - if: IDF_TARGET in ["esp32","esp32s3","esp32c3"] and (IDF_VERSION_MAJOR == 4 and IDF_VERSION_MINOR == 4) + - if: IDF_TARGET in ["esp32","esp32s3","esp32c2","esp32c3"] and (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR == 0) + - if: IDF_TARGET in ["esp32","esp32s3","esp32c2","esp32c3","esp32c6","esp32h2"] and (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR == 1) + examples/bluetooth/ble_ota: enable: - if: IDF_TARGET in ["esp32","esp32c3","esp32s3"] and (IDF_VERSION_MAJOR == 4 and IDF_VERSION_MINOR == 4) diff --git a/examples/bluetooth/ble_services/ble_ans/main/idf_component.yml b/examples/bluetooth/ble_services/ble_ans/main/idf_component.yml index 5fcf5940f..10a79099a 100644 --- a/examples/bluetooth/ble_services/ble_ans/main/idf_component.yml +++ b/examples/bluetooth/ble_services/ble_ans/main/idf_component.yml @@ -4,5 +4,5 @@ dependencies: version: "~0.*" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.*" + version: "~1.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_bas/main/idf_component.yml b/examples/bluetooth/ble_services/ble_bas/main/idf_component.yml index 5fcf5940f..10a79099a 100644 --- a/examples/bluetooth/ble_services/ble_bas/main/idf_component.yml +++ b/examples/bluetooth/ble_services/ble_bas/main/idf_component.yml @@ -4,5 +4,5 @@ dependencies: version: "~0.*" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.*" + version: "~1.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_bcs/main/idf_component.yml b/examples/bluetooth/ble_services/ble_bcs/main/idf_component.yml index 5fcf5940f..10a79099a 100644 --- a/examples/bluetooth/ble_services/ble_bcs/main/idf_component.yml +++ b/examples/bluetooth/ble_services/ble_bcs/main/idf_component.yml @@ -4,5 +4,5 @@ dependencies: version: "~0.*" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.*" + version: "~1.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_cts/main/idf_component.yml b/examples/bluetooth/ble_services/ble_cts/main/idf_component.yml index 5fcf5940f..10a79099a 100644 --- a/examples/bluetooth/ble_services/ble_cts/main/idf_component.yml +++ b/examples/bluetooth/ble_services/ble_cts/main/idf_component.yml @@ -4,5 +4,5 @@ dependencies: version: "~0.*" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.*" + version: "~1.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_dis/main/idf_component.yml b/examples/bluetooth/ble_services/ble_dis/main/idf_component.yml index 5fcf5940f..10a79099a 100644 --- a/examples/bluetooth/ble_services/ble_dis/main/idf_component.yml +++ b/examples/bluetooth/ble_services/ble_dis/main/idf_component.yml @@ -4,5 +4,5 @@ dependencies: version: "~0.*" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.*" + version: "~1.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_hrs/main/idf_component.yml b/examples/bluetooth/ble_services/ble_hrs/main/idf_component.yml index 5fcf5940f..10a79099a 100644 --- a/examples/bluetooth/ble_services/ble_hrs/main/idf_component.yml +++ b/examples/bluetooth/ble_services/ble_hrs/main/idf_component.yml @@ -4,5 +4,5 @@ dependencies: version: "~0.*" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.*" + version: "~1.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_hts/main/idf_component.yml b/examples/bluetooth/ble_services/ble_hts/main/idf_component.yml index 5fcf5940f..10a79099a 100644 --- a/examples/bluetooth/ble_services/ble_hts/main/idf_component.yml +++ b/examples/bluetooth/ble_services/ble_hts/main/idf_component.yml @@ -4,5 +4,5 @@ dependencies: version: "~0.*" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.*" + version: "~1.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_tps/main/idf_component.yml b/examples/bluetooth/ble_services/ble_tps/main/idf_component.yml index 5fcf5940f..10a79099a 100644 --- a/examples/bluetooth/ble_services/ble_tps/main/idf_component.yml +++ b/examples/bluetooth/ble_services/ble_tps/main/idf_component.yml @@ -4,5 +4,5 @@ dependencies: version: "~0.*" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.*" + version: "~1.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_uds/main/idf_component.yml b/examples/bluetooth/ble_services/ble_uds/main/idf_component.yml index 5fcf5940f..10a79099a 100644 --- a/examples/bluetooth/ble_services/ble_uds/main/idf_component.yml +++ b/examples/bluetooth/ble_services/ble_uds/main/idf_component.yml @@ -4,5 +4,5 @@ dependencies: version: "~0.*" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.*" + version: "~1.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_wss/CMakeLists.txt b/examples/bluetooth/ble_services/ble_wss/CMakeLists.txt new file mode 100644 index 000000000..896030fa4 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_wss/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(ble_wss) diff --git a/examples/bluetooth/ble_services/ble_wss/README.md b/examples/bluetooth/ble_services/ble_wss/README.md new file mode 100644 index 000000000..2ef7b6c92 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_wss/README.md @@ -0,0 +1,90 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C2 | ESP32-S3 | ESP32-H2 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | + +# BLE User Data Service Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example creates a GATT server and starts advertising, waiting to be connected by a GATT client. + +The device information service exposes manufacturer and/or vendor information about a device. + +It uses Bluetooth controller based on BLE connection management. + +This example aims at understanding BLE Body Composition service and BLE connection management APIs. + +To test this demo, any BLE scanner app can be used. + +## How to Use Example + +Before project configuration and build, be sure to set the correct chip target using: + +```bash +idf.py set-target +``` + +### Hardware Required + +* A development board with ESP32/ESP32-C3/ESP32-C2/ESP32-S3 SoC +* A USB cable for Power supply and programming + +See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it. + +### Configure the project + +Open the project configuration menu: + +```bash +idf.py menuconfig +``` + +In the `Example Configuration` menu: + +* Select advertisement name of device from `Example Configuration --> Advertisement name`, default is `BLE_WSS`. + +In the `BLE Standard Services` menu: + +* Select the optional functions of device from `GATT Weight Scale Service`, default is disable. + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects. + +## Example Output1 + +There is this console output when bleprph is connected and characteristic is read: + +``` +I (330) BLE_INIT: BT controller compile version [9359a4d] +I (340) system_api: Base MAC address is not set +I (340) system_api: read default base MAC address from EFUSE +I (350) BLE_INIT: Bluetooth MAC: 58:cf:79:1e:9e:de + +I (350) phy_init: phy_version 1150,7c3c08f,Jan 24 2024,17:32:21 +I (410) blecm_nimble: BLE Host Task Started +I (410) blecm_nimble: No characteristic(0x2a00) found +I (410) blecm_nimble: No characteristic(0x2a01) found +I (410) blecm_nimble: No characteristic(0x2a05) found +I (420) NimBLE: GAP procedure initiated: stop advertising. + +I (430) NimBLE: GAP procedure initiated: advertise; +I (430) NimBLE: disc_mode=2 +I (440) NimBLE: adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=256 adv_itvl_max=256 +I (450) NimBLE: + +I (450) main_task: Returned from app_main() + + +``` + +## Troubleshooting + +For any technical queries, please open an [issue](https://github.com/espressif/esp-iot-solution/issues) on GitHub. We will get back to you soon. diff --git a/examples/bluetooth/ble_services/ble_wss/main/CMakeLists.txt b/examples/bluetooth/ble_services/ble_wss/main/CMakeLists.txt new file mode 100644 index 000000000..5695bd667 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_wss/main/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register(SRCS "app_main.c") diff --git a/examples/bluetooth/ble_services/ble_wss/main/Kconfig.projbuild b/examples/bluetooth/ble_services/ble_wss/main/Kconfig.projbuild new file mode 100644 index 000000000..f0642cfb6 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_wss/main/Kconfig.projbuild @@ -0,0 +1,13 @@ +menu "Example Configuration" + config EXAMPLE_BLE_ADV_NAME + string "Advertisement name" + default "BLE_CTS" + help + The device name inside advertisement. + + config EXAMPLE_BLE_SUB_ADV + string "Subsequent advertisement data" + default "SUB_ADV" + help + The data inside subsequent advertisements. +endmenu diff --git a/examples/bluetooth/ble_services/ble_wss/main/app_main.c b/examples/bluetooth/ble_services/ble_wss/main/app_main.c new file mode 100644 index 000000000..2497702cf --- /dev/null +++ b/examples/bluetooth/ble_services/ble_wss/main/app_main.c @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "esp_idf_version.h" +#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) +#include "esp_random.h" +#include "esp_mac.h" +#else +#include "esp_system.h" +#endif + +#include "esp_ble_conn_mgr.h" +#include "esp_wss.h" + +static const char *TAG = "app_main"; + +static void app_ble_wss_init(void) +{ + esp_ble_wss_init(); +} + +static void app_ble_conn_event_handler(void *handler_args, esp_event_base_t base, int32_t id, void *event_data) +{ + esp_ble_wss_measurement_t wss_measurement = { + .flag.measurement_unit = 0x1, + .flag.time_present = 0x1, + .flag.user_present = 0x1, + .flag.bmi_height_present = 0x1, + .timestamp.year = 2024, + .timestamp.month = 10, + .timestamp.day = 1, + .timestamp.hours = 9, + .timestamp.minutes = 10, + .timestamp.seconds = 25, + .user_id = 1, + .bmi = 0x18, + .height = 0x33, + }; + + if (base != BLE_CONN_MGR_EVENTS) { + return; + } + + switch (id) { + case ESP_BLE_CONN_EVENT_CONNECTED: + ESP_LOGI(TAG, "ESP_BLE_CONN_EVENT_CONNECTED"); + esp_ble_wss_set_measurement(&wss_measurement, true); + break; + case ESP_BLE_CONN_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "ESP_BLE_CONN_EVENT_DISCONNECTED"); + break; + default: + break; + } +} + +void +app_main(void) +{ + esp_ble_conn_config_t config = { + .device_name = CONFIG_EXAMPLE_BLE_ADV_NAME, + .broadcast_data = CONFIG_EXAMPLE_BLE_SUB_ADV + }; + + esp_err_t ret; + + // Initialize NVS + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + esp_event_loop_create_default(); + esp_event_handler_register(BLE_CONN_MGR_EVENTS, ESP_EVENT_ANY_ID, app_ble_conn_event_handler, NULL); + + esp_ble_conn_init(&config); + app_ble_wss_init(); + if (esp_ble_conn_start() != ESP_OK) { + esp_ble_conn_stop(); + esp_ble_conn_deinit(); + esp_event_handler_unregister(BLE_CONN_MGR_EVENTS, ESP_EVENT_ANY_ID, app_ble_conn_event_handler); + } +} diff --git a/examples/bluetooth/ble_services/ble_wss/main/idf_component.yml b/examples/bluetooth/ble_services/ble_wss/main/idf_component.yml new file mode 100644 index 000000000..10a79099a --- /dev/null +++ b/examples/bluetooth/ble_services/ble_wss/main/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + idf: ">=4.3" + ble_conn_mgr: + version: "~0.*" + override_path: "../../../../../components/bluetooth/ble_conn_mgr" + ble_services: + version: "~1.*" + override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_wss/sdkconfig.ci.nimble b/examples/bluetooth/ble_services/ble_wss/sdkconfig.ci.nimble new file mode 100644 index 000000000..f49256fb2 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_wss/sdkconfig.ci.nimble @@ -0,0 +1 @@ +CONFIG_BT_NIMBLE_ENABLED=y diff --git a/examples/bluetooth/ble_services/ble_wss/sdkconfig.defaults b/examples/bluetooth/ble_services/ble_wss/sdkconfig.defaults new file mode 100644 index 000000000..ea47f0dec --- /dev/null +++ b/examples/bluetooth/ble_services/ble_wss/sdkconfig.defaults @@ -0,0 +1,7 @@ +# Override some defaults so BT stack is enabled +# by default in this example +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y + +CONFIG_BLE_CONN_MGR_ROLE_PERIPHERAL=y +CONFIG_BLE_WSS=y