Skip to content

Commit

Permalink
Merge branch 'feature/aeg-1990' into 'master'
Browse files Browse the repository at this point in the history
feat(ble_services): Support Weight Scale Service

Closes AEG-1990

See merge request ae_group/esp-iot-solution!1177
  • Loading branch information
wujiangang committed Dec 27, 2024
2 parents c8c5f90 + e16b29f commit 5ebc23c
Show file tree
Hide file tree
Showing 33 changed files with 614 additions and 11 deletions.
13 changes: 13 additions & 0 deletions .gitlab/ci/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions components/bluetooth/ble_services/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
5 changes: 5 additions & 0 deletions components/bluetooth/ble_services/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand Down
1 change: 1 addition & 0 deletions components/bluetooth/ble_services/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions components/bluetooth/ble_services/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion components/bluetooth/ble_services/idf_component.yml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
8 changes: 8 additions & 0 deletions components/bluetooth/ble_services/wss/Kconfig.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Weight Scale Service

menuconfig BLE_WSS
bool "GATT Weight Scale Service"

if BLE_WSS

endif # BLE_WSS
137 changes: 137 additions & 0 deletions components/bluetooth/ble_services/wss/include/esp_wss.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <stdbool.h>
#include <stdint.h>

#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
172 changes: 172 additions & 0 deletions components/bluetooth/ble_services/wss/src/esp_wss.c
Original file line number Diff line number Diff line change
@@ -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 <string.h>

#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);
}
1 change: 1 addition & 0 deletions docs/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
1 change: 1 addition & 0 deletions docs/en/bluetooth/ble_services.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ BLE Services
Health Thermometer Service <ble_hts>
TX Power Service <ble_tps>
User Data Service <ble_uds>
Weight Scale Service <ble_wss>
Loading

0 comments on commit 5ebc23c

Please sign in to comment.