diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index f6d438331..40e80feb7 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -331,6 +331,7 @@ - "components/bluetooth/ble_hci/include/ble_hci.h" - "components/bluetooth/ble_services/ans/include/esp_ans.h" - "components/bluetooth/ble_services/bas/include/esp_bas.h" + - "components/bluetooth/ble_services/bcs/include/esp_bcs.h" - "components/bluetooth/ble_services/dis/include/esp_dis.h" - "components/bluetooth/ble_services/hrs/include/esp_hrs.h" - "components/bluetooth/ble_services/hts/include/esp_hts.h" diff --git a/components/bluetooth/ble_services/CHANGELOG.md b/components/bluetooth/ble_services/CHANGELOG.md index 01bc73468..e3222ea4e 100644 --- a/components/bluetooth/ble_services/CHANGELOG.md +++ b/components/bluetooth/ble_services/CHANGELOG.md @@ -1,3 +1,8 @@ +## v0.2.0 - 2024.10.31 + +Features: +- BCS: Support Body Composition Service + ## v0.1.0 This is the first release version for BLE services component in Espressif Component Registry, more detailed descriptions about the project, please refer to [User_Guide](https://docs.espressif.com/projects/espressif-esp-iot-solution/en/latest/bluetooth/ble_services.html). diff --git a/components/bluetooth/ble_services/CMakeLists.txt b/components/bluetooth/ble_services/CMakeLists.txt index e40d52135..7830678bc 100644 --- a/components/bluetooth/ble_services/CMakeLists.txt +++ b/components/bluetooth/ble_services/CMakeLists.txt @@ -34,6 +34,11 @@ list(APPEND srcs "tps/src/esp_tps.c") list(APPEND include "tps/include") endif() +if(CONFIG_BLE_BCS) +list(APPEND srcs "bcs/src/esp_bcs.c") +list(APPEND include "bcs/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 b5fbe75a5..a8098997a 100644 --- a/components/bluetooth/ble_services/Kconfig +++ b/components/bluetooth/ble_services/Kconfig @@ -1,8 +1,9 @@ menu "BLE Standard Services" orsource "./ans/Kconfig.in" - orsource "./dis/Kconfig.in" orsource "./bas/Kconfig.in" + orsource "./bcs/Kconfig.in" + orsource "./dis/Kconfig.in" orsource "./hrs/Kconfig.in" orsource "./hts/Kconfig.in" orsource "./tps/Kconfig.in" diff --git a/components/bluetooth/ble_services/README.md b/components/bluetooth/ble_services/README.md index b35cd42fb..d9390c50e 100644 --- a/components/bluetooth/ble_services/README.md +++ b/components/bluetooth/ble_services/README.md @@ -28,10 +28,11 @@ The example will be downloaded to the current folder. You can navigate into it f > You can use this command to download other examples. Or you can download examples from esp-iot-solution repository: 1. [ble_ans](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_ans) 2. [ble_bas](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_bas) -3. [ble_dis](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_dis) -4. [ble_hrs](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_hrs) -5. [ble_hts](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_hts) -5. [ble_tps](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_tps) +3. [ble_bcs](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_bcs) +4. [ble_dis](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_dis) +5. [ble_hrs](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_hrs) +6. [ble_hts](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_hts) +7. [ble_tps](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_tps) ### Q&A diff --git a/components/bluetooth/ble_services/bcs/Kconfig.in b/components/bluetooth/ble_services/bcs/Kconfig.in new file mode 100644 index 000000000..a04e5d69a --- /dev/null +++ b/components/bluetooth/ble_services/bcs/Kconfig.in @@ -0,0 +1,14 @@ +# Body Composition Service + +menuconfig BLE_BCS + bool "GATT Body Composition Service" + +if BLE_BCS + +config BLE_BCS_FEATURE_INDICATE_ENABLE + bool "Body Composition Feature Indication" + default n + help + Set y to support Indication or n to disable it. + +endif # BLE_BCS diff --git a/components/bluetooth/ble_services/bcs/include/esp_bcs.h b/components/bluetooth/ble_services/bcs/include/esp_bcs.h new file mode 100644 index 000000000..9d374422e --- /dev/null +++ b/components/bluetooth/ble_services/bcs/include/esp_bcs.h @@ -0,0 +1,109 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Maximum Attribute Value Length */ +#define BLE_BCS_MAX_VAL_LEN 100 + +/* 16 Bit Body Composition Service UUID */ +#define BLE_BCS_UUID16 0x181B + +/* 16 Bit Body Composition Characteristic UUIDs */ +#define BLE_BCS_CHR_UUID16_FEATURE 0x2A9B +#define BLE_BCS_CHR_UUID16_MEASUREMENT 0x2A9C + +/* Body Composition Feature Bit Masks */ +#define BLE_BCS_FEAT_TIME_STAMP (0x1 << 0) //bit0 Time Stamp(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_MULTI_USER (0x1 << 1) //bit1 User ID(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_BASAL_METABOLISM (0x1 << 2) //bit2 Basal Metabolism(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_MUSCLE_PERCENTAGE (0x1 << 3) //bit3 Muscle Percentage(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_MUSCLE_MASS (0x1 << 4) //bit4 Muscle Mass(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_FAT_FREE_MASS (0x1 << 5) //bit5 Fat Free Mass(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_SOFT_LEAN_MASS (0x1 << 6) //bit6 Soft Lean Mass(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_BODY_WATER_MASS (0x1 << 7) //bit7 Body Water Mass(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_IMPEDENCE (0x1 << 8) //bit8 Impedance(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_WEIGHT (0x1 << 9) //bit9 Weight(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_HEIGHT (0x1 << 10) //bit10 Height(0-Don't support, 1-Support) +#define BLE_BCS_FEAT_MASS_MEASUREMENT_RESOLUTION (0x1 << 11) //bit11-bit14 Weight Resolution (000-undefine, 001-0.5kg or 1lb, 002-0.2kg or 0.5lb, 003-0.1kg or 0.2lb, 004-0.05kg or 0.1lb, 005-0.02kg or 0.05lb, 006-0.01kg or 0.02lb, 007-0.005kg or 0.01lb); +#define BLE_BCS_FEAT_HEIGHT_RESOLUTION (0x1 << 15) //bit15-bit17 Height Resolution (000-undefine, 001-0.01m or 1ft, 002-0.005m or 0.5ft, 003-0.001m or 0.1ft); + +/* Body Composition Measurement Flags Bit Masks */ +#define BLE_BCS_FLAG_MEASUREMENT_UNITS (0x1 << 0) //bit0 Measurement Units +#define BLE_BCS_FLAG_TIME_STAMP (0x1 << 1) //bit1 Time Stamp +#define BLE_BCS_FLAG_MULTI_USER (0x1 << 2) //bit2 User ID +#define BLE_BCS_FLAG_BASAL_METABOLISM (0x1 << 3) //bit3 Basal Metabolism +#define BLE_BCS_FLAG_MUSCLE_PERCENTAGE (0x1 << 4) //bit4 Muscle Percentage +#define BLE_BCS_FLAG_MUSCLE_MASS (0x1 << 5) //bit5 Muscle Mass +#define BLE_BCS_FLAG_FAT_FREE_MASS (0x1 << 6) //bit6 Fat Free Mass +#define BLE_BCS_FLAG_SOFT_LEAN_MASS (0x1 << 7) //bit7 Soft Lean Mass +#define BLE_BCS_FLAG_BODY_WATER_MASS (0x1 << 8) //bit8 Body Water Mass +#define BLE_BCS_FLAG_IMPEDENCE (0x1 << 9) //bit9 Impedance +#define BLE_BCS_FLAG_WEIGHT (0x1 << 10) //bit10 Weight +#define BLE_BCS_FLAG_HEIGHT (0x1 << 11) //bit11 Height +#define BLE_BCS_FLAG_MULTIPLE_PACKET (0x1 << 12) //bit12 Multiple Packet + +/** + * @brief Body Composition Measurement Characteristic + */ +typedef struct { + uint32_t bcs_flag; /*!< Body Composition flag field */ + + 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 ID field */ + uint16_t basal_metabolism; /*!< Basal Metabolism field */ + uint16_t muscle_percentage; /*!< Muscle Percentage field */ + uint16_t muscle_mass; /*!< Muscle Mass field */ + uint16_t fat_free_mass; /*!< Fat Free Mass field */ + uint16_t soft_lean_mass; /*!< Soft Lean Mass field */ + uint16_t body_water_mass; /*!< Body Water Mass field */ + uint8_t impedance; /*!< Impedance field */ + uint16_t weight; /*!< Weight field */ + uint16_t height; /*!< Height field */ +} __attribute__((packed)) esp_bcs_val_t; + +/** + * @brief Set the Body Componsition value. + * + * @param[in] in_val The pointer to store the Body Componsition Information. + * + * @param[in] need_send If set to true, the Body Componsition Info will send to remote client. + * + * @return + * - ESP_OK on successful + * - ESP_ERR_INVALID_ARG on wrong initialization + * - ESP_FAIL on error + */ +esp_err_t esp_ble_bcs_set_measurement(esp_bcs_val_t *in_val, bool need_send); + +/** + * @brief Initialization Body Componsion Service + * + * @return + * - ESP_OK on successful + * - ESP_ERR_INVALID_ARG on wrong initialization + * - ESP_FAIL on error + */ +esp_err_t esp_ble_bcs_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/bluetooth/ble_services/bcs/src/esp_bcs.c b/components/bluetooth/ble_services/bcs/src/esp_bcs.c new file mode 100644 index 000000000..1e44c988e --- /dev/null +++ b/components/bluetooth/ble_services/bcs/src/esp_bcs.c @@ -0,0 +1,224 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Body Composition Service(BCS) + */ + +#include + +#include "esp_ble_conn_mgr.h" +#include "esp_bcs.h" + +typedef struct { + uint8_t len; + uint8_t buf[BLE_BCS_MAX_VAL_LEN]; +} indicate_buf_t; + +static uint32_t body_composition_feature = BLE_BCS_FEAT_TIME_STAMP | + BLE_BCS_FEAT_MULTI_USER | + BLE_BCS_FEAT_BASAL_METABOLISM | + BLE_BCS_FEAT_MUSCLE_PERCENTAGE | + BLE_BCS_FEAT_MUSCLE_MASS | + BLE_BCS_FEAT_FAT_FREE_MASS | + BLE_BCS_FEAT_SOFT_LEAN_MASS | + BLE_BCS_FEAT_BODY_WATER_MASS | + BLE_BCS_FEAT_IMPEDENCE | + BLE_BCS_FEAT_WEIGHT | + BLE_BCS_FEAT_HEIGHT | + BLE_BCS_FEAT_MASS_MEASUREMENT_RESOLUTION | + BLE_BCS_FEAT_HEIGHT_RESOLUTION; + +static void build_bcs_ind_buf(esp_bcs_val_t *in_val, indicate_buf_t *out_buf) +{ + uint32_t offset = 0; + + /* Add Flag */ + memcpy(out_buf->buf + offset, &(in_val->bcs_flag), sizeof(uint32_t)); + offset += sizeof(uint32_t); + + if (in_val->bcs_flag | BLE_BCS_FLAG_TIME_STAMP) { + memcpy(out_buf->buf + offset, &(in_val->timestamp), sizeof(in_val->timestamp)); + offset += sizeof(in_val->timestamp); // timestamp length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_MULTI_USER) { + memcpy(out_buf->buf + offset, &(in_val->user_id), sizeof(uint8_t)); + offset += sizeof(uint8_t); // user id length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_BASAL_METABOLISM) { + memcpy(out_buf->buf + offset, &(in_val->basal_metabolism), sizeof(uint16_t)); + offset += sizeof(uint16_t); // Basal Metabolism length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_MUSCLE_PERCENTAGE) { + memcpy(out_buf->buf + offset, &(in_val->muscle_percentage), sizeof(uint16_t)); + offset += sizeof(uint16_t); // Muscle Percentage length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_MUSCLE_MASS) { + memcpy(out_buf->buf + offset, &(in_val->muscle_mass), sizeof(uint16_t)); + offset += sizeof(uint16_t); // Muscle Mass length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_FAT_FREE_MASS) { + memcpy(out_buf->buf + offset, &(in_val->fat_free_mass), sizeof(uint16_t)); + offset += sizeof(uint16_t); // Fat Free Mass length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_SOFT_LEAN_MASS) { + memcpy(out_buf->buf + offset, &(in_val->soft_lean_mass), sizeof(uint16_t)); + offset += sizeof(uint16_t); // Soft Lean Mass length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_BODY_WATER_MASS) { + memcpy(out_buf->buf + offset, &(in_val->body_water_mass), sizeof(uint16_t)); + offset += sizeof(uint16_t); // Body water Mass length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_IMPEDENCE) { + memcpy(out_buf->buf + offset, &(in_val->impedance), sizeof(uint8_t)); + offset += sizeof(uint8_t); // impedance length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_WEIGHT) { + memcpy(out_buf->buf + offset, &(in_val->weight), sizeof(uint16_t)); + offset += sizeof(uint16_t); // weight length + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_HEIGHT) { + 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_bcs_set_measurement(esp_bcs_val_t *in_val, bool need_send) +{ + if (in_val == NULL) { + ESP_LOGE("ERROR", "in_val is NULL."); + return ESP_ERR_INVALID_ARG; + } + + /* Set Body Composition Feature Bit Masks */ + body_composition_feature = 0; + + if (in_val->bcs_flag | BLE_BCS_FLAG_TIME_STAMP) { + body_composition_feature |= BLE_BCS_FEAT_TIME_STAMP; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_MULTI_USER) { + body_composition_feature |= BLE_BCS_FEAT_MULTI_USER; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_BASAL_METABOLISM) { + body_composition_feature |= BLE_BCS_FEAT_BASAL_METABOLISM; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_MUSCLE_PERCENTAGE) { + body_composition_feature |= BLE_BCS_FEAT_MUSCLE_PERCENTAGE; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_MUSCLE_MASS) { + body_composition_feature |= BLE_BCS_FEAT_MUSCLE_MASS; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_FAT_FREE_MASS) { + body_composition_feature |= BLE_BCS_FEAT_FAT_FREE_MASS; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_SOFT_LEAN_MASS) { + body_composition_feature |= BLE_BCS_FEAT_SOFT_LEAN_MASS; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_BODY_WATER_MASS) { + body_composition_feature |= BLE_BCS_FEAT_BODY_WATER_MASS; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_IMPEDENCE) { + body_composition_feature |= BLE_BCS_FEAT_IMPEDENCE; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_WEIGHT) { + body_composition_feature |= BLE_BCS_FEAT_WEIGHT; + } + + if (in_val->bcs_flag | BLE_BCS_FLAG_HEIGHT) { + body_composition_feature |= BLE_BCS_FEAT_HEIGHT; + } + +#ifdef CONFIG_BLE_BCS_FEATURE_INDICATE_ENABLE + if (need_send) { + indicate_buf_t out_buf; + + /* Build Body Composition Measurement value */ + build_bcs_ind_buf(in_val, &out_buf); + + esp_ble_conn_data_t conn_data = { + .type = BLE_CONN_UUID_TYPE_16, + .uuid = { + .uuid16 = BLE_BCS_CHR_UUID16_MEASUREMENT, + }, + .data = out_buf.buf, + .data_len = out_buf.len, + }; + + return esp_ble_conn_write(&conn_data); + } +#endif + + return ESP_OK; +} + +static esp_err_t bcs_feature_cb(const uint8_t *inbuf, uint16_t inlen, + uint8_t **outbuf, uint16_t *outlen, void *priv_data) +{ + if (inbuf || !outbuf || !outlen) { + return ESP_ERR_INVALID_ARG; + } + + *outlen = sizeof(body_composition_feature); + *outbuf = (uint8_t *)calloc(1, *outlen); + if (!(*outbuf)) { + return ESP_ERR_NO_MEM; + } + memcpy(*outbuf, &body_composition_feature, *outlen); + + return ESP_OK; +} + +static const esp_ble_conn_character_t nu_lookup_table[] = { + { + "feature", BLE_CONN_UUID_TYPE_16, BLE_CONN_GATT_CHR_READ +#ifdef CONFIG_BLE_BCS_FEATURE_INDICATE_ENABLE + | BLE_CONN_GATT_CHR_INDICATE +#endif + , { BLE_BCS_CHR_UUID16_FEATURE }, bcs_feature_cb + }, + + { + "measurement", BLE_CONN_UUID_TYPE_16, BLE_CONN_GATT_CHR_INDICATE + , { BLE_BCS_CHR_UUID16_MEASUREMENT }, NULL + }, +}; + +static const esp_ble_conn_svc_t svc = { + .type = BLE_CONN_UUID_TYPE_16, + .uuid = { + .uuid16 = BLE_BCS_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_bcs_init(void) +{ + return esp_ble_conn_add_svc(&svc); +} diff --git a/components/bluetooth/ble_services/idf_component.yml b/components/bluetooth/ble_services/idf_component.yml index 0778e5423..ace4cca50 100644 --- a/components/bluetooth/ble_services/idf_component.yml +++ b/components/bluetooth/ble_services/idf_component.yml @@ -1,4 +1,4 @@ -version: "0.1.0" +version: "0.2.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/docs/Doxyfile b/docs/Doxyfile index 406949962..29ba977ff 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -31,6 +31,7 @@ INPUT = \ $(PROJECT_PATH)/components/bluetooth/ble_profiles/std/ble_htp/include/esp_htp.h \ $(PROJECT_PATH)/components/bluetooth/ble_services/ans/include/esp_ans.h \ $(PROJECT_PATH)/components/bluetooth/ble_services/bas/include/esp_bas.h \ + $(PROJECT_PATH)/components/bluetooth/ble_services/bcs/include/esp_bcs.h \ $(PROJECT_PATH)/components/bluetooth/ble_services/dis/include/esp_dis.h \ $(PROJECT_PATH)/components/bluetooth/ble_services/hrs/include/esp_hrs.h \ $(PROJECT_PATH)/components/bluetooth/ble_services/hts/include/esp_hts.h \ diff --git a/docs/en/bluetooth/ble_bcs.rst b/docs/en/bluetooth/ble_bcs.rst new file mode 100644 index 000000000..2931af77e --- /dev/null +++ b/docs/en/bluetooth/ble_bcs.rst @@ -0,0 +1,15 @@ +Body Composition Service +============================== +:link_to_translation:`zh_CN:[中文]` + +The Body Composition Service (BCS) exposes data related to body composition from a body composition analyzer (Server) intended for consumer healthcare as well as sports/fitness applications. + +Examples +-------------- + +:example:`bluetooth/ble_services/ble_bcs`. + +API Reference +----------------- + +.. include-build-file:: inc/esp_bcs.inc diff --git a/docs/en/bluetooth/ble_services.rst b/docs/en/bluetooth/ble_services.rst index 5f39f522e..f239ef8d1 100644 --- a/docs/en/bluetooth/ble_services.rst +++ b/docs/en/bluetooth/ble_services.rst @@ -7,6 +7,7 @@ BLE Services Alert Notification Service Battery Service + Body Composition Service Device Information Service Heart Rate Service Health Thermometer Service diff --git a/docs/sphinx-known-warnings.txt b/docs/sphinx-known-warnings.txt index 1cc91fb6b..3bdf69b67 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::@39::@43 precise'. +Declaration is '.. cpp:member:: struct lightbulb_config_t::@40::@44 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_bcs.rst b/docs/zh_CN/bluetooth/ble_bcs.rst new file mode 100644 index 000000000..ec9d9c35f --- /dev/null +++ b/docs/zh_CN/bluetooth/ble_bcs.rst @@ -0,0 +1,15 @@ +人体组织成分服务 +============================== +:link_to_translation:`en:[English]` + +人体成分服务提供了用于健康以及健身领域的相关数据。 + +示例 +-------------- + +:example:`bluetooth/ble_services/ble_bcs`. + +API 参考 +----------------- + +.. include-build-file:: inc/esp_bcs.inc diff --git a/docs/zh_CN/bluetooth/ble_services.rst b/docs/zh_CN/bluetooth/ble_services.rst index 176d338c2..fa080be99 100644 --- a/docs/zh_CN/bluetooth/ble_services.rst +++ b/docs/zh_CN/bluetooth/ble_services.rst @@ -7,6 +7,7 @@ BLE 服务 警报通知服务 电池服务 + 人体组织成分服务 设备信息服务 心率服务 健康温度计服务 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 552b51f4b..e0b2519fa 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.1.0" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.1.0" + version: "~0.*" 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 552b51f4b..e0b2519fa 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.1.0" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.1.0" + version: "~0.*" override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_bcs/CMakeLists.txt b/examples/bluetooth/ble_services/ble_bcs/CMakeLists.txt new file mode 100644 index 000000000..e4f0de34a --- /dev/null +++ b/examples/bluetooth/ble_services/ble_bcs/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_bcs) diff --git a/examples/bluetooth/ble_services/ble_bcs/README.md b/examples/bluetooth/ble_services/ble_bcs/README.md new file mode 100644 index 000000000..c6cb38320 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_bcs/README.md @@ -0,0 +1,89 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C2 | ESP32-S3 | ESP32-H2 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | + +# BLE Body Composition 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_BCS`. + +In the `BLE Standard Services` menu: + +* Select the optional functions of device from `GATT Body Composition 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 (420) blecm_nimble: BLE Host Task Started +I (420) blecm_nimble: No characteristic(0x2a00) found +I (420) blecm_nimble: No characteristic(0x2a01) found +I (430) blecm_nimble: No characteristic(0x2a05) found +I (430) NimBLE: GAP procedure initiated: stop advertising. + +I (440) NimBLE: GAP procedure initiated: advertise; +I (440) NimBLE: disc_mode=2 +I (450) NimBLE: adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=256 adv_itvl_max=256 +I (460) NimBLE: + +I (460) 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_bcs/main/CMakeLists.txt b/examples/bluetooth/ble_services/ble_bcs/main/CMakeLists.txt new file mode 100644 index 000000000..5695bd667 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_bcs/main/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register(SRCS "app_main.c") diff --git a/examples/bluetooth/ble_services/ble_bcs/main/Kconfig.projbuild b/examples/bluetooth/ble_services/ble_bcs/main/Kconfig.projbuild new file mode 100644 index 000000000..c027c983c --- /dev/null +++ b/examples/bluetooth/ble_services/ble_bcs/main/Kconfig.projbuild @@ -0,0 +1,13 @@ +menu "Example Configuration" + config EXAMPLE_BLE_ADV_NAME + string "Advertisement name" + default "BLE_BCS" + 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_bcs/main/app_main.c b/examples/bluetooth/ble_services/ble_bcs/main/app_main.c new file mode 100644 index 000000000..94800b5c2 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_bcs/main/app_main.c @@ -0,0 +1,107 @@ +/* + * 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_bcs.h" + +static const char *TAG = "app_main"; + +static void app_ble_bcs_init(void) +{ + esp_ble_bcs_init(); +} + +static void app_ble_conn_event_handler(void *handler_args, esp_event_base_t base, int32_t id, void *event_data) +{ + esp_bcs_val_t bcs_val = { + .bcs_flag = BLE_BCS_FLAG_TIME_STAMP | + BLE_BCS_FLAG_MULTI_USER | + BLE_BCS_FLAG_BASAL_METABOLISM | + BLE_BCS_FLAG_MUSCLE_PERCENTAGE | + BLE_BCS_FLAG_MUSCLE_MASS | + BLE_BCS_FLAG_FAT_FREE_MASS | + BLE_BCS_FLAG_SOFT_LEAN_MASS | + BLE_BCS_FLAG_BODY_WATER_MASS | + BLE_BCS_FLAG_IMPEDENCE | + BLE_BCS_FLAG_WEIGHT | + BLE_BCS_FLAG_HEIGHT, + .timestamp.year = 2024, + .timestamp.month = 11, + .timestamp.day = 5, + .timestamp.hours = 15, + .timestamp.minutes = 15, + .timestamp.seconds = 6, + .user_id = 1, + .basal_metabolism = 0x01, + .muscle_percentage = 0x02, + .muscle_mass = 0x03, + .fat_free_mass = 0x04, + .soft_lean_mass = 0x05, + .body_water_mass = 0x06, + .impedance = 0x01, + .weight = 0x42, + .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_bcs_set_measurement(&bcs_val, 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_bcs_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_bcs/main/idf_component.yml b/examples/bluetooth/ble_services/ble_bcs/main/idf_component.yml new file mode 100644 index 000000000..e0b2519fa --- /dev/null +++ b/examples/bluetooth/ble_services/ble_bcs/main/idf_component.yml @@ -0,0 +1,8 @@ +dependencies: + idf: ">=4.3" + ble_conn_mgr: + version: "~0.1.0" + override_path: "../../../../../components/bluetooth/ble_conn_mgr" + ble_services: + version: "~0.*" + override_path: "../../../../../components/bluetooth/ble_services" diff --git a/examples/bluetooth/ble_services/ble_bcs/sdkconfig.ci.nimble b/examples/bluetooth/ble_services/ble_bcs/sdkconfig.ci.nimble new file mode 100644 index 000000000..f49256fb2 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_bcs/sdkconfig.ci.nimble @@ -0,0 +1 @@ +CONFIG_BT_NIMBLE_ENABLED=y diff --git a/examples/bluetooth/ble_services/ble_bcs/sdkconfig.defaults b/examples/bluetooth/ble_services/ble_bcs/sdkconfig.defaults new file mode 100644 index 000000000..1a27ba508 --- /dev/null +++ b/examples/bluetooth/ble_services/ble_bcs/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_BCS=y 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 552b51f4b..e0b2519fa 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.1.0" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.1.0" + version: "~0.*" 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 552b51f4b..e0b2519fa 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.1.0" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.1.0" + version: "~0.*" 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 552b51f4b..e0b2519fa 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.1.0" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.1.0" + version: "~0.*" 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 552b51f4b..e0b2519fa 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.1.0" override_path: "../../../../../components/bluetooth/ble_conn_mgr" ble_services: - version: "~0.1.0" + version: "~0.*" override_path: "../../../../../components/bluetooth/ble_services"