Mon, 17 Apr 2023 16:20:58 +0200
Version 0.4.1 Measure internal chip temperature, range -10 to 80. Result available in mqtt json payload.
31 | 1 | /** |
2 | * @file ble_gatts.c | |
3 | * @brief BLE GATTS services. | |
4 | */ | |
5 | ||
6 | #include "config.h" | |
7 | ||
8 | static const char *TAG = "ble_gatts"; | |
9 | ||
10 | #define PROFILE_NUM 1 | |
11 | #define PROFILE_RGB_APP_ID 0 | |
12 | #define PROFILE_RGB_NUM_HANDLE 3 | |
13 | ||
14 | #ifdef USE_BATTERY | |
15 | /// characteristic presentation information | |
16 | struct char_pres_fmt | |
17 | { | |
18 | uint16_t unit; ///< Unit (The Unit is a UUID) | |
19 | uint16_t description; ///< Description | |
20 | uint8_t format; | |
21 | uint8_t exponent; | |
22 | uint8_t name_space; ///< Name space | |
23 | }; | |
24 | ||
25 | ||
26 | static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE; | |
27 | static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE; | |
28 | static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; | |
29 | ||
30 | static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY; | |
31 | static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ; | |
32 | static const uint8_t char_prop_read_notify = ESP_GATT_CHAR_PROP_BIT_READ|ESP_GATT_CHAR_PROP_BIT_NOTIFY; | |
33 | #endif | |
34 | ||
35 | uint8_t rgb_service_uuid[ESP_UUID_LEN_128] = {0x00, 0x56, 0xa5, 0x97, 0xd2, 0xb7, 0x2e, 0x81, 0x57, 0x49, 0x00, 0x47, 0x6c, 0x55, 0x02, 0x3b}; | |
36 | uint8_t rgb_characteristic_uuid[ESP_UUID_LEN_128] = {0x00, 0x56, 0xa5, 0x97, 0xd2, 0xb7, 0x2e, 0x81, 0x57, 0x49, 0x00, 0x47, 0x6c, 0x55, 0x02, 0x3c}; | |
37 | ||
38 | static void gatts_profile_rgb_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); | |
39 | ||
40 | struct gatts_profile_inst { | |
41 | esp_gatts_cb_t gatts_cb; | |
42 | uint16_t gatts_if; | |
43 | uint16_t app_id; | |
44 | uint16_t conn_id; | |
45 | uint16_t service_handle; | |
46 | esp_gatt_srvc_id_t service_id; | |
47 | uint16_t char_handle; | |
48 | esp_bt_uuid_t char_uuid; | |
49 | esp_gatt_perm_t perm; | |
50 | esp_gatt_char_prop_t property; | |
51 | }; | |
52 | ||
53 | ||
54 | /********************/ | |
55 | ||
56 | #ifdef USE_BATTERY | |
57 | /// battery Service | |
58 | static const uint16_t battary_svc = ESP_GATT_UUID_BATTERY_SERVICE_SVC; | |
59 | ||
60 | static const uint16_t bat_lev_uuid = ESP_GATT_UUID_BATTERY_LEVEL; | |
61 | static const uint8_t bat_lev_ccc[2] ={ 0x00, 0x00}; | |
62 | static const uint16_t char_format_uuid = ESP_GATT_UUID_CHAR_PRESENT_FORMAT; | |
63 | ||
64 | static uint8_t battary_lev = 50; | |
65 | ||
66 | /// Full HRS Database Description - Used to add attributes into the database | |
67 | static const esp_gatts_attr_db_t bas_att_db[BAS_IDX_NB] = | |
68 | { | |
69 | // Battary Service Declaration | |
70 | [BAS_IDX_SVC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ, | |
71 | sizeof(uint16_t), sizeof(battary_svc), (uint8_t *)&battary_svc}}, | |
72 | ||
73 | // Battary level Characteristic Declaration | |
74 | [BAS_IDX_BATT_LVL_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ, | |
75 | sizeof(uint8_t),sizeof(uint8_t), (uint8_t *)&char_prop_read_notify}}, | |
76 | ||
77 | // Battary level Characteristic Value | |
78 | [BAS_IDX_BATT_LVL_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&bat_lev_uuid, ESP_GATT_PERM_READ, | |
79 | sizeof(uint8_t),sizeof(uint8_t), &battary_lev}}, | |
80 | ||
81 | // Battary level Characteristic - Client Characteristic Configuration Descriptor | |
82 | [BAS_IDX_BATT_LVL_NTF_CFG] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ|ESP_GATT_PERM_WRITE, | |
83 | sizeof(uint16_t),sizeof(bat_lev_ccc), (uint8_t *)bat_lev_ccc}}, | |
84 | ||
85 | // Battary level report Characteristic Declaration | |
86 | [BAS_IDX_BATT_LVL_PRES_FMT] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&char_format_uuid, ESP_GATT_PERM_READ, | |
87 | sizeof(struct char_pres_fmt), 0, NULL}}, | |
88 | }; | |
89 | #endif | |
90 | ||
91 | ||
92 | ||
93 | /*******************/ | |
94 | ||
95 | ||
96 | /* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */ | |
97 | static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = { | |
98 | [PROFILE_RGB_APP_ID] = { | |
99 | .gatts_cb = gatts_profile_rgb_event_handler, | |
100 | .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ | |
101 | } | |
102 | }; | |
103 | ||
104 | static void create_rgb_service(esp_gatt_if_t gatts_if) | |
105 | { | |
106 | gl_profile_tab[PROFILE_RGB_APP_ID].service_id.is_primary = true; | |
107 | gl_profile_tab[PROFILE_RGB_APP_ID].service_id.id.inst_id = 0x00; | |
108 | gl_profile_tab[PROFILE_RGB_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_128; | |
109 | memcpy(gl_profile_tab[PROFILE_RGB_APP_ID].service_id.id.uuid.uuid.uuid128, rgb_service_uuid, ESP_UUID_LEN_128); | |
110 | ||
111 | esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_RGB_APP_ID].service_id, PROFILE_RGB_NUM_HANDLE); | |
112 | } | |
113 | ||
114 | static void start_rgb_service(esp_ble_gatts_cb_param_t *param) | |
115 | { | |
116 | gl_profile_tab[PROFILE_RGB_APP_ID].service_handle = param->create.service_handle; | |
117 | esp_ble_gatts_start_service(gl_profile_tab[PROFILE_RGB_APP_ID].service_handle); | |
118 | } | |
119 | ||
120 | static void add_rgb_characteristic(void) | |
121 | { | |
122 | uint8_t char_value[] = {0x00}; | |
123 | ||
124 | esp_attr_value_t rgb_char_val = | |
125 | { | |
126 | .attr_max_len = sizeof(char_value), | |
127 | .attr_len = sizeof(char_value), | |
128 | .attr_value = char_value, | |
129 | }; | |
130 | ||
131 | gl_profile_tab[PROFILE_RGB_APP_ID].char_uuid.len = ESP_UUID_LEN_128; | |
132 | memcpy(gl_profile_tab[PROFILE_RGB_APP_ID].char_uuid.uuid.uuid128, rgb_characteristic_uuid, ESP_UUID_LEN_128); | |
133 | ||
134 | esp_err_t add_char_ret = esp_ble_gatts_add_char(gl_profile_tab[PROFILE_RGB_APP_ID].service_handle, &gl_profile_tab[PROFILE_RGB_APP_ID].char_uuid, | |
135 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, | |
136 | ESP_GATT_CHAR_PROP_BIT_WRITE, | |
137 | &rgb_char_val, NULL); | |
138 | if (add_char_ret){ | |
139 | ESP_LOGE(TAG, "add char failed, error code =%x",add_char_ret); | |
140 | } | |
141 | } | |
142 | ||
143 | static void handle_write_event(uint8_t * p_data, uint16_t len) | |
144 | { | |
145 | uint8_t opcode = p_data[0]; | |
146 | ESP_LOGI(TAG, "opcode = 0x%x", opcode); | |
147 | switch (opcode) | |
148 | { | |
149 | case 1: | |
150 | // rgb_ctrl(RGB_RED, RGB_ON); | |
151 | // rgb_ctrl(RGB_GREEN, RGB_OFF); | |
152 | // rgb_ctrl(RGB_BLUE, RGB_OFF); | |
153 | break; | |
154 | case 2: | |
155 | // rgb_ctrl(RGB_RED, RGB_OFF); | |
156 | // rgb_ctrl(RGB_GREEN, RGB_ON); | |
157 | // rgb_ctrl(RGB_BLUE, RGB_OFF); | |
158 | break; | |
159 | case 3: | |
160 | // rgb_ctrl(RGB_RED, RGB_OFF); | |
161 | // rgb_ctrl(RGB_GREEN, RGB_OFF); | |
162 | // rgb_ctrl(RGB_BLUE, RGB_ON); | |
163 | break; | |
164 | case 4: | |
165 | // rgb_ctrl(RGB_RED, RGB_OFF); | |
166 | // rgb_ctrl(RGB_GREEN, RGB_OFF); | |
167 | // rgb_ctrl(RGB_BLUE, RGB_OFF); | |
168 | break; | |
169 | default: | |
170 | break; | |
171 | } | |
172 | } | |
173 | ||
174 | ||
175 | static void gatts_profile_rgb_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) | |
176 | { | |
177 | ESP_LOGI(TAG, "gatts_profile_rgb_event_handler()"); | |
178 | ||
179 | switch (event) { | |
180 | case ESP_GATTS_REG_EVT: | |
181 | ESP_LOGI(TAG, "REGISTER_APP_EVT, status %d, app_id %d", param->reg.status, param->reg.app_id); | |
182 | ble_balkon_adv_config(); | |
183 | create_rgb_service(gatts_if); | |
184 | break; | |
185 | case ESP_GATTS_READ_EVT: { | |
186 | ESP_LOGI(TAG, "GATT_READ_EVT, conn_id %d, trans_id %lu, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); | |
187 | break; | |
188 | } | |
189 | case ESP_GATTS_WRITE_EVT: { | |
190 | ESP_LOGI(TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %lu, handle %d", param->write.conn_id, param->write.trans_id, param->write.handle); | |
191 | if (!param->write.is_prep){ | |
192 | ESP_LOGI(TAG, "GATT_WRITE_EVT, value len %d, value :", param->write.len); | |
193 | esp_log_buffer_hex(TAG, param->write.value, param->write.len); | |
194 | handle_write_event(param->write.value, param->write.len); | |
195 | } | |
196 | esp_gatt_status_t status = ESP_GATT_OK; | |
197 | if (param->write.need_rsp){ | |
198 | if (!param->write.is_prep){ | |
199 | esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, NULL); | |
200 | } | |
201 | } | |
202 | break; | |
203 | } | |
204 | case ESP_GATTS_EXEC_WRITE_EVT: | |
205 | ESP_LOGI(TAG,"ESP_GATTS_EXEC_WRITE_EVT"); | |
206 | break; | |
207 | case ESP_GATTS_MTU_EVT: | |
208 | ESP_LOGI(TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu); | |
209 | break; | |
210 | case ESP_GATTS_UNREG_EVT: | |
211 | break; | |
212 | case ESP_GATTS_CREATE_EVT: | |
213 | ESP_LOGI(TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d", param->create.status, param->create.service_handle); | |
214 | start_rgb_service(param); | |
215 | add_rgb_characteristic(); | |
216 | break; | |
217 | case ESP_GATTS_ADD_INCL_SRVC_EVT: | |
218 | break; | |
219 | case ESP_GATTS_ADD_CHAR_EVT: { | |
220 | ESP_LOGI(TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d", | |
221 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); | |
222 | break; | |
223 | } | |
224 | case ESP_GATTS_ADD_CHAR_DESCR_EVT: | |
225 | ESP_LOGI(TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d", | |
226 | param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle); | |
227 | break; | |
228 | case ESP_GATTS_DELETE_EVT: | |
229 | break; | |
230 | case ESP_GATTS_START_EVT: | |
231 | ESP_LOGI(TAG, "SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle); | |
232 | break; | |
233 | case ESP_GATTS_STOP_EVT: | |
234 | break; | |
235 | case ESP_GATTS_CONNECT_EVT: { | |
236 | esp_ble_conn_update_params_t conn_params = {0}; | |
237 | memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t)); | |
238 | /* For the IOS system, please reference the apple official documents about the ble connection parameters restrictions. */ | |
239 | conn_params.latency = 0; | |
240 | conn_params.max_int = 0x20; // max_int = 0x20*1.25ms = 40ms | |
241 | conn_params.min_int = 0x10; // min_int = 0x10*1.25ms = 20ms | |
242 | conn_params.timeout = 400; // timeout = 400*10ms = 4000ms | |
243 | ESP_LOGI(TAG, "ESP_GATTS_CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:", | |
244 | param->connect.conn_id, | |
245 | param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], | |
246 | param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]); | |
247 | gl_profile_tab[PROFILE_RGB_APP_ID].conn_id = param->connect.conn_id; | |
248 | //start sent the update connection parameters to the peer device. | |
249 | esp_ble_gap_update_conn_params(&conn_params); | |
250 | break; | |
251 | } | |
252 | case ESP_GATTS_DISCONNECT_EVT: | |
253 | ESP_LOGI(TAG, "ESP_GATTS_DISCONNECT_EVT, disconnect reason 0x%x", param->disconnect.reason); | |
254 | ble_balkon_adv_start(); | |
255 | break; | |
256 | case ESP_GATTS_CONF_EVT: | |
257 | ESP_LOGI(TAG, "ESP_GATTS_CONF_EVT, status %d attr_handle %d", param->conf.status, param->conf.handle); | |
258 | if (param->conf.status != ESP_GATT_OK){ | |
259 | esp_log_buffer_hex(TAG, param->conf.value, param->conf.len); | |
260 | } | |
261 | break; | |
262 | case ESP_GATTS_OPEN_EVT: | |
263 | case ESP_GATTS_CANCEL_OPEN_EVT: | |
264 | case ESP_GATTS_CLOSE_EVT: | |
265 | case ESP_GATTS_LISTEN_EVT: | |
266 | case ESP_GATTS_CONGEST_EVT: | |
267 | default: | |
268 | break; | |
269 | } | |
270 | } | |
271 | ||
272 | ||
273 | static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) | |
274 | { | |
275 | ESP_LOGI(TAG, "gatts_event_handler(%x)", event); | |
276 | ||
277 | /* If event is register event, store the gatts_if for each profile */ | |
278 | if (event == ESP_GATTS_REG_EVT) { | |
279 | if (param->reg.status == ESP_GATT_OK) { | |
280 | gl_profile_tab[param->reg.app_id].gatts_if = gatts_if; | |
281 | } else { | |
282 | ESP_LOGI(TAG, "Reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status); | |
283 | return; | |
284 | } | |
285 | } | |
286 | ||
287 | /* If the gatts_if equal to profile A, call profile A cb handler, | |
288 | * so here call each profile's callback */ | |
289 | do { | |
290 | int idx; | |
291 | for (idx = 0; idx < PROFILE_NUM; idx++) { | |
292 | if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ | |
293 | gatts_if == gl_profile_tab[idx].gatts_if) { | |
294 | if (gl_profile_tab[idx].gatts_cb) { | |
295 | gl_profile_tab[idx].gatts_cb(event, gatts_if, param); | |
296 | } | |
297 | } | |
298 | } | |
299 | } while (0); | |
300 | } | |
301 | ||
302 | ||
303 | /***************************************************************************************************************************/ | |
304 | ||
305 | esp_err_t ble_balkon_gatts_register(void) | |
306 | { | |
307 | esp_err_t ret = esp_ble_gatts_register_callback(gatts_event_handler); | |
308 | if (ret){ | |
309 | ESP_LOGE(TAG, "gatts register error, error code = %x", ret); | |
310 | } | |
311 | ||
312 | return ret; | |
313 | } | |
314 | ||
315 | ||
316 | esp_err_t ble_balkon_gatts_app_register(void) | |
317 | { | |
318 | esp_err_t ret = esp_ble_gatts_app_register(PROFILE_RGB_APP_ID); | |
319 | if (ret){ | |
320 | ESP_LOGE(TAG, "gatts app register error, error code = %x", ret); | |
321 | } | |
322 | ||
323 | return ret; | |
324 | } | |
325 | ||
326 | ||
327 | esp_err_t ble_balkon_gatts_set_mtu(void) | |
328 | { | |
329 | esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500); | |
330 | if (local_mtu_ret){ | |
331 | ESP_LOGE(TAG, "set local MTU failed, error code = %x", local_mtu_ret); | |
332 | } | |
333 | ||
334 | return local_mtu_ret; | |
335 | } | |
336 | ||
337 |