Skip to content

Commit 5ebc23c

Browse files
committed
Merge branch 'feature/aeg-1990' into 'master'
feat(ble_services): Support Weight Scale Service Closes AEG-1990 See merge request ae_group/esp-iot-solution!1177
2 parents c8c5f90 + e16b29f commit 5ebc23c

File tree

33 files changed

+614
-11
lines changed

33 files changed

+614
-11
lines changed

.gitlab/ci/build.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,19 @@ build_example_bluetooth_ble_services_ble_uds:
276276
variables:
277277
EXAMPLE_DIR: examples/bluetooth/ble_services/ble_uds
278278

279+
build_example_bluetooth_ble_services_ble_wss:
280+
extends:
281+
- .build_examples_template
282+
- .rules:build:example_bluetooth_ble_services
283+
parallel:
284+
matrix:
285+
- IMAGE: espressif/idf:release-v4.4
286+
- IMAGE: espressif/idf:release-v5.0
287+
- IMAGE: espressif/idf:release-v5.1
288+
- IMAGE: espressif/idf:release-v5.2
289+
variables:
290+
EXAMPLE_DIR: examples/bluetooth/ble_services/ble_wss
291+
279292
build_example_bluetooth_ble_ota:
280293
extends:
281294
- .build_examples_template

components/bluetooth/ble_services/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## v1.0.0 - 2024.12.27
2+
3+
Features:
4+
- BCS: Support Body Composition Service
5+
- CTS: Support Body Composition Service
6+
- UDS: Support Body Composition Service
7+
18
## v0.2.0 - 2024.10.31
29

310
Features:

components/bluetooth/ble_services/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ list(APPEND srcs "cts/src/esp_cts.c")
4949
list(APPEND include "cts/include")
5050
endif()
5151

52+
if(CONFIG_BLE_WSS)
53+
list(APPEND srcs "wss/src/esp_wss.c")
54+
list(APPEND include "wss/include")
55+
endif()
56+
5257
list(APPEND req "ble_conn_mgr")
5358

