本實驗使用ESP-IDF Classic BT API來製作含有5個藍芽設備形成的piconet,一個ESP32-WROOM-32作為Master,兩個ESP32(ESP32-S, ESP32-CAM)為Slave,一台Android phone 為Slave執行Bluetooth Serial Terminal當作控制台,即時接受piconet中元件連線狀態,另外一台筆電為Slave執行Bluetooth Serial Terminal。Slave可向Master發送控制命令,或藉由Master向其他Slave發送控制命令或文字訊息。
本實驗共訂出5個指令類型:
- AT+ST<device_name>:向Master註冊自已的名稱<device_name>,例如:AT+STP0。
- AT+LS: 列出已連線的Slaves,,例如:AT+LS。
- AT+CMD<target_device_name:command>:向其他device送出命令,例如:AT+CMDC0:ON。
- AT+TXT<target_device_name:TEXT>:向其他device送出Text,例如:AT+TXTT0:TEST。
- AT+DIS: 向Master送出離線訊息,,例如:AT+DIS。
本實驗Master名稱固定為M0, 擔任控制台的Slave指定為P0。如下圖所示:
一、成果展示影片:
二、使用軟體環境:
- VSCode
- ESP-IDF extension
- Bluetooth serial terminal for Android and for Windows
三、ESP-IDF Classic BT API - GAP & SPP:
SPP Bluetooth Stack:
BT GAP API提供設備間配對連線等,BT SPP API提供Serial Port Service(Server or client)等。
ESP32 Master與Slave端程式碼大同小異,一端負責提供SPP Service Server,另一端為SPP Client。
有關ESP藍芽架構主要參考文件為下列官方網址:
GAP與SPP以register callback function 來處理相對應的Event,API相關文件說明如下連結。
四、程式碼:
1. Server端(Run at Master side)
#include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "nvs.h" #include "nvs_flash.h" #include "esp_bt_defs.h" #include "esp_bt.h" #include "esp_bt_main.h" #include "esp_bt_device.h" #include "esp_gap_bt_api.h" #include "esp_spp_api.h" #include "esp_err.h" #include "esp_log.h" #include "string.h" #include "driver/gpio.h" #define TAG "MY_SPP_MASTER" #define BT_DEVICE_NAME "MY_SPP_MASTER" #define SPP_SERVER_1 "MY_SPP_SERVER" #define CLIENT_NAME_MAX 10 QueueHandle_t spp_queue_handle; char rmt_bd_name[ESP_BT_GAP_MAX_BDNAME_LEN+1]; // slave device link list typedef struct _tbd{ uint32_t handle; uint8_t bd_client_name[CLIENT_NAME_MAX+1]; uint8_t len; struct _tbd *next; } bd_client_t; bd_client_t *bd_link_header=NULL; //input data item typedef struct { uint32_t handle; uint16_t len; uint8_t in_data[ESP_SPP_MAX_MTU]; } spp_queue_item_t; spp_queue_item_t spp_queue_item; bool pannel_connected=false; uint32_t pannel_handle = 0; void my_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) { switch(event) { case ESP_BT_GAP_DISC_RES_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_DISC_RES_EVT"); break; case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_DISC_STATE_CHANGED_EVT"); break; case ESP_BT_GAP_RMT_SRVCS_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_RMT_SRVCS_EVT"); break; case ESP_BT_GAP_RMT_SRVC_REC_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_RMT_SRVC_REC_EVT"); break; case ESP_BT_GAP_AUTH_CMPL_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_AUTH_CMPL_EVT"); if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) { ESP_LOGI(TAG, "bda:%x%x%x%x%x%x, device_name:%s--", param->auth_cmpl.bda[0],param->auth_cmpl.bda[1],param->auth_cmpl.bda[2],param->auth_cmpl.bda[3],param->auth_cmpl.bda[4],param->auth_cmpl.bda[5], (char*)param->auth_cmpl.device_name); } break; case ESP_BT_GAP_PIN_REQ_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_PIN_REQ_EVT"); break; case ESP_BT_GAP_CFM_REQ_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_CFM_REQ_EVT"); esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true); break; case ESP_BT_GAP_KEY_NOTIF_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_KEY_NOTIF_EVT"); break; case ESP_BT_GAP_KEY_REQ_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_KEY_REQ_EVT"); break; case ESP_BT_GAP_READ_RSSI_DELTA_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_READ_RSSI_DELTA_EVT"); break; case ESP_BT_GAP_CONFIG_EIR_DATA_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_CONFIG_EIR_DATA_EVT"); break; case ESP_BT_GAP_SET_AFH_CHANNELS_EVT: ESP_LOGI(TAG, ""); break; case ESP_BT_GAP_READ_REMOTE_NAME_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_READ_REMOTE_NAME_EVT"); break; case ESP_BT_GAP_MODE_CHG_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_MODE_CHG_EVT"); break; case ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT"); break; case ESP_BT_GAP_QOS_CMPL_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_QOS_CMPL_EVT"); break; default: break; } } char msg[100]; char temp_name[30]; void my_bt_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) { switch(event) { case ESP_SPP_INIT_EVT: ESP_LOGI(TAG, "ESP_SPP_INIT_EVT"); break; case ESP_SPP_UNINIT_EVT: ESP_LOGI(TAG, "ESP_SPP_UNINIT_EVT"); break; case ESP_SPP_DISCOVERY_COMP_EVT: ESP_LOGI(TAG, "ESP_SPP_DISCOVERY_COMP_EVT"); break; case ESP_SPP_OPEN_EVT: ESP_LOGI(TAG,"ESP_SPP_OPEN_EVT"); break; case ESP_SPP_CLOSE_EVT: ESP_LOGI(TAG, "close handle:%d, status:%d", param->close.handle, param->close.status); spp_queue_item.handle = param->close.handle; spp_queue_item.len = 6; memcpy(spp_queue_item.in_data, (uint8_t*)"AT+DIS", 6); xQueueSend(spp_queue_handle, &spp_queue_item, portMAX_DELAY); break; case ESP_SPP_START_EVT: ESP_LOGI(TAG, "SPP_START_EVENT:status:%d, scn:%d", param->start.status, param->start.scn); break; case ESP_SPP_CL_INIT_EVT: ESP_LOGI(TAG, "ESP_SPP_CL_INIT_EVT"); break; case ESP_SPP_DATA_IND_EVT: spp_queue_item.handle = param->data_ind.handle; spp_queue_item.len = param->data_ind.len; memcpy(spp_queue_item.in_data, param->data_ind.data, param->data_ind.len); if (spp_queue_item.in_data[spp_queue_item.len-2] == (uint8_t)'\r' && spp_queue_item.in_data[spp_queue_item.len-1] == (uint8_t)'\n') { spp_queue_item.len -= 2; } xQueueSend(spp_queue_handle, &spp_queue_item, portMAX_DELAY); break; case ESP_SPP_CONG_EVT: ESP_LOGI(TAG, "cong handle:%d, cong:%d, status:%d", param->cong.handle, param->cong.cong, param->cong.status); break; case ESP_SPP_WRITE_EVT: ESP_LOGI(TAG, "ESP_SPP_WRITE_EVT"); break; case ESP_SPP_SRV_OPEN_EVT: ESP_LOGI(TAG, "ESP_SPP_SRV_OPEN_EVT:rem_bda:%x:%x:%x:%x:%x:%x", param->srv_open.rem_bda[0],param->srv_open.rem_bda[1],param->srv_open.rem_bda[2],param->srv_open.rem_bda[3],param->srv_open.rem_bda[4],param->srv_open.rem_bda[5]); ESP_LOGI(TAG, "handle:%d, new handle:%d", param->srv_open.handle, param->srv_open.new_listen_handle); break; case ESP_SPP_SRV_STOP_EVT: ESP_LOGI(TAG, "ESP_SPP_SRV_STOP_EVT"); break; default: break; } } void set_bd_client(spp_queue_item_t item) { bd_client_t *client; bd_client_t *end = bd_link_header; client = malloc(sizeof(bd_client_t)); client->handle = item.handle; memcpy(client->bd_client_name, item.in_data+5, item.len-5); if (memcmp(client->bd_client_name, (uint8_t*)"P0", item.len-5)==0) { pannel_connected=true; pannel_handle = item.handle; } client->len = item.len-5; client->next=NULL; if(end == NULL) { bd_link_header = client; } else { while(end) { if (memcmp(end->bd_client_name, item.in_data+5, item.len-5) == 0) { end->handle=client->handle; free(client); break; } else if (end->next == NULL) { end->next = client; if (pannel_handle) { memcpy((uint8_t*)msg, client->bd_client_name, client->len); sprintf(msg+client->len, ":Connected"); esp_spp_write(pannel_handle, client->len+10, (uint8_t*)msg); } break; } end = end->next; } } } void show_bd_connected_client(spp_queue_item_t item) { bd_client_t *end = bd_link_header; while (end) { esp_spp_write(item.handle, end->len, end->bd_client_name); vTaskDelay(20/portTICK_PERIOD_MS); esp_spp_write(item.handle, 2, (uint8_t*)"\r\n"); vTaskDelay(20/portTICK_PERIOD_MS); end = end->next; } } void get_bd_client_name(uint32_t handle, char *name) { bd_client_t *end = bd_link_header; while (end) { if ((end->handle) == handle) { memcpy((uint8_t*)name, end->bd_client_name, end->len); name[end->len] = '\0'; break; } end=end->next; } name=NULL; } void bd_send_cmd(spp_queue_item_t item) { bd_client_t *end = bd_link_header; int colon=0; for (int i=0; i < item.len; i++) { if (item.in_data[i] == (uint8_t)':') { colon = i; break; } } if (colon == 0) return; if (memcmp(item.in_data+6, (uint8_t*)"M0",colon-6)==0) { // M0 is default master device name if (memcmp(item.in_data+colon+1, (uint8_t*)"ON", item.len-(colon+1)) == 0) { gpio_set_level(GPIO_NUM_4, 1); } if (memcmp(item.in_data+colon+1, (uint8_t*)"OFF", item.len-(colon+1)) == 0) { gpio_set_level(GPIO_NUM_4, 0); } } else { while(end) { if (memcmp(end->bd_client_name, item.in_data+6, end->len)==0) { esp_spp_write(end->handle, item.len-(colon+1), item.in_data+colon+1); break; } end=end->next; } } } void bd_send_txt(spp_queue_item_t item) { bd_client_t *end = bd_link_header; int colon=0; for (int i=0; i < item.len; i++) { if (item.in_data[i] == (uint8_t)':') { colon = i; break; } } if (colon == 0) return; char name[10]; while(end) { memcpy((uint8_t*)name, end->bd_client_name, end->len); name[end->len]='\0'; printf("%s:%d\n", name, end->handle); if (memcmp(end->bd_client_name, item.in_data+6, end->len)==0) { esp_spp_write(end->handle, item.len-(colon+1), item.in_data+colon+1); break; } end=end->next; } } void bd_disconnect(spp_queue_item_t item) { bd_client_t *pre; bd_client_t *end = bd_link_header; get_bd_client_name(item.handle, temp_name); if (strcmp(temp_name, "P0")==0) { pannel_connected = false; pannel_handle=0; } pre = bd_link_header; while (end) { if (item.handle == end->handle) { pre->next = end->next; if (pannel_connected && pannel_handle) { memcpy((uint8_t*)msg, end->bd_client_name, end->len); sprintf(msg+end->len, ":Disconnected"); esp_spp_write(pannel_handle, end->len+13, (uint8_t*)msg); } if (end == bd_link_header) { bd_link_header = end->next; } else { pre->next = end->next; } free(end); break; } pre = end; end = end->next; } } void QueueReceiveTask(void* param) { spp_queue_item_t item; while(1) { if (xQueueReceive(spp_queue_handle, &item, portMAX_DELAY) == pdTRUE) { item.in_data[item.len]='\0'; if (memcmp(item.in_data, (uint8_t*)"AT+ST", 5) == 0) { set_bd_client(item); } else if (memcmp(item.in_data, (uint8_t*)"AT+LS", 5) == 0) { show_bd_connected_client(item); } else if (memcmp(item.in_data, (uint8_t*)"AT+CMD", 6) == 0) { bd_send_cmd(item); } else if (memcmp(item.in_data, (uint8_t*)"AT+TXT", 6) == 0) { bd_send_txt(item); } else if (memcmp(item.in_data, (uint8_t*)"AT+DIS", 6) == 0) { bd_disconnect(item); } } vTaskDelay(10); } } void app_main(void) { esp_err_t err; err = nvs_flash_init(); if (err != ESP_OK) { ESP_LOGI(TAG, "nvs flash init error"); return; } gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT); gpio_set_level(GPIO_NUM_4, 0); spp_queue_handle = xQueueCreate(10, sizeof(spp_queue_item_t)); esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); err = esp_bt_controller_init(&bt_cfg); err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT); err = esp_bluedroid_init(); err = esp_bluedroid_enable(); err = esp_spp_register_callback(my_bt_spp_cb); err = esp_spp_init(ESP_SPP_MODE_CB); err = esp_spp_start_srv(ESP_SPP_SEC_AUTHENTICATE, ESP_SPP_ROLE_MASTER, 1, SPP_SERVER_1); err = esp_bt_gap_register_callback(my_bt_gap_cb); esp_bt_cod_t cod; cod.major = 0x1; cod.minor=0x0; err = esp_bt_gap_set_cod(cod, ESP_BT_SET_COD_MAJOR_MINOR); esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_NONE; err = esp_bt_gap_set_security_param(ESP_BT_SP_IOCAP_MODE, &iocap, sizeof(esp_bt_io_cap_t)); err = esp_bt_dev_set_device_name(BT_DEVICE_NAME); err = esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE; esp_bt_pin_code_t pin_code; esp_bt_gap_set_pin(pin_type, 0, pin_code); xTaskCreatePinnedToCore(QueueReceiveTask, "TASK", 5120, 0, 10,0,1); }
2. Client端(Run at Slave side)
#include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "nvs.h" #include "nvs_flash.h" #include "esp_bt.h" #include "esp_bt_main.h" #include "esp_bt_device.h" #include "esp_gap_bt_api.h" #include "esp_spp_api.h" #include "esp_err.h" #include "esp_log.h" #include "string.h" #include "driver/gpio.h" #define TAG "MY_SPP_C1" #define BT_DEVICE_NAME "MY_SPP_C1" uint8_t client_name[7]="AT+STC1"; #define SPP_SERVER_NAME "MY_SPP_MASTER" uint8_t *spp_peer_name; esp_bd_addr_t spp_server_addr = {0}; uint32_t hServer=0; QueueHandle_t spp_queue_handle; typedef struct { uint32_t handle; uint16_t len; uint8_t in_data[ESP_SPP_MAX_MTU]; } spp_queue_item_t; spp_queue_item_t spp_queue_item; uint8_t bd_name_len; void my_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param) { switch(event) { case ESP_BT_GAP_DISC_RES_EVT: for (int i = 0 ; i < param->disc_res.num_prop; i++) { if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR) { spp_peer_name = esp_bt_gap_resolve_eir_data(param->disc_res.prop[i].val, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &bd_name_len); if (!spp_peer_name) { spp_peer_name = esp_bt_gap_resolve_eir_data(param->disc_res.prop[i].val, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &bd_name_len); } if (spp_peer_name) { if (bd_name_len > ESP_BT_GAP_MAX_BDNAME_LEN) bd_name_len = ESP_BT_GAP_MAX_BDNAME_LEN; spp_peer_name[bd_name_len]='\0'; // connect to default MASTER: MY_SPP_MASTER if (strncmp(SPP_SERVER_NAME, (char*)spp_peer_name, bd_name_len) == 0) { esp_bt_gap_cancel_discovery(); memcpy(spp_server_addr, param->disc_res.bda, ESP_BD_ADDR_LEN); esp_spp_start_discovery(spp_server_addr); } } else { ESP_LOGI(TAG, "GAP_DISC_RES, no peer_name, len:%d", bd_name_len); } } } break; case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: ESP_LOGI(TAG, "GAP_DISC_STATE_CHANGE"); break; case ESP_BT_GAP_RMT_SRVCS_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_RMT_SRVCS_EVT"); break; case ESP_BT_GAP_RMT_SRVC_REC_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_RMT_SRVC_REC_EVT"); break; case ESP_BT_GAP_AUTH_CMPL_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_AUTH_CMPL_EVT"); break; case ESP_BT_GAP_PIN_REQ_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_PIN_REQ_EVT"); break; case ESP_BT_GAP_CFM_REQ_EVT: esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true); break; case ESP_BT_GAP_KEY_NOTIF_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_KEY_NOTIF_EVT"); break; case ESP_BT_GAP_KEY_REQ_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_KEY_REQ_EVT"); break; case ESP_BT_GAP_READ_RSSI_DELTA_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_READ_RSSI_DELTA_EVT"); break; case ESP_BT_GAP_CONFIG_EIR_DATA_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_CONFIG_EIR_DATA_EVT"); break; case ESP_BT_GAP_SET_AFH_CHANNELS_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_SET_AFH_CHANNELS_EVT"); break; case ESP_BT_GAP_READ_REMOTE_NAME_EVT: ESP_LOGI(TAG, "remote Name:%s",(char*)param->read_rmt_name.rmt_name); break; case ESP_BT_GAP_MODE_CHG_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_MODE_CHG_EVT"); break; case ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT"); break; case ESP_BT_GAP_QOS_CMPL_EVT: ESP_LOGI(TAG, "ESP_BT_GAP_QOS_CMPL_EVT"); break; default: break; } } void my_bt_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) { switch(event) { case ESP_SPP_INIT_EVT: if (param->init.status == ESP_SPP_SUCCESS) { esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 0x10, 0); } else { ESP_LOGI(TAG, "ESP_SPP_INIT_ERROR"); } break; case ESP_SPP_UNINIT_EVT: break; case ESP_SPP_DISCOVERY_COMP_EVT: // connect to spp server if found if (param->disc_comp.status == ESP_SPP_SUCCESS) { if (esp_spp_connect(ESP_SPP_SEC_AUTHORIZE, ESP_SPP_ROLE_SLAVE, 1, spp_server_addr)!=ESP_OK) { ESP_LOGI(TAG, "esp_spp_connect error"); } } else { ESP_LOGI(TAG, "ESP_SPP_DISCOVERY_COMP_EVT: not found retry..."); esp_spp_start_discovery(spp_server_addr); } break; case ESP_SPP_OPEN_EVT: if (param->open.status == ESP_SPP_SUCCESS) { hServer=param->open.handle; esp_spp_write(param->open.handle, 7, (uint8_t*)client_name); } else { ESP_LOGI(TAG, "CLINET OPEN- failure"); } break; case ESP_SPP_CLOSE_EVT: ESP_LOGI(TAG, "close handle:%d, status:%d", param->close.handle, param->close.status); break; case ESP_SPP_START_EVT: ESP_LOGI(TAG, "SPP_START_EVENT:status:%d, scn:%d", param->start.status, param->start.scn); break; case ESP_SPP_CL_INIT_EVT: ESP_LOGI(TAG, "Clinet init"); break; case ESP_SPP_DATA_IND_EVT: spp_queue_item.handle = param->data_ind.handle; spp_queue_item.len = param->data_ind.len; memcpy(spp_queue_item.in_data, param->data_ind.data, param->data_ind.len); xQueueSend(spp_queue_handle, &spp_queue_item, portMAX_DELAY); break; case ESP_SPP_CONG_EVT: ESP_LOGI(TAG, "cong handle:%d, cong:%d, status:%d", param->cong.handle, param->cong.cong, param->cong.status); break; case ESP_SPP_WRITE_EVT: ESP_LOGI(TAG, "ESP_SPP_WRITE_EVT"); break; case ESP_SPP_SRV_OPEN_EVT: ESP_LOGI(TAG, "ESP_SPP_SRV_OPEN_EVT"); break; case ESP_SPP_SRV_STOP_EVT: ESP_LOGI(TAG, "ESP_SPP_SRV_STOP_EVT"); break; default: break; } } void QueueReceiveTask(void* param) { spp_queue_item_t item; while(1) { if (xQueueReceive(spp_queue_handle, &item, portMAX_DELAY) == pdTRUE) { if (memcmp(item.in_data, (uint8_t*)"ON", 2) == 0) { gpio_set_level(GPIO_NUM_4, 1); } if (memcmp(item.in_data, (uint8_t*)"OFF", 3) == 0) { gpio_set_level(GPIO_NUM_4, 0); } } vTaskDelay(10); } } void app_main(void) { esp_err_t err; err = nvs_flash_init(); if (err != ESP_OK) { ESP_LOGI(TAG, "nvs flash init error"); return; } gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT); spp_queue_handle = xQueueCreate(10, sizeof(spp_queue_item_t)); esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); err = esp_bt_controller_init(&bt_cfg); err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT); err = esp_bluedroid_init(); err = esp_bluedroid_enable(); err = esp_bt_gap_register_callback(my_bt_gap_cb); esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_NONE; err = esp_bt_gap_set_security_param(ESP_BT_SP_IOCAP_MODE, &iocap, sizeof(esp_bt_io_cap_t)); err = esp_bt_dev_set_device_name(BT_DEVICE_NAME); err = esp_spp_register_callback(my_bt_spp_cb); err = esp_spp_init(ESP_SPP_MODE_CB); xTaskCreatePinnedToCore(QueueReceiveTask, "TASK", 4096, 0, 1,0,1); }
沒有留言:
張貼留言