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 |
|