5459
idf_component_register(SRCS "${srcs}"

components/bluetooth/ble_services/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ menu "BLE Standard Services"
99
orsource "./hts/Kconfig.in"
1010
orsource "./tps/Kconfig.in"
1111
orsource "./uds/Kconfig.in"
12+
orsource "./wss/Kconfig.in"
1213

1314
endmenu

components/bluetooth/ble_services/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ The example will be downloaded to the current folder. You can navigate into it f
3535
7. [ble_hts](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_hts)
3636
8. [ble_tps](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_tps)
3737
9. [ble_uds](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_uds)
38+
10. [ble_wss](https://github.com/espressif/esp-iot-solution/tree/master/examples/bluetooth/ble_services/ble_wss)
3839

3940
### Q&A
4041

components/bluetooth/ble_services/idf_component.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: "0.2.0"
1+
version: "1.0.0"
22
description: BLE standard GATT services support
33
url: https://github.com/espressif/esp-iot-solution/tree/master/components/bluetooth/ble_services
44
issues: https://github.com/espressif/esp-iot-solution/issues
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Weight Scale Service
2+
3+
menuconfig BLE_WSS
4+
bool "GATT Weight Scale Service"
5+
6+
if BLE_WSS
7+
8+
endif # BLE_WSS
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include <stdbool.h>
10+
#include <stdint.h>
11+
12+
#include "esp_err.h"
13+
#include "esp_event_base.h"
14+
15+
#ifdef __cplusplus
16+
extern "C"
17+
{
18+
#endif
19+
20+
/* 16 Bit Weight Scale Service UUID */
21+
#define BLE_WSS_UUID16 0x181D
22+
23+
/* 16 Bit Weight Scale Characteristics UUID */
24+
#define BLE_WSS_CHR_UUID16_WEIGHT_FEATURE 0x2A9E
25+
#define BLE_WSS_CHR_UUID16_WEIGHT_MEASUREMENT 0x2A9D
26+
27+
/* Weight Scale Feature masks */
28+
#define BLE_WSS_TIMESTAMP_MASK (1 << 0)
29+
#define BLE_WSS_MULTI_USER_MASK (1 << 1)
30+
#define BLE_WSS_BMI_MASK (1 << 2)
31+
32+
/* Weight resolution offset*/
33+
#define BLE_WSS_WEIGHT_RESOLUTION_OFSET (3)
34+
35+
#define BLE_WSS_WEIGHT_RESOLUTION_NONE (0x0)
36+
#define BLE_WSS_WEIGHT_RESOLUTION_0P5_KG (0x1)
37+
#define BLE_WSS_WEIGHT_RESOLUTION_0P2_KG (0x2)
38+
#define BLE_WSS_WEIGHT_RESOLUTION_0P1_KG (0x3)
39+
#define BLE_WSS_WEIGHT_RESOLUTION_0P05_KG (0x4)
40+
#define BLE_WSS_WEIGHT_RESOLUTION_0P02_KG (0x5)
41+
#define BLE_WSS_WEIGHT_RESOLUTION_0P01_KG (0x6)
42+
#define BLE_WSS_WEIGHT_RESOLUTION_0P005_KG (0x7)
43+
44+
/* Height resolution offset*/
45+
#define BLE_WSS_HEIGHT_RESOLUTION_OFSET (6)
46+
47+
#define BLE_WSS_HEIGHT_RESOLUTION_NONE (0x0)
48+
#define BLE_WSS_HEIGHT_RESOLUTION_0P01_M (0x1)
49+
#define BLE_WSS_HEIGHT_RESOLUTION_0P005_M (0x2)
50+
#define BLE_WSS_HEIGHT_RESOLUTION_0P001_M (0x3)
51+
52+
/* Weight Scale Measurement Flag */
53+
#define BLE_WSS_MEASUREMENT_UINTS_FLAG (1 << 0)
54+
#define BLE_WSS_TIME_STAMP_FLAG (1 << 1)
55+
#define BLE_WSS_USER_ID_FLAG (1 << 2)
56+
#define BLE_WSS_BMI_FLAG (1 << 3)
57+
58+
/**
59+
* @brief Weight Scale Feature
60+
*/
61+
typedef struct {
62+
uint32_t timestamp: 1; /*!< 0: Don't Support, 1: Support */
63+
uint32_t user_id: 1; /*!< 0: Don't Support, 1: Support */
64+
uint32_t bmi: 1; /*!< 0: Don't Support, 1: Support */
65+
uint32_t weight: 1; /*!< 0: Don't Support, 1: Support */
66+
uint32_t w_resolution: 3; /*!< If weight support, this filed should present */
67+
uint32_t height: 1; /*!< 0: Don't Support, 1: Support */
68+
uint32_t h_resolution: 2; /*!< If height support, this filed should present */
69+
} esp_ble_wss_feature_t; /*!< The structure of the weight scale feature field */
70+
71+
/**
72+
* @brief weight Measurement
73+
*/
74+
typedef struct {
75+
struct {
76+
uint32_t measurement_unit: 1; /*!< 0: Kg & meter, 1: reference to weight and height resolution */
77+
uint32_t time_present: 1; /*!< 0: Don't contain time information, 1: time stamp present */
78+
uint32_t user_present: 1; /*!< 0: Don't contain user index, 1: contain user index */
79+
uint32_t bmi_height_present: 1; /*!< 0: Don't contain BMI and height, 1: contain BMI and height */
80+
} flag; /*!< Flag */
81+
82+
uint16_t weight; /*!< weight */
83+
84+
struct {
85+
uint16_t year; /*!< Year as defined by the Gregorian calendar, Valid range 1582 to 9999 */
86+
uint8_t month; /*!< Month of the year as defined by the Gregorian calendar, Valid range 1 (January) to 12 (December) */
87+
uint8_t day; /*!< Day of the month as defined by the Gregorian calendar, Valid range 1 to 31 */
88+
uint8_t hours; /*!< Number of hours past midnight, Valid range 0 to 23 */
89+
uint8_t minutes; /*!< Number of minutes since the start of the hour. Valid range 0 to 59 */
90+
uint8_t seconds; /*!< Number of seconds since the start of the minute. Valid range 0 to 59 */
91+
} __attribute__((packed)) timestamp; /*!< The date and time */
92+
93+
uint8_t user_id; /*!< User index */
94+
uint8_t bmi; /*!< BMI */
95+
uint16_t height; /*!< Height */
96+
uint8_t weight_resolution; /*!< Weight resolution */
97+
uint8_t height_resolution; /*!< Height resolution */
98+
} __attribute__((packed)) esp_ble_wss_measurement_t;
99+
100+
/**
101+
* @brief Read the weight measurement characteristic value.
102+
*
103+
* @param[in] out_val The pointer to store the weight measurement value.
104+
*
105+
* @return
106+
* - ESP_OK on successful
107+
* - ESP_ERR_INVALID_ARG on wrong parameter
108+
*/
109+
esp_err_t esp_ble_wss_get_measurement(esp_ble_wss_measurement_t *out_val);
110+
111+
/**
112+
* @brief Set the weight measurement characteristic value.
113+
*
114+
* @param[in] in_val The pointer to store the weight measurement.
115+
*
116+
* @param[in] need_send send the weight measurement information to remote client.
117+
*
118+
* @return
119+
* - ESP_OK on successful
120+
* - ESP_ERR_INVALID_ARG on wrong initialization
121+
* - ESP_FAIL on error
122+
*/
123+
esp_err_t esp_ble_wss_set_measurement(esp_ble_wss_measurement_t *in_val, bool need_send);
124+
125+
/**
126+
* @brief Initialization Weight Scale Service
127+
*
128+
* @return
129+
* - ESP_OK on successful
130+
* - ESP_ERR_INVALID_ARG on wrong initialization
131+
* - ESP_FAIL on error
132+
*/
133+
esp_err_t esp_ble_wss_init(void);
134+
135+
#ifdef __cplusplus
136+
}
137+
#endif
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/** @file
8+
* @brief Weight Scale Service(WSS)
9+
*/
10+
11+
#include <string.h>
12+
13+
#include "esp_ble_conn_mgr.h"
14+
#include "esp_wss.h"
15+
16+
#define BLE_WSS_MAX_VAL_LEN 20
17+
18+
typedef struct {
19+
uint8_t len;
20+
uint8_t buf[BLE_WSS_MAX_VAL_LEN];
21+
} indicate_buf_t;
22+
23+
/* Weight Scale Feature value */
24+
static esp_ble_wss_feature_t s_wss_feature = {
25+
.timestamp = 1,
26+
.user_id = 1,
27+
.bmi = 1,
28+
.weight = 1,
29+
.w_resolution = 1,
30+
.height = 1,
31+
.h_resolution = 1
32+
};
33+
34+
static esp_ble_wss_measurement_t s_wss_measurement;
35+
36+
static void build_wss_ind_buf(esp_ble_wss_measurement_t *in_val, indicate_buf_t *out_buf)
37+
{
38+
uint32_t offset = 0;
39+
40+
/* Add Flag */
41+
memcpy(out_buf->buf + offset, &(in_val->flag), sizeof(uint32_t));
42+
offset += sizeof(uint32_t);
43+
44+
/* Add weight */
45+
memcpy(out_buf->buf + offset, &(in_val->weight), sizeof(uint16_t));
46+
offset += sizeof(uint32_t);
47+
48+
if (in_val->flag.time_present == 1) {
49+
memcpy(out_buf->buf + offset, &(in_val->timestamp), sizeof(in_val->timestamp));
50+
offset += sizeof(in_val->timestamp); // timestamp length
51+
}
52+
53+
if (in_val->flag.user_present == 1) {
54+
memcpy(out_buf->buf + offset, &(in_val->user_id), sizeof(uint8_t));
55+
offset += sizeof(uint8_t); // user id length
56+
}
57+
58+
if (in_val->flag.bmi_height_present == 1) {
59+
memcpy(out_buf->buf + offset, &(in_val->bmi), sizeof(uint8_t));
60+
offset += sizeof(uint8_t); // bmi length
61+
62+
memcpy(out_buf->buf + offset, &(in_val->height), sizeof(uint16_t));
63+
offset += sizeof(uint16_t); // height length
64+
}
65+
66+
out_buf->len = offset;
67+
68+
return;
69+
}
70+
71+
esp_err_t esp_ble_wss_get_measurement(esp_ble_wss_measurement_t *out_val)
72+
{
73+
if (!out_val) {
74+
return ESP_ERR_INVALID_ARG;
75+
}
76+
77+
memcpy(out_val, &s_wss_measurement, sizeof(esp_ble_wss_measurement_t));
78+
79+
return ESP_OK;
80+
}
81+
82+
esp_err_t esp_ble_wss_set_measurement(esp_ble_wss_measurement_t *in_val, bool need_send)
83+
{
84+
if (in_val == NULL) {
85+
return ESP_ERR_INVALID_ARG;
86+
}
87+
88+
memcpy(&s_wss_measurement, in_val, sizeof(esp_ble_wss_measurement_t));
89+
90+
/* Set Weight Scale Feature Bit Masks */
91+
memset(&s_wss_feature, 0x0, sizeof(esp_ble_wss_feature_t));
92+
s_wss_feature.weight = 1;
93+
94+
if (in_val->flag.measurement_unit == 0x1) {
95+
s_wss_feature.w_resolution = in_val->weight_resolution;
96+
s_wss_feature.h_resolution = in_val->height_resolution;
97+
}
98+
99+
if (in_val->flag.time_present == 0x1) {
100+
s_wss_feature.timestamp = 1;
101+
}
102+
103+
if (in_val->flag.user_present == 0x1) {
104+
s_wss_feature.user_id = 1;
105+
}
106+
107+
if (in_val->flag.bmi_height_present == 0x1) {
108+
s_wss_feature.bmi = 1;
109+
s_wss_feature.height = 1;
110+
}
111+
112+
indicate_buf_t out_buf;
113+
114+
/* Build Body Composition Measurement value */
115+
build_wss_ind_buf(in_val, &out_buf);
116+
117+
esp_ble_conn_data_t conn_data = {
118+
.type = BLE_CONN_UUID_TYPE_16,
119+
.uuid = {
120+
.uuid16 = BLE_WSS_CHR_UUID16_WEIGHT_MEASUREMENT,
121+
},
122+
.data = out_buf.buf,
123+
.data_len = out_buf.len,
124+
};
125+
126+
return esp_ble_conn_write(&conn_data);
127+
}
128+
129+
static esp_err_t wss_feature_cb(const uint8_t *inbuf, uint16_t inlen,
130+
uint8_t **outbuf, uint16_t *outlen, void *priv_data)
131+
{
132+
uint8_t len = sizeof(s_wss_feature);
133+
134+
if (inbuf || !outbuf || !outlen) {
135+
return ESP_ERR_INVALID_ARG;
136+
}
137+
138+
*outbuf = calloc(1, len);
139+
if (!(*outbuf)) {
140+
return ESP_ERR_NO_MEM;
141+
}
142+
143+
memcpy(*outbuf, &s_wss_feature, len);
144+
*outlen = len;
145+
146+
return ESP_OK;
147+
}
148+
149+
static const esp_ble_conn_character_t nu_lookup_table[] = {
150+
{
151+
"weight feature", BLE_CONN_UUID_TYPE_16, BLE_CONN_GATT_CHR_READ
152+
, { BLE_WSS_CHR_UUID16_WEIGHT_FEATURE }, wss_feature_cb
153+
},
154+
{
155+
"weight measurement", BLE_CONN_UUID_TYPE_16, BLE_CONN_GATT_CHR_INDICATE
156+
, { BLE_WSS_CHR_UUID16_WEIGHT_MEASUREMENT }, NULL
157+
},
158+
};
159+
160+
static const esp_ble_conn_svc_t svc = {
161+
.type = BLE_CONN_UUID_TYPE_16,
162+
.uuid = {
163+
.uuid16 = BLE_WSS_UUID16,
164+
},
165+
.nu_lookup_count = sizeof(nu_lookup_table) / sizeof(nu_lookup_table[0]),
166+
.nu_lookup = (esp_ble_conn_character_t *)nu_lookup_table
167+
};
168+
169+
esp_err_t esp_ble_wss_init(void)
170+
{
171+
return esp_ble_conn_add_svc(&svc);
172+
}

docs/Doxyfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ INPUT = \
3838
$(PROJECT_PATH)/components/bluetooth/ble_services/hts/include/esp_hts.h \
3939
$(PROJECT_PATH)/components/bluetooth/ble_services/tps/include/esp_tps.h \
4040
$(PROJECT_PATH)/components/bluetooth/ble_services/uds/include/esp_uds.h \
41+
$(PROJECT_PATH)/components/bluetooth/ble_services/wss/include/esp_wss.h \
4142
$(PROJECT_PATH)/components/bus/include/i2s_lcd_driver.h \
4243
$(PROJECT_PATH)/components/button/include/iot_button.h \
4344
$(PROJECT_PATH)/components/display/screen/interface_driver/scr_interface_driver.h \

0 commit comments

Comments
 (0)