从零开始学ESP32:个人笔记记录:
芯片型号: ESP32
网络环境支持:LWIP
IDF.PY-SDK: ESP-IDF v4.3
芯片功能: 支持STA/AP网络共存模式:
参考工程:esp-idf/examples/bluetooth/bluedroid/ble/gatt_server
蓝牙初始化:主要测试接口,要注意的是我将ESP32的代码重新编排了
TEST_DEVICE_NAME 蓝牙设备名称
#define TEST_DEVICE_NAME "ESP_GATTS_DEMO"
/****************************************************************************
* 函数名称:BLE_bleDeviceMain
* 输入值:
* 输出值:
* 返回值:
* 其他:
* 说明: 蓝牙设备处理
*
* */
void BLE_bleDeviceMain(void)
{
esp_err_t ret = 0;
esp_err_t local_mtu_ret = 0;
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
for( int i = 0; i < 9 ; i++)
{
switch ( i )
{
case 0: ret = esp_bt_controller_init(&bt_cfg); break;
case 1: ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); break;
case 2: ret = esp_bluedroid_init(); break;
case 3: ret = esp_bluedroid_enable(); break;
case 4: ret = esp_ble_gatts_register_callback(gatts_event_handler); break;
case 5: ret = esp_ble_gap_register_callback(gap_event_handler); break;
case 6: ret = esp_ble_gatts_app_register(PROFILE_A_APP_ID); break;
#ifdef POR_FILE_B
case 7: ret = esp_ble_gatts_app_register(PROFILE_B_APP_ID); break;
#endif
case 8: local_mtu_ret = esp_ble_gatt_set_local_mtu(500); break;
default: break;
}
if( ret || local_mtu_ret )
{
DEV_PRINTF("number = %d errot local_mtu_ret = %x %s\n", i , local_mtu_ret , esp_err_to_name(ret) );
DEV_PRINTF("BEL DEVICE INIT FAILED ");
return ;
}
}
return;
}
讲解这个代码: 里面ESP32默认开启的是两条服务配置,
也就是PORFILE_A和 PORFILE_B 服务。
在注册进去的时候,例程里面提供了两个事件回调函数结构:
下面分别介绍gatts_profile_a_event_handler 和 gatts_profile_b_event_handler回调函数:
由于ESP32蓝牙这块的代码写实在是有点难以言喻,按照事件重新编排,但是其实本质上是没有变化的
gatts_profile_a_event_handler 回调函数的讲解
学习主要是学习几个事件:
ESP_GATTS_REG_EVT 在注册时候回出现注册回调
ESP_GATTS_READ_EVT
ESP_GATTS_WRITE_EVT 作为服务端的写事件,居然是接收手机APP发送过来的数据
ESP_GATTS_CONNECT_EVT 当前用户连接进来就会回调产生事件
ESP_GATTS_DISCONNECT_EVT 断开事件
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 )
{
switch ( event )
{
case ESP_GATTS_REG_EVT: gatt_a_registerEventHandler( event , gatts_if , param ); break; // 注册
case ESP_GATTS_READ_EVT: gatt_a_readPackEventHandler( event , gatts_if , param ); break; //读
case ESP_GATTS_WRITE_EVT: gatt_a_writePackEventHandler(event , gatts_if , param ); break; //写
case ESP_GATTS_EXEC_WRITE_EVT: gatt_a_execPackWriteHandler( event , gatts_if , param ); break;
case ESP_GATTS_MTU_EVT: DEV_PRINTF("ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu); break;
case ESP_GATTS_CREATE_EVT: gatt_a_createPackEventHandler(event , gatts_if , param); break;
case ESP_GATTS_ADD_CHAR_EVT: gatt_a_addCharPackEventHandler(event , gatts_if , param); break;
case ESP_GATTS_ADD_CHAR_DESCR_EVT: gatt_a_addCharDescrEventHandler(event, gatts_if , param); break;
case ESP_GATTS_CONNECT_EVT: gatt_a_connectEventHandler( event , gatts_if , param ); break; //连接事件
case ESP_GATTS_DISCONNECT_EVT: gatt_a_disconnectEventHandler( event, gatts_if, param ); break; //断开连接
case ESP_GATTS_CONF_EVT: gatt_a_configEventHandler( event , gatts_if , param ); break;
case ESP_GATTS_START_EVT: DEV_PRINTF("SERVICE_START_EVT, status %d, service_handle %d\n",
param->start.status, param->start.service_handle); break;
case ESP_GATTS_UNREG_EVT: break;
case ESP_GATTS_ADD_INCL_SRVC_EVT: break;
case ESP_GATTS_DELETE_EVT: break;
case ESP_GATTS_STOP_EVT: break;
case ESP_GATTS_OPEN_EVT: break;
case ESP_GATTS_CANCEL_OPEN_EVT: break;
case ESP_GATTS_CLOSE_EVT: break;
case ESP_GATTS_LISTEN_EVT: break;
case ESP_GATTS_CONGEST_EVT: break;
default: DEV_PRINTF("none event "); break;
}
return ;
}
*******主要可以看看 事件的回调和产生************
/****************************************************************************
* 函数名称
*
*
* GATT B 系列事件 ESP_GATTS_WRITE_EVT
* */
void gatt_b_writePackEventHandler( esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param )
{
char buff[100] = { 0 };
// DEV_PRINTF ("GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle);
if (!param->write.is_prep)
{
memcpy( buff ,param->write.value, param->write.len );
buff[ param->write.len ] = '\0';
/******** param->write.value 就是我们接收到APP 的信息 **************/
DEV_PRINTF("value = %s len %d, value :", buff , param->write.len );
if (gl_profile_tab[PROFILE_B_APP_ID].descr_handle == param->write.handle && param->write.len == 2)
{
uint16_t descr_value= param->write.value[1]<<8 | param->write.value[0];
if (descr_value == 0x0001)
{
if (b_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY)
{
DEV_PRINTF("notify enable");
uint8_t notify_data[15];
for (int i = 0; i < sizeof(notify_data); ++i)
{
notify_data[i] = i%0xff;
}
//the size of notify_data[] need less than MTU size
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_B_APP_ID].char_handle,
sizeof(notify_data), notify_data, false);
}
}else if (descr_value == 0x0002)
{
if (b_property & ESP_GATT_CHAR_PROP_BIT_INDICATE)
{
DEV_PRINTF("indicate enable");
uint8_t indicate_data[15];
for (int i = 0; i < sizeof(indicate_data); ++i)
{
indicate_data[i] = i%0xff;
}
esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_B_APP_ID].char_handle,
sizeof(indicate_data), indicate_data, true);
}
}
else if (descr_value == 0x0000){
DEV_PRINTF("notify/indicate disable ");
}else{
DEV_PRINTF("unknown value");
}
}
}
example_write_event_env(gatts_if, &b_prepare_write_env, param);
}
有关APP得测试:
IOS : NRF CONNECT
ANDROID : NRF CONNECT
下面是测试图片:
进行一次连接和断开操作,发现都存在事件回调
下面是收到APP的数据
IOS系统的NRF CONECT 软件操作:
ANDROID系统的NRF CONECT 软件操作:
关注微信公众号 一起学习 ( 技术Code城 )