├── .gitignore ├── README.md ├── gatt_client_car_controller ├── Makefile ├── README.md ├── main │ ├── component.mk │ └── gattc_demo.c └── sdkconfig.defaults ├── gatt_client_listen_notif_then_output_to_led ├── Makefile ├── README.md ├── main │ ├── component.mk │ └── gattc_demo.c └── sdkconfig.defaults ├── gatt_server_car ├── Makefile ├── README.md ├── main │ ├── Kconfig │ ├── MPU9250_asukiaaa.c │ ├── MPU9250_asukiaaa.h │ ├── component.mk │ └── gatt_server.c └── sdkconfig.defaults ├── gatt_server_gpio_notif ├── Makefile ├── README.md ├── main │ ├── Kconfig │ ├── component.mk │ └── gatt_server_gpio_notif.c └── sdkconfig.defaults └── gatt_server_notif_switch ├── Makefile ├── README.md ├── main ├── Kconfig ├── component.mk └── gatt_server_notif_switch.c └── sdkconfig.defaults /.gitignore: -------------------------------------------------------------------------------- 1 | # Example project files 2 | */sdkconfig 3 | */sdkconfig.old 4 | */build 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp32-idf-samples 2 | Sample projests for esp32 on esp-idf. 3 | 4 | # Partner project 5 | ## nodejs 6 | The following project can be a client of BLE GATT connection. 7 | 8 | [asukiaaa/esp32-nodejs-samples](https://github.com/asukiaaa/esp32-nodejs-samples) 9 | 10 | ## react-native(re-natal) 11 | The following application can controll gat_server_car. 12 | 13 | [asukiaaa/re-natal-esp32control-app](https://github.com/asukiaaa/re-natal-esp32control-app) 14 | 15 | # References 16 | - [how to send BLE notification to client](https://www.esp32.com/viewtopic.php?t=806) 17 | - [GATT SERVER API: esp_ble_gatts_send_indicate](http://esp-idf.readthedocs.io/en/latest/api/bluetooth/esp_gatts.html#_CPPv227esp_ble_gatts_send_indicate13esp_gatt_if_t8uint16_t8uint16_t8uint16_tP7uint8_tb) 18 | -------------------------------------------------------------------------------- /gatt_client_car_controller/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := gatt_client_demo 7 | 8 | COMPONENT_ADD_INCLUDEDIRS := components/include 9 | 10 | include $(IDF_PATH)/make/project.mk 11 | -------------------------------------------------------------------------------- /gatt_client_car_controller/README.md: -------------------------------------------------------------------------------- 1 | # gatt_client_car_cotnroller 2 | A esp-idf project for car controller. 3 | 4 | # Pair project 5 | - [gatt_server_car](/gatt_server_car) 6 | 7 | # References 8 | - [GATT CLIENT API](http://esp-idf.readthedocs.io/en/latest/api-reference/bluetooth/esp_gattc.html) 9 | - [esp-idf/examples/peripherals/adc](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/adc) -------------------------------------------------------------------------------- /gatt_client_car_controller/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main Makefile. This is basically the same as a component makefile. 3 | # 4 | # This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, 5 | # this will take the sources in the src/ directory, compile them and link them into 6 | # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | 10 | #include $(IDF_PATH)/make/component_common.mk 11 | -------------------------------------------------------------------------------- /gatt_client_car_controller/main/gattc_demo.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 17 | /**************************************************************************** 18 | * 19 | * This file is for gatt client. It can scan ble device, connect one device, 20 | * 21 | ****************************************************************************/ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "controller.h" 28 | #include "esp_system.h" 29 | 30 | #include "bt.h" 31 | #include "bt_trace.h" 32 | #include "bt_types.h" 33 | #include "btm_api.h" 34 | #include "bta_api.h" 35 | #include "bta_gatt_api.h" 36 | #include "esp_gap_ble_api.h" 37 | #include "esp_gattc_api.h" 38 | #include "esp_gatt_defs.h" 39 | #include "esp_bt_main.h" 40 | 41 | #include "freertos/FreeRTOS.h" 42 | #include "freertos/task.h" 43 | #include "freertos/queue.h" 44 | #include "driver/gpio.h" 45 | #include "driver/adc.h" 46 | 47 | #define GPIO_OUTPUT_IO_0 2 // for LED 48 | #define GPIO_OUTPUT_IO_1 19 49 | #define GPIO_OUTPUT_PIN_SEL ((1< (b)) ? (a) : (b)) 57 | #define min(a,b) (((a) < (b)) ? (a) : (b)) 58 | #define minmax(a,b,x) (((x) > (b)) ? (b) : (((x) < (a)) ? (a) : (x))) 59 | 60 | ///Declare static functions 61 | static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); 62 | static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); 63 | static void gattc_profile_a_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); 64 | static void gattc_profile_b_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); 65 | 66 | esp_gatt_if_t gattc_if_to_write = ESP_GATT_IF_NONE; 67 | uint16_t conn_id_to_write; 68 | esp_gatt_srvc_id_t srvc_id_to_write; 69 | esp_gatt_id_t descr_id_to_write; 70 | 71 | static esp_gatt_srvc_id_t alert_service_id = { 72 | .id = { 73 | .uuid = { 74 | .len = ESP_UUID_LEN_16, 75 | .uuid = {.uuid16 = 0xff,}, //origin: 0x1811 76 | }, 77 | .inst_id = 0, 78 | }, 79 | .is_primary = true, 80 | }; 81 | 82 | static uint16_t listen_char_id = 0xff01; 83 | 84 | static esp_gatt_id_t write_descr_id = { 85 | .uuid = { 86 | .len = ESP_UUID_LEN_16, 87 | .uuid = {.uuid16 = 0xff01,}, 88 | }, 89 | .inst_id = 0, 90 | }; 91 | 92 | static esp_gatt_id_t notify_descr_id = { 93 | .uuid = { 94 | .len = ESP_UUID_LEN_16, 95 | .uuid = {.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG,}, 96 | }, 97 | .inst_id = 0, 98 | }; 99 | #define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" 100 | #define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] 101 | 102 | static bool connect = false; 103 | static const char device_name[] = "ESP_GATTS_CAR"; //origin: "Alert Notification" 104 | 105 | static esp_ble_scan_params_t ble_scan_params = { 106 | .scan_type = BLE_SCAN_TYPE_ACTIVE, 107 | .own_addr_type = BLE_ADDR_TYPE_PUBLIC, 108 | .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, 109 | .scan_interval = 0x50, 110 | .scan_window = 0x30 111 | }; 112 | 113 | 114 | #define PROFILE_NUM 2 115 | #define PROFILE_A_APP_ID 0 116 | #define PROFILE_B_APP_ID 1 117 | 118 | struct gattc_profile_inst { 119 | esp_gattc_cb_t gattc_cb; 120 | uint16_t gattc_if; 121 | uint16_t app_id; 122 | uint16_t conn_id; 123 | esp_bd_addr_t remote_bda; 124 | }; 125 | 126 | /* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */ 127 | static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = { 128 | [PROFILE_A_APP_ID] = { 129 | .gattc_cb = gattc_profile_a_event_handler, 130 | .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ 131 | }, 132 | [PROFILE_B_APP_ID] = { 133 | .gattc_cb = gattc_profile_b_event_handler, 134 | .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ 135 | }, 136 | }; 137 | 138 | static void init_led() { 139 | gpio_config_t io_conf; 140 | //disable interrupt 141 | io_conf.intr_type = GPIO_PIN_INTR_DISABLE; 142 | //set as output mode 143 | io_conf.mode = GPIO_MODE_OUTPUT; 144 | //bit mask of the pins that you want to set 145 | io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; 146 | //disable pull-down mode 147 | io_conf.pull_down_en = 0; 148 | //disable pull-up mode 149 | io_conf.pull_up_en = 0; 150 | //configure GPIO with the given settings 151 | gpio_config(&io_conf); 152 | 153 | printf("led initlalized"); 154 | } 155 | 156 | static void switch_led(bool value) { 157 | int out_value = 0; 158 | if (value) { 159 | out_value = 1; 160 | } 161 | printf("out value %d\n", out_value); 162 | gpio_set_level(GPIO_OUTPUT_IO_0, out_value); 163 | } 164 | 165 | static void gattc_profile_a_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) 166 | { 167 | uint16_t conn_id = 0; 168 | esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; 169 | printf("gattc_profile_a_event %d\n", event); 170 | printf("GET_CHAR_EVT %d\n", ESP_GATTC_GET_CHAR_EVT); 171 | switch (event) { 172 | case ESP_GATTC_REG_EVT: 173 | ESP_LOGI(GATTC_TAG, "REG_EVT\n"); 174 | esp_ble_gap_set_scan_params(&ble_scan_params); 175 | break; 176 | case ESP_GATTC_OPEN_EVT: 177 | conn_id = p_data->open.conn_id; 178 | 179 | memcpy(gl_profile_tab[PROFILE_A_APP_ID].remote_bda, p_data->open.remote_bda, sizeof(esp_bd_addr_t)); 180 | ESP_LOGI(GATTC_TAG, "ESP_GATTC_OPEN_EVT conn_id %d, if %d, status %d, mtu %d\n", conn_id, gattc_if, p_data->open.status, p_data->open.mtu); 181 | 182 | ESP_LOGI(GATTC_TAG, "REMOTE BDA %02x:%02x:%02x:%02x:%02x:%02x\n", 183 | gl_profile_tab[PROFILE_A_APP_ID].remote_bda[0], gl_profile_tab[PROFILE_A_APP_ID].remote_bda[1], 184 | gl_profile_tab[PROFILE_A_APP_ID].remote_bda[2], gl_profile_tab[PROFILE_A_APP_ID].remote_bda[3], 185 | gl_profile_tab[PROFILE_A_APP_ID].remote_bda[4], gl_profile_tab[PROFILE_A_APP_ID].remote_bda[5] 186 | ); 187 | 188 | esp_ble_gattc_search_service(gattc_if, conn_id, NULL); 189 | break; 190 | case ESP_GATTC_SEARCH_RES_EVT: { 191 | esp_gatt_srvc_id_t *srvc_id = &p_data->search_res.srvc_id; 192 | conn_id = p_data->search_res.conn_id; 193 | ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x\n", conn_id); 194 | if (srvc_id->id.uuid.len == ESP_UUID_LEN_16) { 195 | ESP_LOGI(GATTC_TAG, "UUID16: %x\n", srvc_id->id.uuid.uuid.uuid16); 196 | } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_32) { 197 | ESP_LOGI(GATTC_TAG, "UUID32: %x\n", srvc_id->id.uuid.uuid.uuid32); 198 | } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_128) { 199 | ESP_LOGI(GATTC_TAG, "UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n", srvc_id->id.uuid.uuid.uuid128[0], 200 | srvc_id->id.uuid.uuid.uuid128[1], srvc_id->id.uuid.uuid.uuid128[2], srvc_id->id.uuid.uuid.uuid128[3], 201 | srvc_id->id.uuid.uuid.uuid128[4], srvc_id->id.uuid.uuid.uuid128[5], srvc_id->id.uuid.uuid.uuid128[6], 202 | srvc_id->id.uuid.uuid.uuid128[7], srvc_id->id.uuid.uuid.uuid128[8], srvc_id->id.uuid.uuid.uuid128[9], 203 | srvc_id->id.uuid.uuid.uuid128[10], srvc_id->id.uuid.uuid.uuid128[11], srvc_id->id.uuid.uuid.uuid128[12], 204 | srvc_id->id.uuid.uuid.uuid128[13], srvc_id->id.uuid.uuid.uuid128[14], srvc_id->id.uuid.uuid.uuid128[15]); 205 | } else { 206 | ESP_LOGE(GATTC_TAG, "UNKNOWN LEN %d\n", srvc_id->id.uuid.len); 207 | } 208 | break; 209 | } 210 | case ESP_GATTC_SEARCH_CMPL_EVT: 211 | conn_id = p_data->search_cmpl.conn_id; 212 | ESP_LOGI(GATTC_TAG, "SEARCH_CMPL: conn_id = %x, status %d\n", conn_id, p_data->search_cmpl.status); 213 | esp_ble_gattc_get_characteristic(gattc_if, conn_id, &alert_service_id, NULL); 214 | break; 215 | case ESP_GATTC_GET_CHAR_EVT: 216 | printf("in get char evt\n"); 217 | if (p_data->get_char.status != ESP_GATT_OK) { 218 | printf("status is not OK\n"); 219 | break; 220 | } 221 | ESP_LOGI(GATTC_TAG, "GET CHAR: conn_id = %x, status %d\n", p_data->get_char.conn_id, p_data->get_char.status); 222 | ESP_LOGI(GATTC_TAG, "GET CHAR: srvc_id = %04x, char_id = %04x\n", p_data->get_char.srvc_id.id.uuid.uuid.uuid16, p_data->get_char.char_id.uuid.uuid.uuid16); 223 | 224 | if (p_data->get_char.char_id.uuid.uuid.uuid16 == listen_char_id ) { //origin: 0x2a46 225 | conn_id_to_write = conn_id; 226 | gattc_if_to_write = gattc_if; 227 | srvc_id_to_write = p_data->get_char.srvc_id; 228 | descr_id_to_write = p_data->reg_for_notify.char_id; 229 | ESP_LOGI(GATTC_TAG, "register notify\n"); 230 | esp_ble_gattc_register_for_notify(gattc_if, gl_profile_tab[PROFILE_A_APP_ID].remote_bda, &alert_service_id, &p_data->get_char.char_id); 231 | } 232 | 233 | esp_ble_gattc_get_characteristic(gattc_if, conn_id, &alert_service_id, &p_data->get_char.char_id); 234 | break; 235 | case ESP_GATTC_REG_FOR_NOTIFY_EVT: { 236 | uint16_t notify_en = 1; 237 | ESP_LOGI(GATTC_TAG, "REG FOR NOTIFY: status %d\n", p_data->reg_for_notify.status); 238 | ESP_LOGI(GATTC_TAG, "REG FOR_NOTIFY: srvc_id = %04x, char_id = %04x\n", p_data->reg_for_notify.srvc_id.id.uuid.uuid.uuid16, p_data->reg_for_notify.char_id.uuid.uuid.uuid16); 239 | 240 | esp_ble_gattc_write_char_descr( 241 | gattc_if, 242 | conn_id, 243 | &alert_service_id, 244 | &p_data->reg_for_notify.char_id, 245 | ¬ify_descr_id, 246 | sizeof(notify_en), 247 | (uint8_t *)¬ify_en, 248 | ESP_GATT_WRITE_TYPE_RSP, 249 | ESP_GATT_AUTH_REQ_NONE); 250 | break; 251 | } 252 | case ESP_GATTC_NOTIFY_EVT: 253 | ESP_LOGI(GATTC_TAG, "NOTIFY: len %d, value %08x\n", p_data->notify.value_len, *(uint32_t *)p_data->notify.value); 254 | switch_led(0 == (*(uint32_t *)p_data->notify.value % 2)); 255 | break; 256 | case ESP_GATTC_WRITE_DESCR_EVT: 257 | ESP_LOGI(GATTC_TAG, "WRITE: status %d\n", p_data->write.status); 258 | break; 259 | default: 260 | break; 261 | } 262 | } 263 | 264 | static void gattc_profile_b_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) 265 | { 266 | printf("gattc_profile_b_event %d\n", event); 267 | uint16_t conn_id = 0; 268 | esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; 269 | 270 | switch (event) { 271 | case ESP_GATTC_REG_EVT: 272 | ESP_LOGI(GATTC_TAG, "REG_EVT\n"); 273 | break; 274 | case ESP_GATTC_OPEN_EVT: 275 | conn_id = p_data->open.conn_id; 276 | 277 | memcpy(gl_profile_tab[PROFILE_B_APP_ID].remote_bda, p_data->open.remote_bda, sizeof(esp_bd_addr_t)); 278 | ESP_LOGI(GATTC_TAG, "ESP_GATTC_OPEN_EVT conn_id %d, if %d, status %d, mtu %d\n", conn_id, gattc_if, p_data->open.status, p_data->open.mtu); 279 | 280 | ESP_LOGI(GATTC_TAG, "REMOTE BDA %02x:%02x:%02x:%02x:%02x:%02x\n", 281 | gl_profile_tab[PROFILE_B_APP_ID].remote_bda[0], gl_profile_tab[PROFILE_B_APP_ID].remote_bda[1], 282 | gl_profile_tab[PROFILE_B_APP_ID].remote_bda[2], gl_profile_tab[PROFILE_B_APP_ID].remote_bda[3], 283 | gl_profile_tab[PROFILE_B_APP_ID].remote_bda[4], gl_profile_tab[PROFILE_B_APP_ID].remote_bda[5] 284 | ); 285 | 286 | esp_ble_gattc_search_service(gattc_if, conn_id, NULL); 287 | break; 288 | case ESP_GATTC_SEARCH_RES_EVT: { 289 | esp_gatt_srvc_id_t *srvc_id = &p_data->search_res.srvc_id; 290 | conn_id = p_data->search_res.conn_id; 291 | ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x\n", conn_id); 292 | if (srvc_id->id.uuid.len == ESP_UUID_LEN_16) { 293 | ESP_LOGI(GATTC_TAG, "UUID16: %x\n", srvc_id->id.uuid.uuid.uuid16); 294 | } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_32) { 295 | ESP_LOGI(GATTC_TAG, "UUID32: %x\n", srvc_id->id.uuid.uuid.uuid32); 296 | } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_128) { 297 | ESP_LOGI(GATTC_TAG, "UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n", srvc_id->id.uuid.uuid.uuid128[0], 298 | srvc_id->id.uuid.uuid.uuid128[1], srvc_id->id.uuid.uuid.uuid128[2], srvc_id->id.uuid.uuid.uuid128[3], 299 | srvc_id->id.uuid.uuid.uuid128[4], srvc_id->id.uuid.uuid.uuid128[5], srvc_id->id.uuid.uuid.uuid128[6], 300 | srvc_id->id.uuid.uuid.uuid128[7], srvc_id->id.uuid.uuid.uuid128[8], srvc_id->id.uuid.uuid.uuid128[9], 301 | srvc_id->id.uuid.uuid.uuid128[10], srvc_id->id.uuid.uuid.uuid128[11], srvc_id->id.uuid.uuid.uuid128[12], 302 | srvc_id->id.uuid.uuid.uuid128[13], srvc_id->id.uuid.uuid.uuid128[14], srvc_id->id.uuid.uuid.uuid128[15]); 303 | } else { 304 | ESP_LOGE(GATTC_TAG, "UNKNOWN LEN %d\n", srvc_id->id.uuid.len); 305 | } 306 | break; 307 | } 308 | case ESP_GATTC_SEARCH_CMPL_EVT: 309 | conn_id = p_data->search_cmpl.conn_id; 310 | ESP_LOGI(GATTC_TAG, "SEARCH_CMPL: conn_id = %x, status %d\n", conn_id, p_data->search_cmpl.status); 311 | esp_ble_gattc_get_characteristic(gattc_if, conn_id, &alert_service_id, NULL); 312 | break; 313 | case ESP_GATTC_GET_CHAR_EVT: 314 | if (p_data->get_char.status != ESP_GATT_OK) { 315 | break; 316 | } 317 | ESP_LOGI(GATTC_TAG, "GET CHAR: conn_id = %x, status %d\n", p_data->get_char.conn_id, p_data->get_char.status); 318 | ESP_LOGI(GATTC_TAG, "GET CHAR: srvc_id = %04x, char_id = %04x\n", p_data->get_char.srvc_id.id.uuid.uuid.uuid16, p_data->get_char.char_id.uuid.uuid.uuid16); 319 | 320 | if (p_data->get_char.char_id.uuid.uuid.uuid16 == 0x2a46) { 321 | ESP_LOGI(GATTC_TAG, "register notify\n"); 322 | esp_ble_gattc_register_for_notify(gattc_if, gl_profile_tab[PROFILE_B_APP_ID].remote_bda, &alert_service_id, &p_data->get_char.char_id); 323 | } 324 | 325 | esp_ble_gattc_get_characteristic(gattc_if, conn_id, &alert_service_id, &p_data->get_char.char_id); 326 | break; 327 | case ESP_GATTC_REG_FOR_NOTIFY_EVT: { 328 | uint16_t notify_en = 1; 329 | ESP_LOGI(GATTC_TAG, "REG FOR NOTIFY: status %d\n", p_data->reg_for_notify.status); 330 | ESP_LOGI(GATTC_TAG, "REG FOR_NOTIFY: srvc_id = %04x, char_id = %04x\n", p_data->reg_for_notify.srvc_id.id.uuid.uuid.uuid16, p_data->reg_for_notify.char_id.uuid.uuid.uuid16); 331 | 332 | esp_ble_gattc_write_char_descr( 333 | gattc_if, 334 | conn_id, 335 | &alert_service_id, 336 | &p_data->reg_for_notify.char_id, 337 | ¬ify_descr_id, 338 | sizeof(notify_en), 339 | (uint8_t *)¬ify_en, 340 | ESP_GATT_WRITE_TYPE_RSP, 341 | ESP_GATT_AUTH_REQ_NONE); 342 | break; 343 | } 344 | case ESP_GATTC_NOTIFY_EVT: 345 | ESP_LOGI(GATTC_TAG, "NOTIFY: len %d, value %08x\n", p_data->notify.value_len, *(uint32_t *)p_data->notify.value); 346 | break; 347 | case ESP_GATTC_WRITE_DESCR_EVT: 348 | ESP_LOGI(GATTC_TAG, "WRITE: status %d\n", p_data->write.status); 349 | break; 350 | default: 351 | break; 352 | } 353 | } 354 | 355 | static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) 356 | { 357 | uint8_t *adv_name = NULL; 358 | uint8_t adv_name_len = 0; 359 | printf("esp_gap_cb\n"); 360 | switch (event) { 361 | case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { 362 | printf("ble scan param set completed\n"); 363 | //the unit of the duration is second 364 | uint32_t duration = 10; 365 | esp_ble_gap_start_scanning(duration); 366 | break; 367 | } 368 | case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: 369 | printf("start ble scan\n"); 370 | //scan start complete event to indicate scan start successfully or failed 371 | if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { 372 | ESP_LOGE(GATTC_TAG, "Scan start failed\n"); 373 | } 374 | break; 375 | case ESP_GAP_BLE_SCAN_RESULT_EVT: { 376 | printf("ble scan result\n"); 377 | esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param; 378 | switch (scan_result->scan_rst.search_evt) { 379 | case ESP_GAP_SEARCH_INQ_RES_EVT: 380 | printf("gap search inq res\n"); 381 | printf("scan rst bda: "); 382 | for (int i = 0; i < 6; i++) { 383 | //ESP_LOGI(GATTC_TAG, "%x:", scan_result->scan_rst.bda[i]); 384 | printf("%02x ", scan_result->scan_rst.bda[i]); 385 | } 386 | // ESP_LOGI(GATTC_TAG, "\n"); 387 | printf("\n"); 388 | adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, 389 | ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len); 390 | ESP_LOGI(GATTC_TAG, "Searched Device Name Len %d", adv_name_len); 391 | for (int j = 0; j < adv_name_len; j++) { 392 | //ESP_LOGI(GATTC_TAG, "%c", adv_name[j]); 393 | printf("%c", adv_name[j]); 394 | } 395 | printf("\n"); 396 | 397 | printf("adv_name check\n"); 398 | if (adv_name != NULL) { 399 | printf("adv_name is not null\n"); 400 | if (strncmp((char *)adv_name, device_name, adv_name_len) == 0) { 401 | ESP_LOGI(GATTC_TAG, "Searched device %s\n", device_name); 402 | if (connect == false) { 403 | connect = true; 404 | ESP_LOGI(GATTC_TAG, "Connect to the remote device.\n"); 405 | esp_ble_gap_stop_scanning(); 406 | esp_ble_gattc_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, scan_result->scan_rst.bda, true); 407 | esp_ble_gattc_open(gl_profile_tab[PROFILE_B_APP_ID].gattc_if, scan_result->scan_rst.bda, true); 408 | } 409 | } 410 | } 411 | break; 412 | case ESP_GAP_SEARCH_INQ_CMPL_EVT: 413 | printf("gap search inq compl\n"); 414 | break; 415 | default: 416 | break; 417 | } 418 | printf("break ble scan result\n\n"); 419 | break; 420 | } 421 | default: 422 | break; 423 | } 424 | } 425 | 426 | static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) 427 | { 428 | printf("esp_gatt_cb\n"); 429 | ESP_LOGI(GATTC_TAG, "EVT %d, gattc if %d\n", event, gattc_if); 430 | 431 | /* If event is register event, store the gattc_if for each profile */ 432 | if (event == ESP_GATTC_REG_EVT) { 433 | if (param->reg.status == ESP_GATT_OK) { 434 | gl_profile_tab[param->reg.app_id].gattc_if = gattc_if; 435 | } else { 436 | ESP_LOGI(GATTC_TAG, "Reg app failed, app_id %04x, status %d\n", 437 | param->reg.app_id, 438 | param->reg.status); 439 | return; 440 | } 441 | } 442 | 443 | /* If the gattc_if equal to profile A, call profile A cb handler, 444 | * so here call each profile's callback */ 445 | do { 446 | int idx; 447 | for (idx = 0; idx < PROFILE_NUM; idx++) { 448 | if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ 449 | gattc_if == gl_profile_tab[idx].gattc_if) { 450 | if (gl_profile_tab[idx].gattc_cb) { 451 | gl_profile_tab[idx].gattc_cb(event, gattc_if, param); 452 | } 453 | } 454 | } 455 | } while (0); 456 | } 457 | 458 | void ble_client_appRegister(void) 459 | { 460 | esp_err_t status; 461 | 462 | ESP_LOGI(GATTC_TAG, "register callback\n"); 463 | 464 | //register the scan callback function to the gap moudule 465 | if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) { 466 | ESP_LOGE(GATTC_TAG, "gap register error, error code = %x\n", status); 467 | return; 468 | } 469 | 470 | //register the callback function to the gattc module 471 | if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK) { 472 | ESP_LOGE(GATTC_TAG, "gattc register error, error code = %x\n", status); 473 | return; 474 | } 475 | esp_ble_gattc_app_register(PROFILE_A_APP_ID); 476 | esp_ble_gattc_app_register(PROFILE_B_APP_ID); 477 | } 478 | 479 | void gattc_client_test(void) 480 | { 481 | esp_bluedroid_init(); 482 | esp_bluedroid_enable(); 483 | ble_client_appRegister(); 484 | } 485 | 486 | void init_adc() { 487 | adc1_config_width(ADC_WIDTH_12Bit); 488 | adc1_config_channel_atten(ADC_CHAN_CONTROLLER_FB, ADC_ATTEN_11db); 489 | adc1_config_channel_atten(ADC_CHAN_CONTROLLER_LR, ADC_ATTEN_11db); 490 | } 491 | 492 | uint16_t get_top_value_from_center (uint16_t input_value, uint16_t center_value, uint16_t buffer_value) { 493 | if (input_value > (center_value + buffer_value)) { 494 | return ((input_value - center_value) / 7); 495 | } else { 496 | return 0; 497 | } 498 | }; 499 | 500 | uint16_t get_bottom_value_from_center (uint16_t input_value, uint16_t center_value, uint16_t buffer_value) { 501 | if (input_value < (center_value - buffer_value)) { 502 | return ((center_value - input_value) / 7); 503 | } else { 504 | return 0; 505 | } 506 | }; 507 | 508 | uint16_t fb_value; 509 | uint16_t lr_value; 510 | uint16_t f_value; 511 | uint16_t b_value; 512 | uint16_t r_value; 513 | uint16_t l_value; 514 | uint16_t center_value = 1850; 515 | uint16_t center_buffer = 400; 516 | 517 | uint8_t lf_value; 518 | uint8_t lb_value; 519 | uint8_t rf_value; 520 | uint8_t rb_value; 521 | 522 | void send_by_controller_input() { 523 | fb_value = adc1_get_voltage(ADC_CHAN_CONTROLLER_FB); 524 | lr_value = adc1_get_voltage(ADC_CHAN_CONTROLLER_LR); 525 | 526 | f_value = get_bottom_value_from_center(fb_value, center_value, center_buffer); 527 | b_value = get_top_value_from_center(fb_value, center_value, center_buffer); 528 | l_value = get_top_value_from_center(lr_value, center_value, center_buffer); 529 | r_value = get_bottom_value_from_center(lr_value, center_value, center_buffer); 530 | 531 | // printf("FB: %d\nF: %d\nB: %d\n", fb_value, f_value, b_value); 532 | // printf("LR: %d\nL: %d\nR: %d\n", lr_value, l_value, r_value); 533 | 534 | if (f_value > 0) { 535 | lf_value = (uint8_t) minmax(0,255,f_value - l_value); 536 | lb_value = 0; 537 | rf_value = (uint8_t) minmax(0,255,f_value - r_value); 538 | rb_value = 0; 539 | } else if (b_value > 0) { 540 | lf_value = 0; 541 | lb_value = (uint8_t) minmax(0,255,b_value - l_value); 542 | rf_value = 0; 543 | rb_value = (uint8_t) minmax(0,255,b_value - r_value); 544 | } else { 545 | lf_value = 0; 546 | lb_value = 0; 547 | rf_value = 0; 548 | rb_value = 0; 549 | } 550 | 551 | // printf("lf: %03d, rf: %03d\n", lf_value, rf_value); 552 | // printf("lb: %03d, rb: %03d\n", lb_value, rb_value); 553 | 554 | uint8_t sending_values[] = {lf_value, lb_value, rf_value, rb_value}; 555 | 556 | if (gattc_if_to_write != ESP_GATT_IF_NONE) { 557 | printf("send to gattc_if: %d\n", gattc_if_to_write); 558 | esp_ble_gattc_write_char( 559 | gattc_if_to_write, 560 | conn_id_to_write, 561 | &srvc_id_to_write, 562 | &write_descr_id, 563 | sizeof(sending_values), 564 | (uint8_t *) sending_values, 565 | ESP_GATT_WRITE_TYPE_RSP, 566 | ESP_GATT_AUTH_REQ_NONE); 567 | } else { 568 | printf("gatt_if is not connected\n"); 569 | } 570 | } 571 | 572 | void app_main() 573 | { 574 | esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); 575 | esp_bt_controller_init(&bt_cfg); 576 | esp_bt_controller_enable(ESP_BT_MODE_BTDM); 577 | 578 | gattc_client_test(); 579 | init_led(); 580 | init_adc(); 581 | 582 | while(1) { 583 | send_by_controller_input(); 584 | vTaskDelay(100/portTICK_PERIOD_MS); 585 | } 586 | } 587 | 588 | -------------------------------------------------------------------------------- /gatt_client_car_controller/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # Override some defaults so BT stack is enabled 2 | # and WiFi disabled by default in this example 3 | CONFIG_BT_ENABLED=y 4 | CONFIG_WIFI_ENABLED=n 5 | -------------------------------------------------------------------------------- /gatt_client_listen_notif_then_output_to_led/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := gatt_client_demo 7 | 8 | COMPONENT_ADD_INCLUDEDIRS := components/include 9 | 10 | include $(IDF_PATH)/make/project.mk 11 | -------------------------------------------------------------------------------- /gatt_client_listen_notif_then_output_to_led/README.md: -------------------------------------------------------------------------------- 1 | # gatt_client_listen_notif_then_output_to_led 2 | An esp-idf project based on examples/gatt_client 3 | 4 | # Partner proejct 5 | This project can communidate with the following project. 6 | 7 | [gatt_server_notif_switch](../gatt_server_notif_switch) 8 | 9 | # License 10 | Apache v2 -------------------------------------------------------------------------------- /gatt_client_listen_notif_then_output_to_led/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main Makefile. This is basically the same as a component makefile. 3 | # 4 | # This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, 5 | # this will take the sources in the src/ directory, compile them and link them into 6 | # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | 10 | #include $(IDF_PATH)/make/component_common.mk 11 | -------------------------------------------------------------------------------- /gatt_client_listen_notif_then_output_to_led/main/gattc_demo.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 17 | /**************************************************************************** 18 | * 19 | * This file is for gatt client. It can scan ble device, connect one device, 20 | * 21 | ****************************************************************************/ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "nvs.h" 28 | #include "nvs_flash.h" 29 | #include "controller.h" 30 | #include "esp_system.h" 31 | 32 | #include "bt.h" 33 | #include "bt_trace.h" 34 | #include "bt_types.h" 35 | #include "btm_api.h" 36 | #include "bta_api.h" 37 | #include "bta_gatt_api.h" 38 | #include "esp_gap_ble_api.h" 39 | #include "esp_gattc_api.h" 40 | #include "esp_gatt_defs.h" 41 | #include "esp_bt_main.h" 42 | 43 | #define GPIO_OUTPUT_IO_0 2 // for LED 44 | #define GPIO_OUTPUT_IO_1 19 45 | #define GPIO_OUTPUT_PIN_SEL ((1<open.conn_id; 154 | 155 | memcpy(gl_profile_tab[PROFILE_A_APP_ID].remote_bda, p_data->open.remote_bda, sizeof(esp_bd_addr_t)); 156 | ESP_LOGI(GATTC_TAG, "ESP_GATTC_OPEN_EVT conn_id %d, if %d, status %d, mtu %d\n", conn_id, gattc_if, p_data->open.status, p_data->open.mtu); 157 | 158 | ESP_LOGI(GATTC_TAG, "REMOTE BDA %02x:%02x:%02x:%02x:%02x:%02x\n", 159 | gl_profile_tab[PROFILE_A_APP_ID].remote_bda[0], gl_profile_tab[PROFILE_A_APP_ID].remote_bda[1], 160 | gl_profile_tab[PROFILE_A_APP_ID].remote_bda[2], gl_profile_tab[PROFILE_A_APP_ID].remote_bda[3], 161 | gl_profile_tab[PROFILE_A_APP_ID].remote_bda[4], gl_profile_tab[PROFILE_A_APP_ID].remote_bda[5] 162 | ); 163 | 164 | esp_ble_gattc_search_service(gattc_if, conn_id, NULL); 165 | break; 166 | case ESP_GATTC_SEARCH_RES_EVT: { 167 | esp_gatt_srvc_id_t *srvc_id = &p_data->search_res.srvc_id; 168 | conn_id = p_data->search_res.conn_id; 169 | ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x\n", conn_id); 170 | if (srvc_id->id.uuid.len == ESP_UUID_LEN_16) { 171 | ESP_LOGI(GATTC_TAG, "UUID16: %x\n", srvc_id->id.uuid.uuid.uuid16); 172 | } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_32) { 173 | ESP_LOGI(GATTC_TAG, "UUID32: %x\n", srvc_id->id.uuid.uuid.uuid32); 174 | } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_128) { 175 | ESP_LOGI(GATTC_TAG, "UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n", srvc_id->id.uuid.uuid.uuid128[0], 176 | srvc_id->id.uuid.uuid.uuid128[1], srvc_id->id.uuid.uuid.uuid128[2], srvc_id->id.uuid.uuid.uuid128[3], 177 | srvc_id->id.uuid.uuid.uuid128[4], srvc_id->id.uuid.uuid.uuid128[5], srvc_id->id.uuid.uuid.uuid128[6], 178 | srvc_id->id.uuid.uuid.uuid128[7], srvc_id->id.uuid.uuid.uuid128[8], srvc_id->id.uuid.uuid.uuid128[9], 179 | srvc_id->id.uuid.uuid.uuid128[10], srvc_id->id.uuid.uuid.uuid128[11], srvc_id->id.uuid.uuid.uuid128[12], 180 | srvc_id->id.uuid.uuid.uuid128[13], srvc_id->id.uuid.uuid.uuid128[14], srvc_id->id.uuid.uuid.uuid128[15]); 181 | } else { 182 | ESP_LOGE(GATTC_TAG, "UNKNOWN LEN %d\n", srvc_id->id.uuid.len); 183 | } 184 | break; 185 | } 186 | case ESP_GATTC_SEARCH_CMPL_EVT: 187 | conn_id = p_data->search_cmpl.conn_id; 188 | ESP_LOGI(GATTC_TAG, "SEARCH_CMPL: conn_id = %x, status %d\n", conn_id, p_data->search_cmpl.status); 189 | esp_ble_gattc_get_characteristic(gattc_if, conn_id, &alert_service_id, NULL); 190 | break; 191 | case ESP_GATTC_GET_CHAR_EVT: 192 | printf("in get char evt\n"); 193 | if (p_data->get_char.status != ESP_GATT_OK) { 194 | printf("status is not OK\n"); 195 | break; 196 | } 197 | ESP_LOGI(GATTC_TAG, "GET CHAR: conn_id = %x, status %d\n", p_data->get_char.conn_id, p_data->get_char.status); 198 | ESP_LOGI(GATTC_TAG, "GET CHAR: srvc_id = %04x, char_id = %04x\n", p_data->get_char.srvc_id.id.uuid.uuid.uuid16, p_data->get_char.char_id.uuid.uuid.uuid16); 199 | 200 | if (p_data->get_char.char_id.uuid.uuid.uuid16 == listen_char_id ) { //origin: 0x2a46 201 | ESP_LOGI(GATTC_TAG, "register notify\n"); 202 | esp_ble_gattc_register_for_notify(gattc_if, gl_profile_tab[PROFILE_A_APP_ID].remote_bda, &alert_service_id, &p_data->get_char.char_id); 203 | } 204 | 205 | esp_ble_gattc_get_characteristic(gattc_if, conn_id, &alert_service_id, &p_data->get_char.char_id); 206 | break; 207 | case ESP_GATTC_REG_FOR_NOTIFY_EVT: { 208 | uint16_t notify_en = 1; 209 | ESP_LOGI(GATTC_TAG, "REG FOR NOTIFY: status %d\n", p_data->reg_for_notify.status); 210 | ESP_LOGI(GATTC_TAG, "REG FOR_NOTIFY: srvc_id = %04x, char_id = %04x\n", p_data->reg_for_notify.srvc_id.id.uuid.uuid.uuid16, p_data->reg_for_notify.char_id.uuid.uuid.uuid16); 211 | 212 | esp_ble_gattc_write_char_descr( 213 | gattc_if, 214 | conn_id, 215 | &alert_service_id, 216 | &p_data->reg_for_notify.char_id, 217 | ¬ify_descr_id, 218 | sizeof(notify_en), 219 | (uint8_t *)¬ify_en, 220 | ESP_GATT_WRITE_TYPE_RSP, 221 | ESP_GATT_AUTH_REQ_NONE); 222 | break; 223 | } 224 | case ESP_GATTC_NOTIFY_EVT: 225 | ESP_LOGI(GATTC_TAG, "NOTIFY: len %d, value %08x\n", p_data->notify.value_len, *(uint32_t *)p_data->notify.value); 226 | switch_led(0 == (*(uint32_t *)p_data->notify.value % 2)); 227 | break; 228 | case ESP_GATTC_WRITE_DESCR_EVT: 229 | ESP_LOGI(GATTC_TAG, "WRITE: status %d\n", p_data->write.status); 230 | break; 231 | default: 232 | break; 233 | } 234 | } 235 | 236 | static void gattc_profile_b_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) 237 | { 238 | printf("gattc_profile_b_event %d\n", event); 239 | uint16_t conn_id = 0; 240 | esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; 241 | 242 | switch (event) { 243 | case ESP_GATTC_REG_EVT: 244 | ESP_LOGI(GATTC_TAG, "REG_EVT\n"); 245 | break; 246 | case ESP_GATTC_OPEN_EVT: 247 | conn_id = p_data->open.conn_id; 248 | 249 | memcpy(gl_profile_tab[PROFILE_B_APP_ID].remote_bda, p_data->open.remote_bda, sizeof(esp_bd_addr_t)); 250 | ESP_LOGI(GATTC_TAG, "ESP_GATTC_OPEN_EVT conn_id %d, if %d, status %d, mtu %d\n", conn_id, gattc_if, p_data->open.status, p_data->open.mtu); 251 | 252 | ESP_LOGI(GATTC_TAG, "REMOTE BDA %02x:%02x:%02x:%02x:%02x:%02x\n", 253 | gl_profile_tab[PROFILE_B_APP_ID].remote_bda[0], gl_profile_tab[PROFILE_B_APP_ID].remote_bda[1], 254 | gl_profile_tab[PROFILE_B_APP_ID].remote_bda[2], gl_profile_tab[PROFILE_B_APP_ID].remote_bda[3], 255 | gl_profile_tab[PROFILE_B_APP_ID].remote_bda[4], gl_profile_tab[PROFILE_B_APP_ID].remote_bda[5] 256 | ); 257 | 258 | esp_ble_gattc_search_service(gattc_if, conn_id, NULL); 259 | break; 260 | case ESP_GATTC_SEARCH_RES_EVT: { 261 | esp_gatt_srvc_id_t *srvc_id = &p_data->search_res.srvc_id; 262 | conn_id = p_data->search_res.conn_id; 263 | ESP_LOGI(GATTC_TAG, "SEARCH RES: conn_id = %x\n", conn_id); 264 | if (srvc_id->id.uuid.len == ESP_UUID_LEN_16) { 265 | ESP_LOGI(GATTC_TAG, "UUID16: %x\n", srvc_id->id.uuid.uuid.uuid16); 266 | } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_32) { 267 | ESP_LOGI(GATTC_TAG, "UUID32: %x\n", srvc_id->id.uuid.uuid.uuid32); 268 | } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_128) { 269 | ESP_LOGI(GATTC_TAG, "UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n", srvc_id->id.uuid.uuid.uuid128[0], 270 | srvc_id->id.uuid.uuid.uuid128[1], srvc_id->id.uuid.uuid.uuid128[2], srvc_id->id.uuid.uuid.uuid128[3], 271 | srvc_id->id.uuid.uuid.uuid128[4], srvc_id->id.uuid.uuid.uuid128[5], srvc_id->id.uuid.uuid.uuid128[6], 272 | srvc_id->id.uuid.uuid.uuid128[7], srvc_id->id.uuid.uuid.uuid128[8], srvc_id->id.uuid.uuid.uuid128[9], 273 | srvc_id->id.uuid.uuid.uuid128[10], srvc_id->id.uuid.uuid.uuid128[11], srvc_id->id.uuid.uuid.uuid128[12], 274 | srvc_id->id.uuid.uuid.uuid128[13], srvc_id->id.uuid.uuid.uuid128[14], srvc_id->id.uuid.uuid.uuid128[15]); 275 | } else { 276 | ESP_LOGE(GATTC_TAG, "UNKNOWN LEN %d\n", srvc_id->id.uuid.len); 277 | } 278 | break; 279 | } 280 | case ESP_GATTC_SEARCH_CMPL_EVT: 281 | conn_id = p_data->search_cmpl.conn_id; 282 | ESP_LOGI(GATTC_TAG, "SEARCH_CMPL: conn_id = %x, status %d\n", conn_id, p_data->search_cmpl.status); 283 | esp_ble_gattc_get_characteristic(gattc_if, conn_id, &alert_service_id, NULL); 284 | break; 285 | case ESP_GATTC_GET_CHAR_EVT: 286 | if (p_data->get_char.status != ESP_GATT_OK) { 287 | break; 288 | } 289 | ESP_LOGI(GATTC_TAG, "GET CHAR: conn_id = %x, status %d\n", p_data->get_char.conn_id, p_data->get_char.status); 290 | ESP_LOGI(GATTC_TAG, "GET CHAR: srvc_id = %04x, char_id = %04x\n", p_data->get_char.srvc_id.id.uuid.uuid.uuid16, p_data->get_char.char_id.uuid.uuid.uuid16); 291 | 292 | if (p_data->get_char.char_id.uuid.uuid.uuid16 == 0x2a46) { 293 | ESP_LOGI(GATTC_TAG, "register notify\n"); 294 | esp_ble_gattc_register_for_notify(gattc_if, gl_profile_tab[PROFILE_B_APP_ID].remote_bda, &alert_service_id, &p_data->get_char.char_id); 295 | } 296 | 297 | esp_ble_gattc_get_characteristic(gattc_if, conn_id, &alert_service_id, &p_data->get_char.char_id); 298 | break; 299 | case ESP_GATTC_REG_FOR_NOTIFY_EVT: { 300 | uint16_t notify_en = 1; 301 | ESP_LOGI(GATTC_TAG, "REG FOR NOTIFY: status %d\n", p_data->reg_for_notify.status); 302 | ESP_LOGI(GATTC_TAG, "REG FOR_NOTIFY: srvc_id = %04x, char_id = %04x\n", p_data->reg_for_notify.srvc_id.id.uuid.uuid.uuid16, p_data->reg_for_notify.char_id.uuid.uuid.uuid16); 303 | 304 | esp_ble_gattc_write_char_descr( 305 | gattc_if, 306 | conn_id, 307 | &alert_service_id, 308 | &p_data->reg_for_notify.char_id, 309 | ¬ify_descr_id, 310 | sizeof(notify_en), 311 | (uint8_t *)¬ify_en, 312 | ESP_GATT_WRITE_TYPE_RSP, 313 | ESP_GATT_AUTH_REQ_NONE); 314 | break; 315 | } 316 | case ESP_GATTC_NOTIFY_EVT: 317 | ESP_LOGI(GATTC_TAG, "NOTIFY: len %d, value %08x\n", p_data->notify.value_len, *(uint32_t *)p_data->notify.value); 318 | break; 319 | case ESP_GATTC_WRITE_DESCR_EVT: 320 | ESP_LOGI(GATTC_TAG, "WRITE: status %d\n", p_data->write.status); 321 | break; 322 | default: 323 | break; 324 | } 325 | } 326 | 327 | static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) 328 | { 329 | uint8_t *adv_name = NULL; 330 | uint8_t adv_name_len = 0; 331 | printf("esp_gap_cb\n"); 332 | switch (event) { 333 | case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { 334 | printf("ble scan param set completed\n"); 335 | //the unit of the duration is second 336 | uint32_t duration = 10; 337 | esp_ble_gap_start_scanning(duration); 338 | break; 339 | } 340 | case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: 341 | printf("start ble scan\n"); 342 | //scan start complete event to indicate scan start successfully or failed 343 | if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { 344 | ESP_LOGE(GATTC_TAG, "Scan start failed\n"); 345 | } 346 | break; 347 | case ESP_GAP_BLE_SCAN_RESULT_EVT: { 348 | printf("ble scan result\n"); 349 | esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param; 350 | switch (scan_result->scan_rst.search_evt) { 351 | case ESP_GAP_SEARCH_INQ_RES_EVT: 352 | printf("gap search inq res\n"); 353 | printf("scan rst bda: "); 354 | for (int i = 0; i < 6; i++) { 355 | //ESP_LOGI(GATTC_TAG, "%x:", scan_result->scan_rst.bda[i]); 356 | printf("%02x ", scan_result->scan_rst.bda[i]); 357 | } 358 | // ESP_LOGI(GATTC_TAG, "\n"); 359 | printf("\n"); 360 | adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, 361 | ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len); 362 | ESP_LOGI(GATTC_TAG, "Searched Device Name Len %d", adv_name_len); 363 | for (int j = 0; j < adv_name_len; j++) { 364 | //ESP_LOGI(GATTC_TAG, "%c", adv_name[j]); 365 | printf("%c", adv_name[j]); 366 | } 367 | printf("\n"); 368 | 369 | printf("adv_name check\n"); 370 | if (adv_name != NULL) { 371 | printf("adv_name is not null\n"); 372 | if (strncmp((char *)adv_name, device_name, adv_name_len) == 0) { 373 | ESP_LOGI(GATTC_TAG, "Searched device %s\n", device_name); 374 | if (connect == false) { 375 | connect = true; 376 | ESP_LOGI(GATTC_TAG, "Connect to the remote device.\n"); 377 | esp_ble_gap_stop_scanning(); 378 | esp_ble_gattc_open(gl_profile_tab[PROFILE_A_APP_ID].gattc_if, scan_result->scan_rst.bda, true); 379 | esp_ble_gattc_open(gl_profile_tab[PROFILE_B_APP_ID].gattc_if, scan_result->scan_rst.bda, true); 380 | } 381 | } 382 | } 383 | break; 384 | case ESP_GAP_SEARCH_INQ_CMPL_EVT: 385 | printf("gap search inq compl\n"); 386 | break; 387 | default: 388 | break; 389 | } 390 | printf("break ble scan result\n\n"); 391 | break; 392 | } 393 | default: 394 | break; 395 | } 396 | } 397 | 398 | static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) 399 | { 400 | printf("esp_gatt_cb\n"); 401 | ESP_LOGI(GATTC_TAG, "EVT %d, gattc if %d\n", event, gattc_if); 402 | 403 | /* If event is register event, store the gattc_if for each profile */ 404 | if (event == ESP_GATTC_REG_EVT) { 405 | if (param->reg.status == ESP_GATT_OK) { 406 | gl_profile_tab[param->reg.app_id].gattc_if = gattc_if; 407 | } else { 408 | ESP_LOGI(GATTC_TAG, "Reg app failed, app_id %04x, status %d\n", 409 | param->reg.app_id, 410 | param->reg.status); 411 | return; 412 | } 413 | } 414 | 415 | /* If the gattc_if equal to profile A, call profile A cb handler, 416 | * so here call each profile's callback */ 417 | do { 418 | int idx; 419 | for (idx = 0; idx < PROFILE_NUM; idx++) { 420 | if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ 421 | gattc_if == gl_profile_tab[idx].gattc_if) { 422 | if (gl_profile_tab[idx].gattc_cb) { 423 | gl_profile_tab[idx].gattc_cb(event, gattc_if, param); 424 | } 425 | } 426 | } 427 | } while (0); 428 | } 429 | 430 | void ble_client_appRegister(void) 431 | { 432 | esp_err_t status; 433 | 434 | ESP_LOGI(GATTC_TAG, "register callback\n"); 435 | 436 | //register the scan callback function to the gap moudule 437 | if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) { 438 | ESP_LOGE(GATTC_TAG, "gap register error, error code = %x\n", status); 439 | return; 440 | } 441 | 442 | //register the callback function to the gattc module 443 | if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK) { 444 | ESP_LOGE(GATTC_TAG, "gattc register error, error code = %x\n", status); 445 | return; 446 | } 447 | esp_ble_gattc_app_register(PROFILE_A_APP_ID); 448 | esp_ble_gattc_app_register(PROFILE_B_APP_ID); 449 | } 450 | 451 | void gattc_client_test(void) 452 | { 453 | esp_bluedroid_init(); 454 | esp_bluedroid_enable(); 455 | ble_client_appRegister(); 456 | } 457 | 458 | void app_main() 459 | { 460 | // Initialize NVS. 461 | esp_err_t ret = nvs_flash_init(); 462 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { 463 | ESP_ERROR_CHECK(nvs_flash_erase()); 464 | ret = nvs_flash_init(); 465 | } 466 | ESP_ERROR_CHECK( ret ); 467 | 468 | esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); 469 | esp_bt_controller_init(&bt_cfg); 470 | esp_bt_controller_enable(ESP_BT_MODE_BTDM); 471 | 472 | gattc_client_test(); 473 | init_led(); 474 | } 475 | 476 | -------------------------------------------------------------------------------- /gatt_client_listen_notif_then_output_to_led/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # Override some defaults so BT stack is enabled 2 | # and WiFi disabled by default in this example 3 | CONFIG_BT_ENABLED=y 4 | CONFIG_WIFI_ENABLED=n 5 | -------------------------------------------------------------------------------- /gatt_server_car/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := gatt_server_demos 7 | 8 | COMPONENT_ADD_INCLUDEDIRS := components/include 9 | 10 | include $(IDF_PATH)/make/project.mk 11 | -------------------------------------------------------------------------------- /gatt_server_car/README.md: -------------------------------------------------------------------------------- 1 | # gatt_server_car 2 | A project for car that can controll over BLE GATT connection. 3 | 4 | # Pair project 5 | - [gatt_client_car_controller](/gatt_client_car_controller) 6 | - [re-natal-esp32control-app](https://github.com/asukiaaa/re-natal-esp32control-app)] 7 | 8 | # Component 9 | - [MPU-9250](https://www.aliexpress.com/item/MPU-9250-GY-9250-9-axis-sensor-module-I2C-SPI-Communications-Thriaxis-gyroscope-triaxial-accelerometer-triaxial/32657044146.html?spm=2114.search0104.3.65.vprPdk&ws_ab_test=searchweb0_0,searchweb201602_3_10152_10065_10151_10068_5400011_5430020_5410020_10307_10137_10060_10155_10154_10333_5370011_10334_10056_10335_10055_10054_10059_10332_100031_10099_10103_10102_10052_10053_10107_10050_10142_10051_10326_5390020_10084_10083_10080_10082_10081_10110_10175_10111_5420020_10112_10113_10114_10312_10313_10314_10315_10078_10079_10073,searchweb201603_1,ppcSwitch_7&btsid=0e08e01b-e73b-4de0-a498-907f6c891eaa&algo_expid=d8592909-2710-4ed9-a983-948849a70354-8&algo_pvid=d8592909-2710-4ed9-a983-948849a70354&transAbTest=ae803_3) 10 | - [TB6612FNG](https://www.aliexpress.com/item/5PCS-Free-Shipping-Dual-Motor-Driver-1A-TB6612FNG-for-Arduino-Microcontroller-Better-than-L298N-TB6612/32696432503.html?spm=a2g0s.9042311.0.0.ZJazYc) 11 | 12 | # References 13 | - [LED-PWM example for a beginner?](https://www.esp32.com/viewtopic.php?f=13&t=821) 14 | - [esp-idf/examples/peripherals/ledc/main/ledc_example_main.c](https://github.com/espressif/esp-idf/blob/master/examples/peripherals/ledc/main/ledc_example_main.c) 15 | - [esp-idf/examples/bluetooth/gatt_server/main/gatts_demo.c](https://github.com/espressif/esp-idf/blob/master/examples/bluetooth/gatt_server/main/gatts_demo.c) -------------------------------------------------------------------------------- /gatt_server_car/main/Kconfig: -------------------------------------------------------------------------------- 1 | menu "Example 'GATT SERVER' Config" 2 | 3 | config SET_RAW_ADV_DATA 4 | bool "Use raw data for advertising packets and scan response data" 5 | help 6 | If this config item is set, raw binary data will be used to generate advertising & scan response data. 7 | This option uses the esp_ble_gap_config_adv_data_raw() and esp_ble_gap_config_scan_rsp_data_raw() functions. 8 | 9 | If this config item is unset, advertising & scan response data is provided via a higher-level esp_ble_adv_data_t structure. 10 | The lower layer will generate the BLE packets. This option has higher overhead at runtime. 11 | 12 | endmenu 13 | -------------------------------------------------------------------------------- /gatt_server_car/main/MPU9250_asukiaaa.c: -------------------------------------------------------------------------------- 1 | #include "MPU9250_asukiaaa.h" 2 | 3 | void delay(unsigned long milli_seconds) { 4 | vTaskDelay(milli_seconds / portTICK_RATE_MS); 5 | } 6 | 7 | static esp_err_t i2c_master_write_slave(uint8_t address, uint8_t* data_wr, size_t size) { 8 | i2c_cmd_handle_t cmd = i2c_cmd_link_create(); 9 | i2c_master_start(cmd); 10 | i2c_master_write_byte(cmd, ( address << 1 ) | WRITE_BIT, ACK_CHECK_EN); 11 | i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN); 12 | i2c_master_stop(cmd); 13 | esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS); 14 | i2c_cmd_link_delete(cmd); 15 | return ret; 16 | } 17 | 18 | static esp_err_t i2c_master_read_slave(uint8_t address, uint8_t register_address, uint8_t* data_rd, size_t size) { 19 | if (size == 0) { 20 | return ESP_OK; 21 | } 22 | esp_err_t ret = i2c_master_write_slave(address, ®ister_address, 1); 23 | if (ret == ESP_FAIL) { 24 | return ret; 25 | } 26 | delay(30); 27 | 28 | i2c_cmd_handle_t cmd = i2c_cmd_link_create(); 29 | i2c_master_start(cmd); 30 | i2c_master_write_byte(cmd, ( address << 1 ) | READ_BIT, ACK_CHECK_EN); 31 | if (size > 1) { 32 | i2c_master_read(cmd, data_rd, size - 1, ACK_VAL); 33 | } 34 | i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL); 35 | i2c_master_stop(cmd); 36 | ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS); 37 | i2c_cmd_link_delete(cmd); 38 | return ret; 39 | } 40 | 41 | static void i2c_master_init(mpu9250_t *data) { 42 | int i2c_master_port = I2C_MASTER_NUM; 43 | i2c_config_t conf; 44 | conf.mode = I2C_MODE_MASTER; 45 | conf.sda_io_num = data->sdaPin; 46 | conf.sda_pullup_en = GPIO_PULLUP_ENABLE; 47 | conf.scl_io_num = data->sclPin; 48 | conf.scl_pullup_en = GPIO_PULLUP_ENABLE; 49 | conf.master.clk_speed = I2C_MASTER_FREQ_HZ; 50 | i2c_param_config(i2c_master_port, &conf); 51 | i2c_driver_install(i2c_master_port, conf.mode, 52 | I2C_MASTER_RX_BUF_DISABLE, 53 | I2C_MASTER_TX_BUF_DISABLE, 0); 54 | } 55 | 56 | void mpu9250_mag_set_mode(uint8_t mode) { 57 | static uint8_t buf[] = {AK8963_RA_CNTL1, 0x00}; 58 | buf[1] = mode; 59 | printf("set mode\n"); 60 | i2c_master_write_slave(MPU9250_MAG_ADDRESS, buf, 2); 61 | delay(10); 62 | } 63 | 64 | void mpu9250_mag_read_adjust_values(mpu9250_t *data) { 65 | mpu9250_mag_set_mode(AK8963_MODE_POWERDOWN); 66 | mpu9250_mag_set_mode(AK8963_MODE_FUSEROM); 67 | 68 | uint8_t buff[3]; 69 | i2c_master_read_slave(MPU9250_MAG_ADDRESS, AK8963_RA_ASAX, buff, 3); 70 | printf("adjust values: %03d, %03d, %03d\n", buff[0], buff[1], buff[2]); 71 | data->magXAdjust = buff[0]; 72 | data->magYAdjust = buff[1]; 73 | data->magZAdjust = buff[2]; 74 | } 75 | 76 | void mpu9250_mag_begin(mpu9250_t *data) { 77 | printf("begin magnetometor\n"); 78 | i2c_master_init(data); 79 | delay(10); 80 | 81 | // turn on magnetometor 82 | static uint8_t buf[] = {0x37, 0x02}; 83 | i2c_master_write_slave(data->address, buf, 2); 84 | delay(20); 85 | 86 | mpu9250_mag_read_adjust_values(data); 87 | mpu9250_mag_set_mode(AK8963_MODE_POWERDOWN); 88 | mpu9250_mag_set_mode(AK8963_MODE_CONTINUOUS_8HZ); 89 | } 90 | 91 | void mpu9250_mag_update(mpu9250_t *data) { 92 | i2c_master_read_slave(MPU9250_MAG_ADDRESS, AK8963_RA_HXL, data->magBuf, 7); 93 | } 94 | 95 | int16_t mpu9250_mag_get(mpu9250_t *data, uint8_t high_index, uint8_t low_index) { 96 | return (((int16_t)data->magBuf[high_index]) << 8) | data->magBuf[low_index]; 97 | } 98 | 99 | int16_t mag_adjust_value(int16_t value, uint8_t adjust) { 100 | return (int16_t) ((int32_t) value * (((((int16_t) adjust - 128) / 2) / 128) + 1)); 101 | } 102 | 103 | int16_t mpu9250_mag_x(mpu9250_t *data) { 104 | return mag_adjust_value(mpu9250_mag_get(data, 1, 0), data->magXAdjust) + data->magXOffset; 105 | } 106 | 107 | int16_t mpu9250_mag_y(mpu9250_t *data) { 108 | return mag_adjust_value(mpu9250_mag_get(data, 3, 2), data->magYAdjust) + data->magYOffset; 109 | } 110 | 111 | int16_t mpu9250_mag_z(mpu9250_t *data) { 112 | return mag_adjust_value(mpu9250_mag_get(data, 5, 4), data->magZAdjust) + data->magZOffset; 113 | } 114 | -------------------------------------------------------------------------------- /gatt_server_car/main/MPU9250_asukiaaa.h: -------------------------------------------------------------------------------- 1 | #ifndef _MPU9250_ASUKIAAA_H_ 2 | #define _MPU9250_ASUKIAAA_H_ 3 | #include 4 | #include "driver/i2c.h" 5 | 6 | #define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */ 7 | #define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ 8 | #define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */ 9 | #define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */ 10 | 11 | #define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */ 12 | #define READ_BIT I2C_MASTER_READ /*!< I2C master read */ 13 | #define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ 14 | #define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ 15 | #define ACK_VAL 0x0 /*!< I2C ack value */ 16 | #define NACK_VAL 0x1 /*!< I2C nack value */ 17 | 18 | #define MPU9250_ADDRESS_AD0_LOW 0x68 19 | #define MPU9250_ADDRESS_AD0_HIGH 0x69 20 | #define MPU9250_MAG_ADDRESS 0x0C 21 | 22 | #define GYRO_FULL_SCALE_250_DPS 0x00 23 | #define GYRO_FULL_SCALE_500_DPS 0x08 24 | #define GYRO_FULL_SCALE_1000_DPS 0x10 25 | #define GYRO_FULL_SCALE_2000_DPS 0x18 26 | 27 | #define ACC_FULL_SCALE_2_G 0x00 28 | #define ACC_FULL_SCALE_4_G 0x08 29 | #define ACC_FULL_SCALE_8_G 0x10 30 | #define ACC_FULL_SCALE_16_G 0x18 31 | 32 | #define AK8963_RA_HXL 0x03 33 | #define AK8963_RA_CNTL1 0x0A 34 | #define AK8963_RA_ASAX 0x10 35 | 36 | #define AK8963_MODE_POWERDOWN 0x0 37 | #define AK8963_MODE_SINGLE 0x1 38 | #define AK8963_MODE_CONTINUOUS_8HZ 0x2 39 | #define AK8963_MODE_EXTERNAL 0x4 40 | #define AK8963_MODE_CONTINUOUS_100HZ 0x6 41 | #define AK8963_MODE_SELFTEST 0x8 42 | #define AK8963_MODE_FUSEROM 0xF 43 | 44 | typedef struct { 45 | int16_t magXOffset, magYOffset, magZOffset; 46 | uint8_t address; 47 | uint8_t accelBuf[14]; 48 | uint8_t magBuf[7]; 49 | uint8_t magXAdjust, magYAdjust, magZAdjust; 50 | uint8_t sdaPin, sclPin; 51 | } mpu9250_t; 52 | 53 | void mpu9250_begin(mpu9250_t *data); 54 | void mpu9250_mag_begin(mpu9250_t *data); 55 | void mpu9250_mag_update(mpu9250_t *data); 56 | int16_t mpu9250_mag_x(mpu9250_t *data); 57 | int16_t mpu9250_mag_y(mpu9250_t *data); 58 | int16_t mpu9250_mag_z(mpu9250_t *data); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /gatt_server_car/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main Makefile. This is basically the same as a component makefile. 3 | # 4 | # This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, 5 | # this will take the sources in the src/ directory, compile them and link them into 6 | # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /gatt_server_car/main/gatt_server.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "freertos/FreeRTOS.h" 21 | #include "freertos/task.h" 22 | #include "freertos/event_groups.h" 23 | #include "driver/ledc.h" 24 | #include "esp_system.h" 25 | #include "esp_log.h" 26 | #include "nvs_flash.h" 27 | #include "bt.h" 28 | #include "bta_api.h" 29 | 30 | #include "esp_gap_ble_api.h" 31 | #include "esp_gatts_api.h" 32 | #include "esp_bt_defs.h" 33 | #include "esp_bt_main.h" 34 | #include "esp_bt_main.h" 35 | 36 | #include "sdkconfig.h" 37 | 38 | #include "MPU9250_asukiaaa.h" 39 | 40 | #define PI 3.14159265 41 | #define GATTS_TAG "GATTS_DEMO" 42 | 43 | // #define GPIO_OUTPUT_IO_0 5 44 | // #define GPIO_OUTPUT_IO_1 19 45 | // #define GPIO_OUTPUT_PIN_SEL ((1< MSB */ 125 | //first uuid, 16bit, [12],[13] is the value 126 | 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00, 127 | //second uuid, 32bit, [12], [13], [14], [15] is the value 128 | 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0xAB, 0xCD, 129 | }; 130 | 131 | //static uint8_t test_manufacturer[TEST_MANUFACTURER_DATA_LEN] = {0x12, 0x23, 0x45, 0x56}; 132 | static esp_ble_adv_data_t test_adv_data = { 133 | .set_scan_rsp = false, 134 | .include_name = true, 135 | .include_txpower = true, 136 | .min_interval = 0x20, 137 | .max_interval = 0x40, 138 | .appearance = 0x00, 139 | .manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN, 140 | .p_manufacturer_data = NULL, //&test_manufacturer[0], 141 | .service_data_len = 0, 142 | .p_service_data = NULL, 143 | .service_uuid_len = 32, 144 | .p_service_uuid = test_service_uuid128, 145 | .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), 146 | }; 147 | #endif /* CONFIG_SET_RAW_ADV_DATA */ 148 | 149 | static esp_ble_adv_params_t test_adv_params = { 150 | .adv_int_min = 0x20, 151 | .adv_int_max = 0x40, 152 | .adv_type = ADV_TYPE_IND, 153 | .own_addr_type = BLE_ADDR_TYPE_PUBLIC, 154 | //.peer_addr = 155 | //.peer_addr_type = 156 | .channel_map = ADV_CHNL_ALL, 157 | .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, 158 | }; 159 | 160 | #define PROFILE_NUM 2 161 | #define PROFILE_A_APP_ID 0 162 | #define PROFILE_B_APP_ID 1 163 | 164 | struct gatts_profile_inst { 165 | esp_gatts_cb_t gatts_cb; 166 | uint16_t gatts_if; 167 | uint16_t app_id; 168 | uint16_t conn_id; 169 | uint16_t service_handle; 170 | esp_gatt_srvc_id_t service_id; 171 | uint16_t char_handle; 172 | esp_bt_uuid_t char_uuid; 173 | esp_gatt_perm_t perm; 174 | esp_gatt_char_prop_t property; 175 | uint16_t descr_handle; 176 | esp_bt_uuid_t descr_uuid; 177 | }; 178 | 179 | /* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */ 180 | static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = { 181 | [PROFILE_A_APP_ID] = { 182 | .gatts_cb = gatts_profile_a_event_handler, 183 | .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ 184 | }, 185 | [PROFILE_B_APP_ID] = { 186 | .gatts_cb = gatts_profile_b_event_handler, /* This demo does not implement, similar as profile A */ 187 | .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ 188 | }, 189 | }; 190 | 191 | uint32_t get_millis() { 192 | return (uint32_t) (clock() * 1000 / CLOCKS_PER_SEC); 193 | } 194 | 195 | static void ble_indicate(int value) { 196 | if (gatts_if_for_indicate == ESP_GATT_IF_NONE) { 197 | printf("cannot indicate because gatts_if_for_indicate is NONE\n"); 198 | return; 199 | } 200 | printf("indicate %d to %d\n", value, gatts_if_for_indicate); 201 | uint16_t attr_handle = 0x002a; 202 | uint8_t value_len = 1; 203 | uint8_t value_arr[] = {value}; 204 | esp_ble_gatts_send_indicate(gatts_if_for_indicate, 0, attr_handle, value_len, value_arr, false); 205 | } 206 | 207 | static void gpio_task(void* arg) { 208 | uint8_t io_num; 209 | while (true) { 210 | if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { 211 | int io_level = gpio_get_level(io_num); 212 | printf("GPIO[%d] val: %d\n", io_num, io_level); 213 | ble_indicate(io_level); 214 | } 215 | } 216 | } 217 | 218 | typedef struct { 219 | int gpio_num; 220 | int channel; 221 | } pin_info_t; 222 | 223 | static void init_motors() { 224 | 225 | int ch; 226 | pin_info_t motor_pins_info[] = { 227 | { 228 | .gpio_num = MOTOR_LEFT_FORWARD_PIN, 229 | .channel = MOTOR_LEFT_FORWARD_CHANNEL, 230 | }, 231 | { 232 | .gpio_num = MOTOR_LEFT_BACK_PIN, 233 | .channel = MOTOR_LEFT_BACK_CHANNEL, 234 | }, 235 | { 236 | .gpio_num = MOTOR_RIGHT_FORWARD_PIN, 237 | .channel = MOTOR_RIGHT_FORWARD_CHANNEL, 238 | }, 239 | { 240 | .gpio_num = MOTOR_RIGHT_BACK_PIN, 241 | .channel = MOTOR_RIGHT_BACK_CHANNEL, 242 | } 243 | }; 244 | 245 | ledc_channel_config_t channel_config = { 246 | .speed_mode = MOTOR_PWM_SPEED_MODE, 247 | .intr_type = LEDC_INTR_DISABLE, 248 | .timer_sel = MOTOR_PWM_TIMER, 249 | .duty = 0, 250 | }; 251 | for (ch=0; ch<4; ch++) { 252 | channel_config.gpio_num = motor_pins_info[ch].gpio_num; 253 | channel_config.channel = motor_pins_info[ch].channel; 254 | ledc_channel_config(&channel_config); 255 | } 256 | 257 | ledc_timer_config_t motor_timer = { 258 | .speed_mode = MOTOR_PWM_SPEED_MODE, 259 | .bit_num = MOTOR_PWM_BIT_NUM, 260 | .timer_num = MOTOR_PWM_TIMER, 261 | .freq_hz = 25000, 262 | }; 263 | ledc_timer_config(&motor_timer); 264 | } 265 | 266 | static void init_switch() { 267 | gpio_config_t io_conf; 268 | //interrupt of rising edge 269 | io_conf.intr_type = GPIO_PIN_INTR_POSEDGE; 270 | //bit mask of the pins, use GPIO4/5 here 271 | io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; 272 | //set as input mode 273 | io_conf.mode = GPIO_MODE_INPUT; 274 | //enable pull-up mode 275 | io_conf.pull_up_en = 1; 276 | //disable pull-down mode 277 | io_conf.pull_down_en = 0; 278 | //configure 279 | gpio_config(&io_conf); 280 | 281 | //change gpio intrrupt type for one pin 282 | gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE); 283 | 284 | //create a queue to handle gpio event from isr 285 | gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); 286 | //start gpio task 287 | xTaskCreate(gpio_task, "gpio_task", 2048, NULL, 10, NULL); 288 | 289 | //install gpio isr service 290 | gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); 291 | //hook isr handler for specific gpio pin 292 | gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); 293 | } 294 | 295 | // static void init_led() { 296 | // gpio_config_t io_conf; 297 | // //disable interrupt 298 | // io_conf.intr_type = GPIO_PIN_INTR_DISABLE; 299 | // //set as output mode 300 | // io_conf.mode = GPIO_MODE_OUTPUT; 301 | // //bit mask of the pins that you want to set 302 | // io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; 303 | // //disable pull-down mode 304 | // io_conf.pull_down_en = 0; 305 | // //disable pull-up mode 306 | // io_conf.pull_up_en = 0; 307 | // //configure GPIO with the given settings 308 | // gpio_config(&io_conf); 309 | // 310 | // printf("led initlalized"); 311 | // } 312 | 313 | // static void switch_led(bool value) { 314 | // int out_value = 0; 315 | // if (value) { 316 | // out_value = 1; 317 | // } 318 | // printf("out value %d\n", out_value); 319 | // gpio_set_level(GPIO_OUTPUT_IO_0, out_value); 320 | // } 321 | 322 | static void set_and_update_duty(uint8_t channel, uint8_t value) { 323 | uint32_t value_for_duty; 324 | if (value == 0) { 325 | value_for_duty = 0; 326 | } else { 327 | value_for_duty = (((uint32_t) value + 1) * 4) - 1; // expand value for 10bit 328 | } 329 | // printf("c: %03d, v: %03d, d: %04d\n", channel, value, value_for_duty); 330 | ledc_set_duty(MOTOR_PWM_SPEED_MODE, channel, value_for_duty); 331 | ledc_update_duty(MOTOR_PWM_SPEED_MODE, channel); 332 | } 333 | 334 | static void set_speed_for_a_motor(uint8_t value,uint8_t forward_channel, uint8_t back_channel) { 335 | uint8_t back_value = 0; 336 | uint8_t forward_value = 0; 337 | if (value < 127) { 338 | back_value = (127 - value) * 2 + 1; 339 | } else if (value > 128) { 340 | forward_value = (value - 128) * 2 + 1; 341 | } 342 | // printf("set f: %d: b: %d;\n", forward_value, back_value); 343 | set_and_update_duty(forward_channel, forward_value); 344 | set_and_update_duty(back_channel, back_value); 345 | } 346 | 347 | static void set_speed(uint8_t left, uint8_t right) { 348 | // printf("got left: %d: right: %d;\n", left, right); 349 | set_speed_for_a_motor(left, 350 | MOTOR_LEFT_FORWARD_CHANNEL, 351 | MOTOR_LEFT_BACK_CHANNEL); 352 | set_speed_for_a_motor(right, 353 | MOTOR_RIGHT_FORWARD_CHANNEL, 354 | MOTOR_RIGHT_BACK_CHANNEL); 355 | if ((left == 127 || left == 128) && 356 | (right == 127 || right == 128)) { 357 | is_moving = false; 358 | } else { 359 | is_moving = true; 360 | last_moved_millis = get_millis(); 361 | // printf("set last_moved_milllis: %d\n", last_moved_millis); 362 | } 363 | } 364 | 365 | static float get_diff_direction(int8_t plus_direction, uint8_t minus_direction) { 366 | float target_directoin = (float)plus_direction - minus_direction; 367 | float diff_direction = car_direction - target_directoin; 368 | while (diff_direction > 180 || -180 > diff_direction) { 369 | if (diff_direction > 180) { 370 | diff_direction -= 180; 371 | } else if (diff_direction < -180) { 372 | diff_direction += 180; 373 | } 374 | } 375 | return diff_direction; 376 | } 377 | 378 | static void get_speed_for_diff_direction(float diff_direction, uint8_t* right, uint8_t* left) { 379 | // printf("diff direction: %f\n", diff_direction); 380 | float plus_direction = (diff_direction > 0) ? diff_direction : - diff_direction; 381 | uint8_t go_speed = 255; 382 | uint8_t stop_speed = 128; 383 | uint8_t right_speed = go_speed; 384 | uint8_t left_speed; 385 | if (plus_direction > 90) { 386 | left_speed = stop_speed; 387 | } else { 388 | left_speed = (((float)90 - plus_direction) / 90) * (go_speed - stop_speed) + stop_speed; 389 | } 390 | if (diff_direction > 0) { 391 | *right = right_speed; 392 | *left = left_speed; 393 | } else { 394 | *left = right_speed; 395 | *right = left_speed; 396 | } 397 | // printf("l: %03d r: %03d", *left, *right); 398 | } 399 | 400 | static void go_to_direction(int8_t plus_direction, uint8_t minus_direction) { 401 | uint8_t left, right; 402 | get_speed_for_diff_direction(get_diff_direction(plus_direction, minus_direction), 403 | &left, &right); 404 | set_speed(left, right); 405 | } 406 | 407 | static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) 408 | { 409 | switch (event) { 410 | case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: 411 | esp_ble_gap_start_advertising(&test_adv_params); 412 | break; 413 | case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: 414 | esp_ble_gap_start_advertising(&test_adv_params); 415 | break; 416 | case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: 417 | esp_ble_gap_start_advertising(&test_adv_params); 418 | break; 419 | case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: 420 | //advertising start complete event to indicate advertising start successfully or failed 421 | if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { 422 | ESP_LOGE(GATTS_TAG, "Advertising start failed\n"); 423 | } 424 | break; 425 | default: 426 | break; 427 | } 428 | } 429 | 430 | static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { 431 | switch (event) { 432 | case ESP_GATTS_REG_EVT: 433 | ESP_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); 434 | gl_profile_tab[PROFILE_A_APP_ID].service_id.is_primary = true; 435 | gl_profile_tab[PROFILE_A_APP_ID].service_id.id.inst_id = 0x00; 436 | gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; 437 | gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A; 438 | 439 | esp_ble_gap_set_device_name(TEST_DEVICE_NAME); 440 | #ifdef CONFIG_SET_RAW_ADV_DATA 441 | esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data)); 442 | esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data)); 443 | #else 444 | esp_ble_gap_config_adv_data(&test_adv_data); 445 | #endif 446 | esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_A); 447 | break; 448 | case ESP_GATTS_READ_EVT: { 449 | ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); 450 | esp_gatt_rsp_t rsp; 451 | memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); 452 | rsp.attr_value.handle = param->read.handle; 453 | rsp.attr_value.len = 4; 454 | rsp.attr_value.value[0] = 0xde; 455 | rsp.attr_value.value[1] = 0xed; 456 | rsp.attr_value.value[2] = 0xbe; 457 | rsp.attr_value.value[3] = 0xef; 458 | esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, 459 | ESP_GATT_OK, &rsp); 460 | break; 461 | } 462 | case ESP_GATTS_WRITE_EVT: { 463 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle); 464 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, value len %d, value %08x\n", param->write.len, *(uint32_t *)param->write.value); 465 | esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); 466 | if (param->write.value[0] == 'm') { 467 | set_speed(param->write.value[1], 468 | param->write.value[2]); 469 | } else if (param->write.value[0] == 'd') { 470 | if (param->write.value[3] != 0) { 471 | go_to_direction(param->write.value[1], 472 | param->write.value[2]); 473 | } 474 | } 475 | break; 476 | } 477 | case ESP_GATTS_EXEC_WRITE_EVT: 478 | case ESP_GATTS_MTU_EVT: 479 | case ESP_GATTS_UNREG_EVT: 480 | break; 481 | case ESP_GATTS_CREATE_EVT: 482 | ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle); 483 | gl_profile_tab[PROFILE_A_APP_ID].service_handle = param->create.service_handle; 484 | gl_profile_tab[PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16; 485 | gl_profile_tab[PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_A; 486 | 487 | esp_ble_gatts_start_service(gl_profile_tab[PROFILE_A_APP_ID].service_handle); 488 | 489 | esp_ble_gatts_add_char(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].char_uuid, 490 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 491 | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY, 492 | &gatts_demo_char1_val, NULL); 493 | break; 494 | case ESP_GATTS_ADD_INCL_SRVC_EVT: 495 | break; 496 | case ESP_GATTS_ADD_CHAR_EVT: { 497 | uint16_t length = 0; 498 | const uint8_t *prf_char; 499 | 500 | ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", 501 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 502 | gl_profile_tab[PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle; 503 | gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; 504 | gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; 505 | esp_ble_gatts_get_attr_value(param->add_char.attr_handle, &length, &prf_char); 506 | 507 | ESP_LOGI(GATTS_TAG, "the gatts demo char length = %x\n", length); 508 | for(int i = 0; i < length; i++){ 509 | ESP_LOGI(GATTS_TAG, "prf_char[%x] =%x\n",i,prf_char[i]); 510 | } 511 | esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].descr_uuid, 512 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL); 513 | break; 514 | } 515 | case ESP_GATTS_ADD_CHAR_DESCR_EVT: 516 | ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n", 517 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 518 | break; 519 | case ESP_GATTS_DELETE_EVT: 520 | break; 521 | case ESP_GATTS_START_EVT: 522 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n", 523 | param->start.status, param->start.service_handle); 524 | break; 525 | case ESP_GATTS_STOP_EVT: 526 | break; 527 | case ESP_GATTS_CONNECT_EVT: { 528 | esp_ble_conn_update_params_t conn_params = {0}; 529 | memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t)); 530 | /* For the IOS system, please reference the apple official documents about the ble connection parameters restrictions. */ 531 | conn_params.latency = 0; 532 | conn_params.max_int = 0x20; // max_int = 0x20*1.25ms = 40ms 533 | conn_params.min_int = 0x10; // min_int = 0x10*1.25ms = 20ms 534 | conn_params.timeout = 400; // timeout = 400*10ms = 4000ms 535 | ESP_LOGI(GATTS_TAG, "ESP_GATTS_CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:", 536 | param->connect.conn_id, 537 | param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], 538 | param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]); 539 | gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->connect.conn_id; 540 | //start sent the update connection parameters to the peer device. 541 | esp_ble_gap_update_conn_params(&conn_params); 542 | } 543 | break; 544 | case ESP_GATTS_DISCONNECT_EVT: 545 | esp_ble_gap_start_advertising(&test_adv_params); 546 | break; 547 | case ESP_GATTS_CONF_EVT: 548 | ESP_LOGI(GATTS_TAG, "ESP_GATTS_CONF_EVT, status %d", param->conf.status); 549 | if (param->conf.status != ESP_GATT_OK){ 550 | esp_log_buffer_hex(GATTS_TAG, param->conf.value, param->conf.len); 551 | } 552 | break; 553 | case ESP_GATTS_OPEN_EVT: 554 | case ESP_GATTS_CANCEL_OPEN_EVT: 555 | case ESP_GATTS_CLOSE_EVT: 556 | case ESP_GATTS_LISTEN_EVT: 557 | case ESP_GATTS_CONGEST_EVT: 558 | default: 559 | break; 560 | } 561 | } 562 | 563 | static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { 564 | switch (event) { 565 | case ESP_GATTS_REG_EVT: 566 | ESP_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); 567 | gl_profile_tab[PROFILE_B_APP_ID].service_id.is_primary = true; 568 | gl_profile_tab[PROFILE_B_APP_ID].service_id.id.inst_id = 0x00; 569 | gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; 570 | gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_B; 571 | 572 | esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_B_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_B); 573 | break; 574 | case ESP_GATTS_READ_EVT: { 575 | ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); 576 | esp_gatt_rsp_t rsp; 577 | memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); 578 | rsp.attr_value.handle = param->read.handle; 579 | rsp.attr_value.len = 4; 580 | rsp.attr_value.value[0] = 0xde; 581 | rsp.attr_value.value[1] = 0xed; 582 | rsp.attr_value.value[2] = 0xbe; 583 | rsp.attr_value.value[3] = 0xef; 584 | esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, 585 | ESP_GATT_OK, &rsp); 586 | break; 587 | } 588 | case ESP_GATTS_WRITE_EVT: { 589 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle); 590 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, value len %d, value %08x\n", param->write.len, *(uint32_t *)param->write.value); 591 | esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); 592 | break; 593 | } 594 | case ESP_GATTS_EXEC_WRITE_EVT: 595 | case ESP_GATTS_MTU_EVT: 596 | case ESP_GATTS_UNREG_EVT: 597 | break; 598 | case ESP_GATTS_CREATE_EVT: 599 | ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle); 600 | gl_profile_tab[PROFILE_B_APP_ID].service_handle = param->create.service_handle; 601 | gl_profile_tab[PROFILE_B_APP_ID].char_uuid.len = ESP_UUID_LEN_16; 602 | gl_profile_tab[PROFILE_B_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_B; 603 | 604 | esp_ble_gatts_start_service(gl_profile_tab[PROFILE_B_APP_ID].service_handle); 605 | 606 | esp_ble_gatts_add_char(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].char_uuid, 607 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 608 | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY, 609 | NULL, NULL); 610 | break; 611 | case ESP_GATTS_ADD_INCL_SRVC_EVT: 612 | break; 613 | case ESP_GATTS_ADD_CHAR_EVT: 614 | ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", 615 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 616 | 617 | gl_profile_tab[PROFILE_B_APP_ID].char_handle = param->add_char.attr_handle; 618 | gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; 619 | gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; 620 | esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].descr_uuid, 621 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 622 | NULL, NULL); 623 | break; 624 | case ESP_GATTS_ADD_CHAR_DESCR_EVT: 625 | ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n", 626 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 627 | break; 628 | case ESP_GATTS_DELETE_EVT: 629 | break; 630 | case ESP_GATTS_START_EVT: 631 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n", 632 | param->start.status, param->start.service_handle); 633 | break; 634 | case ESP_GATTS_STOP_EVT: 635 | break; 636 | case ESP_GATTS_CONNECT_EVT: 637 | ESP_LOGI(GATTS_TAG, "CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:", 638 | param->connect.conn_id, 639 | param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], 640 | param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5]); 641 | gl_profile_tab[PROFILE_B_APP_ID].conn_id = param->connect.conn_id; 642 | break; 643 | case ESP_GATTS_CONF_EVT: 644 | ESP_LOGI(GATTS_TAG, "ESP_GATTS_CONF_EVT status %d", param->conf.status); 645 | if (param->conf.status != ESP_GATT_OK){ 646 | esp_log_buffer_hex(GATTS_TAG, param->conf.value, param->conf.len); 647 | } 648 | case ESP_GATTS_DISCONNECT_EVT: 649 | case ESP_GATTS_OPEN_EVT: 650 | case ESP_GATTS_CANCEL_OPEN_EVT: 651 | case ESP_GATTS_CLOSE_EVT: 652 | case ESP_GATTS_LISTEN_EVT: 653 | case ESP_GATTS_CONGEST_EVT: 654 | default: 655 | break; 656 | } 657 | } 658 | 659 | static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) 660 | { 661 | /* If event is register event, store the gatts_if for each profile */ 662 | if (event == ESP_GATTS_REG_EVT) { 663 | if (param->reg.status == ESP_GATT_OK) { 664 | gl_profile_tab[param->reg.app_id].gatts_if = gatts_if; 665 | } else { 666 | ESP_LOGI(GATTS_TAG, "Reg app failed, app_id %04x, status %d\n", 667 | param->reg.app_id, 668 | param->reg.status); 669 | return; 670 | } 671 | } 672 | 673 | /* If the gatts_if equal to profile A, call profile A cb handler, 674 | * so here call each profile's callback */ 675 | do { 676 | int idx; 677 | for (idx = 0; idx < PROFILE_NUM; idx++) { 678 | if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ 679 | gatts_if == gl_profile_tab[idx].gatts_if) { 680 | if (gl_profile_tab[idx].gatts_cb) { 681 | gl_profile_tab[idx].gatts_cb(event, gatts_if, param); 682 | } 683 | } 684 | } 685 | } while (0); 686 | } 687 | 688 | void app_main() 689 | { 690 | esp_err_t ret; 691 | esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); 692 | 693 | esp_bt_controller_init(&bt_cfg); 694 | 695 | ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM); 696 | if (ret) { 697 | ESP_LOGE(GATTS_TAG, "%s enable controller failed\n", __func__); 698 | return; 699 | } 700 | ret = esp_bluedroid_init(); 701 | if (ret) { 702 | ESP_LOGE(GATTS_TAG, "%s init bluetooth failed\n", __func__); 703 | return; 704 | } 705 | ret = esp_bluedroid_enable(); 706 | if (ret) { 707 | ESP_LOGE(GATTS_TAG, "%s enable bluetooth failed\n", __func__); 708 | return; 709 | } 710 | 711 | esp_ble_gatts_register_callback(gatts_event_handler); 712 | esp_ble_gap_register_callback(gap_event_handler); 713 | esp_ble_gatts_app_register(PROFILE_A_APP_ID); 714 | esp_ble_gatts_app_register(PROFILE_B_APP_ID); 715 | 716 | //init_led(); 717 | init_switch(); 718 | init_motors(); 719 | vTaskDelay(1000 / portTICK_RATE_MS); 720 | mpu9250_mag_begin(&mpu9250_data); 721 | 722 | uint32_t current_millis; 723 | uint8_t stop_speed = 128; 724 | while (1) { 725 | vTaskDelay(200 / portTICK_RATE_MS); 726 | mpu9250_mag_update(&mpu9250_data); 727 | // printf("magValues: %03d %03d %03d\n", 728 | // mpu9250_mag_x(&mpu9250_data), 729 | // mpu9250_mag_y(&mpu9250_data), 730 | // mpu9250_mag_z(&mpu9250_data)); 731 | car_direction = atan2((float) mpu9250_mag_x(&mpu9250_data),(float) mpu9250_mag_y(&mpu9250_data)) * 180 / PI; 732 | // printf("direction: %f\n", car_direction); 733 | current_millis = get_millis(); 734 | // go_to_direction(90,0); 735 | if (is_moving && current_millis - last_moved_millis > 1000) { 736 | set_speed(stop_speed, stop_speed); 737 | } 738 | } 739 | return; 740 | } 741 | -------------------------------------------------------------------------------- /gatt_server_car/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # Override some defaults so BT stack is enabled 2 | # and WiFi disabled by default in this example 3 | CONFIG_BT_ENABLED=y 4 | CONFIG_WIFI_ENABLED=n 5 | -------------------------------------------------------------------------------- /gatt_server_gpio_notif/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := gatt_server_demos 7 | 8 | COMPONENT_ADD_INCLUDEDIRS := components/include 9 | 10 | include $(IDF_PATH)/make/project.mk 11 | -------------------------------------------------------------------------------- /gatt_server_gpio_notif/README.md: -------------------------------------------------------------------------------- 1 | # gatt_server_gpio_notif 2 | A sample program for ESP32 on esp-idf. This program do the following behaviors. 3 | - Send notification by push or release GPIO0 switch 4 | - Turn on or off LED that connected to GPIO5 by writing 0 or 1 over GATT. 5 | 6 | # Partner program 7 | The following nodejs program can listen notice from and write data for this project. 8 | 9 | [esp32-nodejs-samples/wirite-and-listen.js](https://github.com/asukiaaa/esp32-nodejs-samples/blob/master/wirite-and-listen.js) 10 | 11 | # License 12 | Appache v2 13 | 14 | # References 15 | - [esp-idf/examples/bluetooth/gatt_server](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/gatt_server) 16 | - [esp-idf/examples/peripherals/gpio/](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/gpio) 17 | - [GATT SERVER API: esp_ble_gatts_send_indicate](http://esp-idf.readthedocs.io/en/latest/api/bluetooth/esp_gatts.html#_CPPv227esp_ble_gatts_send_indicate13esp_gatt_if_t8uint16_t8uint16_t8uint16_tP7uint8_tb) 18 | -------------------------------------------------------------------------------- /gatt_server_gpio_notif/main/Kconfig: -------------------------------------------------------------------------------- 1 | menu "Example 'GATT SERVER' Config" 2 | 3 | config SET_RAW_ADV_DATA 4 | bool "Use raw data for advertising packets and scan response data" 5 | help 6 | If this config item is set, raw binary data will be used to generate advertising & scan response data. 7 | This option uses the esp_ble_gap_config_adv_data_raw() and esp_ble_gap_config_scan_rsp_data_raw() functions. 8 | 9 | If this config item is unset, advertising & scan response data is provided via a higher-level esp_ble_adv_data_t structure. 10 | The lower layer will generate the BLE packets. This option has higher overhead at runtime. 11 | 12 | endmenu 13 | -------------------------------------------------------------------------------- /gatt_server_gpio_notif/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main Makefile. This is basically the same as a component makefile. 3 | # 4 | # This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, 5 | # this will take the sources in the src/ directory, compile them and link them into 6 | # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /gatt_server_gpio_notif/main/gatt_server_gpio_notif.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include "freertos/FreeRTOS.h" 19 | #include "freertos/task.h" 20 | #include "freertos/event_groups.h" 21 | #include "esp_system.h" 22 | #include "esp_log.h" 23 | #include "nvs_flash.h" 24 | #include "bt.h" 25 | #include "bta_api.h" 26 | 27 | #include "esp_gap_ble_api.h" 28 | #include "esp_gatts_api.h" 29 | #include "esp_bt_defs.h" 30 | #include "esp_bt_main.h" 31 | #include "esp_bt_main.h" 32 | 33 | #include "sdkconfig.h" 34 | 35 | #define GATTS_TAG "GATTS_DEMO" 36 | 37 | #define GPIO_OUTPUT_IO_0 5 38 | #define GPIO_OUTPUT_IO_1 19 39 | #define GPIO_OUTPUT_PIN_SEL ((1< MSB */ 94 | //first uuid, 16bit, [12],[13] is the value 95 | 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00, 96 | //second uuid, 32bit, [12], [13], [14], [15] is the value 97 | 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0xAB, 0xCD, 98 | }; 99 | 100 | //static uint8_t test_manufacturer[TEST_MANUFACTURER_DATA_LEN] = {0x12, 0x23, 0x45, 0x56}; 101 | static esp_ble_adv_data_t test_adv_data = { 102 | .set_scan_rsp = false, 103 | .include_name = true, 104 | .include_txpower = true, 105 | .min_interval = 0x20, 106 | .max_interval = 0x40, 107 | .appearance = 0x00, 108 | .manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN, 109 | .p_manufacturer_data = NULL, //&test_manufacturer[0], 110 | .service_data_len = 0, 111 | .p_service_data = NULL, 112 | .service_uuid_len = 32, 113 | .p_service_uuid = test_service_uuid128, 114 | .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), 115 | }; 116 | #endif /* CONFIG_SET_RAW_ADV_DATA */ 117 | 118 | static esp_ble_adv_params_t test_adv_params = { 119 | .adv_int_min = 0x20, 120 | .adv_int_max = 0x40, 121 | .adv_type = ADV_TYPE_IND, 122 | .own_addr_type = BLE_ADDR_TYPE_PUBLIC, 123 | //.peer_addr = 124 | //.peer_addr_type = 125 | .channel_map = ADV_CHNL_ALL, 126 | .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, 127 | }; 128 | 129 | #define PROFILE_NUM 2 130 | #define PROFILE_A_APP_ID 0 131 | #define PROFILE_B_APP_ID 1 132 | 133 | struct gatts_profile_inst { 134 | esp_gatts_cb_t gatts_cb; 135 | uint16_t gatts_if; 136 | uint16_t app_id; 137 | uint16_t conn_id; 138 | uint16_t service_handle; 139 | esp_gatt_srvc_id_t service_id; 140 | uint16_t char_handle; 141 | esp_bt_uuid_t char_uuid; 142 | esp_gatt_perm_t perm; 143 | esp_gatt_char_prop_t property; 144 | uint16_t descr_handle; 145 | esp_bt_uuid_t descr_uuid; 146 | }; 147 | 148 | /* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */ 149 | static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = { 150 | [PROFILE_A_APP_ID] = { 151 | .gatts_cb = gatts_profile_a_event_handler, 152 | .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ 153 | }, 154 | [PROFILE_B_APP_ID] = { 155 | .gatts_cb = gatts_profile_b_event_handler, /* This demo does not implement, similar as profile A */ 156 | .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ 157 | }, 158 | }; 159 | 160 | static void ble_indicate(int value) { 161 | if (gatts_if_for_indicate == ESP_GATT_IF_NONE) { 162 | printf("cannot indicate because gatts_if_for_indicate is NONE\n"); 163 | return; 164 | } 165 | printf("indicate %d to %d\n", value, gatts_if_for_indicate); 166 | uint16_t attr_handle = 0x002a; 167 | uint8_t value_len = 1; 168 | uint8_t value_arr[] = {value}; 169 | esp_ble_gatts_send_indicate(gatts_if_for_indicate, 0, attr_handle, value_len, value_arr, false); 170 | } 171 | 172 | static void gpio_task(void* arg) { 173 | uint8_t io_num; 174 | while (true) { 175 | if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { 176 | int io_level = gpio_get_level(io_num); 177 | printf("GPIO[%d] val: %d\n", io_num, io_level); 178 | ble_indicate(io_level); 179 | } 180 | } 181 | } 182 | 183 | static void init_switch() { 184 | gpio_config_t io_conf; 185 | //interrupt of rising edge 186 | io_conf.intr_type = GPIO_PIN_INTR_POSEDGE; 187 | //bit mask of the pins, use GPIO4/5 here 188 | io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; 189 | //set as input mode 190 | io_conf.mode = GPIO_MODE_INPUT; 191 | //enable pull-up mode 192 | io_conf.pull_up_en = 1; 193 | //disable pull-down mode 194 | io_conf.pull_down_en = 0; 195 | //configure 196 | gpio_config(&io_conf); 197 | 198 | //change gpio intrrupt type for one pin 199 | gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE); 200 | 201 | //create a queue to handle gpio event from isr 202 | gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); 203 | //start gpio task 204 | xTaskCreate(gpio_task, "gpio_task", 2048, NULL, 10, NULL); 205 | 206 | //install gpio isr service 207 | gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); 208 | //hook isr handler for specific gpio pin 209 | gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); 210 | } 211 | 212 | static void init_led() { 213 | gpio_config_t io_conf; 214 | //disable interrupt 215 | io_conf.intr_type = GPIO_PIN_INTR_DISABLE; 216 | //set as output mode 217 | io_conf.mode = GPIO_MODE_OUTPUT; 218 | //bit mask of the pins that you want to set 219 | io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; 220 | //disable pull-down mode 221 | io_conf.pull_down_en = 0; 222 | //disable pull-up mode 223 | io_conf.pull_up_en = 0; 224 | //configure GPIO with the given settings 225 | gpio_config(&io_conf); 226 | 227 | printf("led initlalized"); 228 | } 229 | 230 | static void switch_led(bool value) { 231 | int out_value = 0; 232 | if (value) { 233 | out_value = 1; 234 | } 235 | printf("out value %d\n", out_value); 236 | gpio_set_level(GPIO_OUTPUT_IO_0, out_value); 237 | } 238 | 239 | static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) 240 | { 241 | switch (event) { 242 | case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: 243 | esp_ble_gap_start_advertising(&test_adv_params); 244 | break; 245 | case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: 246 | esp_ble_gap_start_advertising(&test_adv_params); 247 | break; 248 | case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: 249 | esp_ble_gap_start_advertising(&test_adv_params); 250 | break; 251 | case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: 252 | //advertising start complete event to indicate advertising start successfully or failed 253 | if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { 254 | ESP_LOGE(GATTS_TAG, "Advertising start failed\n"); 255 | } 256 | break; 257 | default: 258 | break; 259 | } 260 | } 261 | 262 | static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { 263 | switch (event) { 264 | case ESP_GATTS_REG_EVT: 265 | ESP_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); 266 | gl_profile_tab[PROFILE_A_APP_ID].service_id.is_primary = true; 267 | gl_profile_tab[PROFILE_A_APP_ID].service_id.id.inst_id = 0x00; 268 | gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; 269 | gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A; 270 | 271 | esp_ble_gap_set_device_name(TEST_DEVICE_NAME); 272 | #ifdef CONFIG_SET_RAW_ADV_DATA 273 | esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data)); 274 | esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data)); 275 | #else 276 | esp_ble_gap_config_adv_data(&test_adv_data); 277 | #endif 278 | esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_A); 279 | break; 280 | case ESP_GATTS_READ_EVT: { 281 | ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); 282 | esp_gatt_rsp_t rsp; 283 | memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); 284 | rsp.attr_value.handle = param->read.handle; 285 | rsp.attr_value.len = 4; 286 | rsp.attr_value.value[0] = 0xde; 287 | rsp.attr_value.value[1] = 0xed; 288 | rsp.attr_value.value[2] = 0xbe; 289 | rsp.attr_value.value[3] = 0xef; 290 | esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, 291 | ESP_GATT_OK, &rsp); 292 | break; 293 | } 294 | case ESP_GATTS_WRITE_EVT: { 295 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle); 296 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, value len %d, value %08x\n", param->write.len, *(uint32_t *)param->write.value); 297 | esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); 298 | 299 | if (0 == param->write.value[0]) { 300 | switch_led(false); 301 | } else { 302 | switch_led(true); 303 | } 304 | break; 305 | } 306 | case ESP_GATTS_EXEC_WRITE_EVT: 307 | case ESP_GATTS_MTU_EVT: 308 | case ESP_GATTS_CONF_EVT: 309 | case ESP_GATTS_UNREG_EVT: 310 | break; 311 | case ESP_GATTS_CREATE_EVT: 312 | ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle); 313 | gl_profile_tab[PROFILE_A_APP_ID].service_handle = param->create.service_handle; 314 | gl_profile_tab[PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16; 315 | gl_profile_tab[PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_A; 316 | 317 | esp_ble_gatts_start_service(gl_profile_tab[PROFILE_A_APP_ID].service_handle); 318 | 319 | esp_ble_gatts_add_char(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].char_uuid, 320 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 321 | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY, 322 | &gatts_demo_char1_val, NULL); 323 | break; 324 | case ESP_GATTS_ADD_INCL_SRVC_EVT: 325 | break; 326 | case ESP_GATTS_ADD_CHAR_EVT: { 327 | uint16_t length = 0; 328 | const uint8_t *prf_char; 329 | 330 | ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", 331 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 332 | gl_profile_tab[PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle; 333 | gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; 334 | gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; 335 | esp_ble_gatts_get_attr_value(param->add_char.attr_handle, &length, &prf_char); 336 | 337 | ESP_LOGI(GATTS_TAG, "the gatts demo char length = %x\n", length); 338 | for(int i = 0; i < length; i++){ 339 | ESP_LOGI(GATTS_TAG, "prf_char[%x] =%x\n",i,prf_char[i]); 340 | } 341 | esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].descr_uuid, 342 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL); 343 | break; 344 | } 345 | case ESP_GATTS_ADD_CHAR_DESCR_EVT: 346 | ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n", 347 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 348 | break; 349 | case ESP_GATTS_DELETE_EVT: 350 | break; 351 | case ESP_GATTS_START_EVT: 352 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n", 353 | param->start.status, param->start.service_handle); 354 | break; 355 | case ESP_GATTS_STOP_EVT: 356 | break; 357 | case ESP_GATTS_CONNECT_EVT: 358 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:, is_conn %d\n", 359 | param->connect.conn_id, 360 | param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], 361 | param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5], 362 | param->connect.is_connected); 363 | gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->connect.conn_id; 364 | 365 | gatts_if_for_indicate = gatts_if; 366 | printf("set gatts_if_for_indicate %d\n", gatts_if); 367 | break; 368 | case ESP_GATTS_DISCONNECT_EVT: 369 | esp_ble_gap_start_advertising(&test_adv_params); 370 | break; 371 | case ESP_GATTS_OPEN_EVT: 372 | case ESP_GATTS_CANCEL_OPEN_EVT: 373 | case ESP_GATTS_CLOSE_EVT: 374 | case ESP_GATTS_LISTEN_EVT: 375 | case ESP_GATTS_CONGEST_EVT: 376 | default: 377 | break; 378 | } 379 | } 380 | 381 | static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { 382 | switch (event) { 383 | case ESP_GATTS_REG_EVT: 384 | ESP_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); 385 | gl_profile_tab[PROFILE_B_APP_ID].service_id.is_primary = true; 386 | gl_profile_tab[PROFILE_B_APP_ID].service_id.id.inst_id = 0x00; 387 | gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; 388 | gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_B; 389 | 390 | esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_B_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_B); 391 | break; 392 | case ESP_GATTS_READ_EVT: { 393 | ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); 394 | esp_gatt_rsp_t rsp; 395 | memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); 396 | rsp.attr_value.handle = param->read.handle; 397 | rsp.attr_value.len = 4; 398 | rsp.attr_value.value[0] = 0xde; 399 | rsp.attr_value.value[1] = 0xed; 400 | rsp.attr_value.value[2] = 0xbe; 401 | rsp.attr_value.value[3] = 0xef; 402 | esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, 403 | ESP_GATT_OK, &rsp); 404 | break; 405 | } 406 | case ESP_GATTS_WRITE_EVT: { 407 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle); 408 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, value len %d, value %08x\n", param->write.len, *(uint32_t *)param->write.value); 409 | esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); 410 | break; 411 | } 412 | case ESP_GATTS_EXEC_WRITE_EVT: 413 | case ESP_GATTS_MTU_EVT: 414 | case ESP_GATTS_CONF_EVT: 415 | case ESP_GATTS_UNREG_EVT: 416 | break; 417 | case ESP_GATTS_CREATE_EVT: 418 | ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle); 419 | gl_profile_tab[PROFILE_B_APP_ID].service_handle = param->create.service_handle; 420 | gl_profile_tab[PROFILE_B_APP_ID].char_uuid.len = ESP_UUID_LEN_16; 421 | gl_profile_tab[PROFILE_B_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_B; 422 | 423 | esp_ble_gatts_start_service(gl_profile_tab[PROFILE_B_APP_ID].service_handle); 424 | 425 | esp_ble_gatts_add_char(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].char_uuid, 426 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 427 | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY, 428 | NULL, NULL); 429 | break; 430 | case ESP_GATTS_ADD_INCL_SRVC_EVT: 431 | break; 432 | case ESP_GATTS_ADD_CHAR_EVT: 433 | ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", 434 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 435 | 436 | gl_profile_tab[PROFILE_B_APP_ID].char_handle = param->add_char.attr_handle; 437 | gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; 438 | gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; 439 | esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].descr_uuid, 440 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 441 | NULL, NULL); 442 | break; 443 | case ESP_GATTS_ADD_CHAR_DESCR_EVT: 444 | ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n", 445 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 446 | break; 447 | case ESP_GATTS_DELETE_EVT: 448 | break; 449 | case ESP_GATTS_START_EVT: 450 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n", 451 | param->start.status, param->start.service_handle); 452 | break; 453 | case ESP_GATTS_STOP_EVT: 454 | break; 455 | case ESP_GATTS_CONNECT_EVT: 456 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:, is_conn %d\n", 457 | param->connect.conn_id, 458 | param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], 459 | param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5], 460 | param->connect.is_connected); 461 | gl_profile_tab[PROFILE_B_APP_ID].conn_id = param->connect.conn_id; 462 | break; 463 | case ESP_GATTS_DISCONNECT_EVT: 464 | case ESP_GATTS_OPEN_EVT: 465 | case ESP_GATTS_CANCEL_OPEN_EVT: 466 | case ESP_GATTS_CLOSE_EVT: 467 | case ESP_GATTS_LISTEN_EVT: 468 | case ESP_GATTS_CONGEST_EVT: 469 | default: 470 | break; 471 | } 472 | } 473 | 474 | static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) 475 | { 476 | /* If event is register event, store the gatts_if for each profile */ 477 | if (event == ESP_GATTS_REG_EVT) { 478 | if (param->reg.status == ESP_GATT_OK) { 479 | gl_profile_tab[param->reg.app_id].gatts_if = gatts_if; 480 | } else { 481 | ESP_LOGI(GATTS_TAG, "Reg app failed, app_id %04x, status %d\n", 482 | param->reg.app_id, 483 | param->reg.status); 484 | return; 485 | } 486 | } 487 | 488 | /* If the gatts_if equal to profile A, call profile A cb handler, 489 | * so here call each profile's callback */ 490 | do { 491 | int idx; 492 | for (idx = 0; idx < PROFILE_NUM; idx++) { 493 | if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ 494 | gatts_if == gl_profile_tab[idx].gatts_if) { 495 | if (gl_profile_tab[idx].gatts_cb) { 496 | gl_profile_tab[idx].gatts_cb(event, gatts_if, param); 497 | } 498 | } 499 | } 500 | } while (0); 501 | } 502 | 503 | void app_main() 504 | { 505 | esp_err_t ret; 506 | esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); 507 | 508 | esp_bt_controller_init(&bt_cfg); 509 | 510 | ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM); 511 | if (ret) { 512 | ESP_LOGE(GATTS_TAG, "%s enable controller failed\n", __func__); 513 | return; 514 | } 515 | ret = esp_bluedroid_init(); 516 | if (ret) { 517 | ESP_LOGE(GATTS_TAG, "%s init bluetooth failed\n", __func__); 518 | return; 519 | } 520 | ret = esp_bluedroid_enable(); 521 | if (ret) { 522 | ESP_LOGE(GATTS_TAG, "%s enable bluetooth failed\n", __func__); 523 | return; 524 | } 525 | 526 | esp_ble_gatts_register_callback(gatts_event_handler); 527 | esp_ble_gap_register_callback(gap_event_handler); 528 | esp_ble_gatts_app_register(PROFILE_A_APP_ID); 529 | esp_ble_gatts_app_register(PROFILE_B_APP_ID); 530 | 531 | init_led(); 532 | init_switch(); 533 | 534 | return; 535 | } 536 | -------------------------------------------------------------------------------- /gatt_server_gpio_notif/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # Override some defaults so BT stack is enabled 2 | # and WiFi disabled by default in this example 3 | CONFIG_BT_ENABLED=y 4 | CONFIG_WIFI_ENABLED=n 5 | -------------------------------------------------------------------------------- /gatt_server_notif_switch/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := gatt_server_demos 7 | 8 | COMPONENT_ADD_INCLUDEDIRS := components/include 9 | 10 | include $(IDF_PATH)/make/project.mk 11 | -------------------------------------------------------------------------------- /gatt_server_notif_switch/README.md: -------------------------------------------------------------------------------- 1 | # gatt_server_notif_switch 2 | A sample program for ESP32 on esp-idf. This program send notification by push or release GPIO0 switch. 3 | 4 | # Partner program 5 | The following nodejs program can listen notice from this project. 6 | 7 | - [esp32-nodejs-samples/listen-notification.js](https://github.com/asukiaaa/esp32-nodejs-samples/blob/master/listen-notification.js) 8 | - [gatt_client_listen_notif_then_output_to_led](../gatt_client_listen_notif_then_output_to_led) 9 | 10 | # License 11 | Appache v2 12 | 13 | # References 14 | - [esp-idf/examples/bluetooth/gatt_server](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/gatt_server) 15 | - [esp-idf/examples/peripherals/gpio/](https://github.com/espressif/esp-idf/tree/master/examples/peripherals/gpio) 16 | - [GATT SERVER API: esp_ble_gatts_send_indicate](http://esp-idf.readthedocs.io/en/latest/api/bluetooth/esp_gatts.html#_CPPv227esp_ble_gatts_send_indicate13esp_gatt_if_t8uint16_t8uint16_t8uint16_tP7uint8_tb) 17 | - [ESP32からBLE GATTのnotifを発信し、nodejs(noble)で受信する方法](http://asukiaaa.blogspot.com/2017/04/esp32ble-gattnodejsnoble.html) -------------------------------------------------------------------------------- /gatt_server_notif_switch/main/Kconfig: -------------------------------------------------------------------------------- 1 | menu "Example 'GATT SERVER' Config" 2 | 3 | config SET_RAW_ADV_DATA 4 | bool "Use raw data for advertising packets and scan response data" 5 | help 6 | If this config item is set, raw binary data will be used to generate advertising & scan response data. 7 | This option uses the esp_ble_gap_config_adv_data_raw() and esp_ble_gap_config_scan_rsp_data_raw() functions. 8 | 9 | If this config item is unset, advertising & scan response data is provided via a higher-level esp_ble_adv_data_t structure. 10 | The lower layer will generate the BLE packets. This option has higher overhead at runtime. 11 | 12 | endmenu 13 | -------------------------------------------------------------------------------- /gatt_server_notif_switch/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main Makefile. This is basically the same as a component makefile. 3 | # 4 | # This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, 5 | # this will take the sources in the src/ directory, compile them and link them into 6 | # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /gatt_server_notif_switch/main/gatt_server_notif_switch.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include "freertos/FreeRTOS.h" 19 | #include "freertos/task.h" 20 | #include "freertos/event_groups.h" 21 | #include "esp_system.h" 22 | #include "esp_log.h" 23 | #include "nvs_flash.h" 24 | #include "bt.h" 25 | #include "bta_api.h" 26 | 27 | #include "esp_gap_ble_api.h" 28 | #include "esp_gatts_api.h" 29 | #include "esp_bt_defs.h" 30 | #include "esp_bt_main.h" 31 | #include "esp_bt_main.h" 32 | 33 | #include "sdkconfig.h" 34 | 35 | #define GATTS_TAG "GATTS_DEMO" 36 | 37 | #define GPIO_INPUT_IO_0 0 38 | #define GPIO_INPUT_IO_1 18 39 | #define GPIO_INPUT_PIN_SEL ((1< MSB */ 90 | //first uuid, 16bit, [12],[13] is the value 91 | 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00, 92 | //second uuid, 32bit, [12], [13], [14], [15] is the value 93 | 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0xAB, 0xCD, 94 | }; 95 | 96 | //static uint8_t test_manufacturer[TEST_MANUFACTURER_DATA_LEN] = {0x12, 0x23, 0x45, 0x56}; 97 | static esp_ble_adv_data_t test_adv_data = { 98 | .set_scan_rsp = false, 99 | .include_name = true, 100 | .include_txpower = true, 101 | .min_interval = 0x20, 102 | .max_interval = 0x40, 103 | .appearance = 0x00, 104 | .manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN, 105 | .p_manufacturer_data = NULL, //&test_manufacturer[0], 106 | .service_data_len = 0, 107 | .p_service_data = NULL, 108 | .service_uuid_len = 32, 109 | .p_service_uuid = test_service_uuid128, 110 | .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), 111 | }; 112 | #endif /* CONFIG_SET_RAW_ADV_DATA */ 113 | 114 | static esp_ble_adv_params_t test_adv_params = { 115 | .adv_int_min = 0x20, 116 | .adv_int_max = 0x40, 117 | .adv_type = ADV_TYPE_IND, 118 | .own_addr_type = BLE_ADDR_TYPE_PUBLIC, 119 | //.peer_addr = 120 | //.peer_addr_type = 121 | .channel_map = ADV_CHNL_ALL, 122 | .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, 123 | }; 124 | 125 | #define PROFILE_NUM 2 126 | #define PROFILE_A_APP_ID 0 127 | #define PROFILE_B_APP_ID 1 128 | 129 | struct gatts_profile_inst { 130 | esp_gatts_cb_t gatts_cb; 131 | uint16_t gatts_if; 132 | uint16_t app_id; 133 | uint16_t conn_id; 134 | uint16_t service_handle; 135 | esp_gatt_srvc_id_t service_id; 136 | uint16_t char_handle; 137 | esp_bt_uuid_t char_uuid; 138 | esp_gatt_perm_t perm; 139 | esp_gatt_char_prop_t property; 140 | uint16_t descr_handle; 141 | esp_bt_uuid_t descr_uuid; 142 | }; 143 | 144 | /* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */ 145 | static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = { 146 | [PROFILE_A_APP_ID] = { 147 | .gatts_cb = gatts_profile_a_event_handler, 148 | .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ 149 | }, 150 | [PROFILE_B_APP_ID] = { 151 | .gatts_cb = gatts_profile_b_event_handler, /* This demo does not implement, similar as profile A */ 152 | .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ 153 | }, 154 | }; 155 | 156 | static void ble_indicate(int value) { 157 | if (gatts_if_for_indicate == ESP_GATT_IF_NONE) { 158 | printf("cannot indicate because gatts_if_for_indicate is NONE\n"); 159 | return; 160 | } 161 | printf("indicate %d to gatts_if:%d\n", value, gatts_if_for_indicate); 162 | uint16_t attr_handle = 0x002a; 163 | uint8_t value_len = 1; 164 | uint8_t value_arr[] = {value}; 165 | esp_ble_gatts_send_indicate(gatts_if_for_indicate, 0, attr_handle, value_len, value_arr, false); 166 | } 167 | 168 | static void gpio_task(void* arg) { 169 | uint8_t io_num; 170 | while (true) { 171 | if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) { 172 | int io_level = gpio_get_level(io_num); 173 | printf("GPIO[%d] val: %d\n", io_num, io_level); 174 | ble_indicate(io_level); 175 | } 176 | } 177 | } 178 | 179 | static void init_switch() { 180 | gpio_config_t io_conf; 181 | //interrupt of rising edge 182 | io_conf.intr_type = GPIO_PIN_INTR_POSEDGE; 183 | //bit mask of the pins, use GPIO here 184 | io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; 185 | //set as input mode 186 | io_conf.mode = GPIO_MODE_INPUT; 187 | //enable pull-up mode 188 | io_conf.pull_up_en = 1; 189 | //disable pull-down mode 190 | io_conf.pull_down_en = 0; 191 | //configure 192 | gpio_config(&io_conf); 193 | 194 | //change gpio intrrupt type for one pin 195 | gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE); 196 | 197 | //create a queue to handle gpio event from isr 198 | gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); 199 | //start gpio task 200 | xTaskCreate(gpio_task, "gpio_task", 2048, NULL, 10, NULL); 201 | 202 | //install gpio isr service 203 | gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); 204 | //hook isr handler for specific gpio pin 205 | gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); 206 | } 207 | 208 | static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) 209 | { 210 | switch (event) { 211 | case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: 212 | esp_ble_gap_start_advertising(&test_adv_params); 213 | break; 214 | case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: 215 | esp_ble_gap_start_advertising(&test_adv_params); 216 | break; 217 | case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: 218 | esp_ble_gap_start_advertising(&test_adv_params); 219 | break; 220 | case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: 221 | //advertising start complete event to indicate advertising start successfully or failed 222 | if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { 223 | ESP_LOGE(GATTS_TAG, "Advertising start failed\n"); 224 | } 225 | break; 226 | default: 227 | break; 228 | } 229 | } 230 | 231 | static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { 232 | switch (event) { 233 | case ESP_GATTS_REG_EVT: 234 | ESP_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); 235 | gl_profile_tab[PROFILE_A_APP_ID].service_id.is_primary = true; 236 | gl_profile_tab[PROFILE_A_APP_ID].service_id.id.inst_id = 0x00; 237 | gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; 238 | gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A; 239 | 240 | esp_ble_gap_set_device_name(TEST_DEVICE_NAME); 241 | #ifdef CONFIG_SET_RAW_ADV_DATA 242 | esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data)); 243 | esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data)); 244 | #else 245 | esp_ble_gap_config_adv_data(&test_adv_data); 246 | #endif 247 | esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_A); 248 | break; 249 | case ESP_GATTS_READ_EVT: { 250 | ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); 251 | esp_gatt_rsp_t rsp; 252 | memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); 253 | rsp.attr_value.handle = param->read.handle; 254 | rsp.attr_value.len = 4; 255 | rsp.attr_value.value[0] = 0xde; 256 | rsp.attr_value.value[1] = 0xed; 257 | rsp.attr_value.value[2] = 0xbe; 258 | rsp.attr_value.value[3] = 0xef; 259 | esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, 260 | ESP_GATT_OK, &rsp); 261 | break; 262 | } 263 | case ESP_GATTS_WRITE_EVT: { 264 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle); 265 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, value len %d, value %08x\n", param->write.len, *(uint32_t *)param->write.value); 266 | esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); 267 | break; 268 | } 269 | case ESP_GATTS_EXEC_WRITE_EVT: 270 | case ESP_GATTS_MTU_EVT: 271 | case ESP_GATTS_CONF_EVT: 272 | case ESP_GATTS_UNREG_EVT: 273 | break; 274 | case ESP_GATTS_CREATE_EVT: 275 | ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle); 276 | gl_profile_tab[PROFILE_A_APP_ID].service_handle = param->create.service_handle; 277 | gl_profile_tab[PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16; 278 | gl_profile_tab[PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_A; 279 | 280 | esp_ble_gatts_start_service(gl_profile_tab[PROFILE_A_APP_ID].service_handle); 281 | 282 | esp_ble_gatts_add_char(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].char_uuid, 283 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 284 | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY, 285 | &gatts_demo_char1_val, NULL); 286 | break; 287 | case ESP_GATTS_ADD_INCL_SRVC_EVT: 288 | break; 289 | case ESP_GATTS_ADD_CHAR_EVT: { 290 | uint16_t length = 0; 291 | const uint8_t *prf_char; 292 | 293 | ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", 294 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 295 | gl_profile_tab[PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle; 296 | gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; 297 | gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; 298 | esp_ble_gatts_get_attr_value(param->add_char.attr_handle, &length, &prf_char); 299 | 300 | ESP_LOGI(GATTS_TAG, "the gatts demo char length = %x\n", length); 301 | for(int i = 0; i < length; i++){ 302 | ESP_LOGI(GATTS_TAG, "prf_char[%x] =%x\n",i,prf_char[i]); 303 | } 304 | esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].descr_uuid, 305 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL); 306 | break; 307 | } 308 | case ESP_GATTS_ADD_CHAR_DESCR_EVT: 309 | ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n", 310 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 311 | break; 312 | case ESP_GATTS_DELETE_EVT: 313 | break; 314 | case ESP_GATTS_START_EVT: 315 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n", 316 | param->start.status, param->start.service_handle); 317 | break; 318 | case ESP_GATTS_STOP_EVT: 319 | break; 320 | case ESP_GATTS_CONNECT_EVT: 321 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:, is_conn %d\n", 322 | param->connect.conn_id, 323 | param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], 324 | param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5], 325 | param->connect.is_connected); 326 | gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->connect.conn_id; 327 | 328 | gatts_if_for_indicate = gatts_if; 329 | printf("set %d for gatts_if_for_indicate\n", gatts_if); 330 | break; 331 | case ESP_GATTS_DISCONNECT_EVT: 332 | esp_ble_gap_start_advertising(&test_adv_params); 333 | gatts_if_for_indicate = ESP_GATT_IF_NONE; 334 | printf("set NONE for gatts_if_for_indicate\n"); 335 | break; 336 | case ESP_GATTS_OPEN_EVT: 337 | case ESP_GATTS_CANCEL_OPEN_EVT: 338 | case ESP_GATTS_CLOSE_EVT: 339 | case ESP_GATTS_LISTEN_EVT: 340 | case ESP_GATTS_CONGEST_EVT: 341 | default: 342 | break; 343 | } 344 | } 345 | 346 | static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { 347 | switch (event) { 348 | case ESP_GATTS_REG_EVT: 349 | ESP_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); 350 | gl_profile_tab[PROFILE_B_APP_ID].service_id.is_primary = true; 351 | gl_profile_tab[PROFILE_B_APP_ID].service_id.id.inst_id = 0x00; 352 | gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; 353 | gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_B; 354 | 355 | esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_B_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_B); 356 | break; 357 | case ESP_GATTS_READ_EVT: { 358 | ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle); 359 | esp_gatt_rsp_t rsp; 360 | memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); 361 | rsp.attr_value.handle = param->read.handle; 362 | rsp.attr_value.len = 4; 363 | rsp.attr_value.value[0] = 0xde; 364 | rsp.attr_value.value[1] = 0xed; 365 | rsp.attr_value.value[2] = 0xbe; 366 | rsp.attr_value.value[3] = 0xef; 367 | esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, 368 | ESP_GATT_OK, &rsp); 369 | break; 370 | } 371 | case ESP_GATTS_WRITE_EVT: { 372 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle); 373 | ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, value len %d, value %08x\n", param->write.len, *(uint32_t *)param->write.value); 374 | esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); 375 | break; 376 | } 377 | case ESP_GATTS_EXEC_WRITE_EVT: 378 | case ESP_GATTS_MTU_EVT: 379 | case ESP_GATTS_CONF_EVT: 380 | case ESP_GATTS_UNREG_EVT: 381 | break; 382 | case ESP_GATTS_CREATE_EVT: 383 | ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d, service_handle %d\n", param->create.status, param->create.service_handle); 384 | gl_profile_tab[PROFILE_B_APP_ID].service_handle = param->create.service_handle; 385 | gl_profile_tab[PROFILE_B_APP_ID].char_uuid.len = ESP_UUID_LEN_16; 386 | gl_profile_tab[PROFILE_B_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_B; 387 | 388 | esp_ble_gatts_start_service(gl_profile_tab[PROFILE_B_APP_ID].service_handle); 389 | 390 | esp_ble_gatts_add_char(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].char_uuid, 391 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 392 | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY, 393 | NULL, NULL); 394 | break; 395 | case ESP_GATTS_ADD_INCL_SRVC_EVT: 396 | break; 397 | case ESP_GATTS_ADD_CHAR_EVT: 398 | ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d, attr_handle %d, service_handle %d\n", 399 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 400 | 401 | gl_profile_tab[PROFILE_B_APP_ID].char_handle = param->add_char.attr_handle; 402 | gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.len = ESP_UUID_LEN_16; 403 | gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG; 404 | esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].descr_uuid, 405 | ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, 406 | NULL, NULL); 407 | break; 408 | case ESP_GATTS_ADD_CHAR_DESCR_EVT: 409 | ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n", 410 | param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle); 411 | break; 412 | case ESP_GATTS_DELETE_EVT: 413 | break; 414 | case ESP_GATTS_START_EVT: 415 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n", 416 | param->start.status, param->start.service_handle); 417 | break; 418 | case ESP_GATTS_STOP_EVT: 419 | break; 420 | case ESP_GATTS_CONNECT_EVT: 421 | ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:, is_conn %d\n", 422 | param->connect.conn_id, 423 | param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2], 424 | param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5], 425 | param->connect.is_connected); 426 | gl_profile_tab[PROFILE_B_APP_ID].conn_id = param->connect.conn_id; 427 | break; 428 | case ESP_GATTS_DISCONNECT_EVT: 429 | case ESP_GATTS_OPEN_EVT: 430 | case ESP_GATTS_CANCEL_OPEN_EVT: 431 | case ESP_GATTS_CLOSE_EVT: 432 | case ESP_GATTS_LISTEN_EVT: 433 | case ESP_GATTS_CONGEST_EVT: 434 | default: 435 | break; 436 | } 437 | } 438 | 439 | static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) 440 | { 441 | /* If event is register event, store the gatts_if for each profile */ 442 | if (event == ESP_GATTS_REG_EVT) { 443 | if (param->reg.status == ESP_GATT_OK) { 444 | gl_profile_tab[param->reg.app_id].gatts_if = gatts_if; 445 | } else { 446 | ESP_LOGI(GATTS_TAG, "Reg app failed, app_id %04x, status %d\n", 447 | param->reg.app_id, 448 | param->reg.status); 449 | return; 450 | } 451 | } 452 | 453 | /* If the gatts_if equal to profile A, call profile A cb handler, 454 | * so here call each profile's callback */ 455 | do { 456 | int idx; 457 | for (idx = 0; idx < PROFILE_NUM; idx++) { 458 | if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ 459 | gatts_if == gl_profile_tab[idx].gatts_if) { 460 | if (gl_profile_tab[idx].gatts_cb) { 461 | gl_profile_tab[idx].gatts_cb(event, gatts_if, param); 462 | } 463 | } 464 | } 465 | } while (0); 466 | } 467 | 468 | void app_main() 469 | { 470 | esp_err_t ret; 471 | esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); 472 | 473 | esp_bt_controller_init(&bt_cfg); 474 | 475 | ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM); 476 | if (ret) { 477 | ESP_LOGE(GATTS_TAG, "%s enable controller failed\n", __func__); 478 | return; 479 | } 480 | ret = esp_bluedroid_init(); 481 | if (ret) { 482 | ESP_LOGE(GATTS_TAG, "%s init bluetooth failed\n", __func__); 483 | return; 484 | } 485 | ret = esp_bluedroid_enable(); 486 | if (ret) { 487 | ESP_LOGE(GATTS_TAG, "%s enable bluetooth failed\n", __func__); 488 | return; 489 | } 490 | 491 | esp_ble_gatts_register_callback(gatts_event_handler); 492 | esp_ble_gap_register_callback(gap_event_handler); 493 | esp_ble_gatts_app_register(PROFILE_A_APP_ID); 494 | esp_ble_gatts_app_register(PROFILE_B_APP_ID); 495 | 496 | init_switch(); 497 | 498 | return; 499 | } 500 | -------------------------------------------------------------------------------- /gatt_server_notif_switch/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # Override some defaults so BT stack is enabled 2 | # and WiFi disabled by default in this example 3 | CONFIG_BT_ENABLED=y 4 | CONFIG_WIFI_ENABLED=n 5 | --------------------------------------------------------------------------------