2017-04-13 14:14:28 +00:00
/* BLE Security example_ble_security_gatts_demo example
2
3 This example code is in the Public Domain ( or CC0 licensed , at your option . )
4
5 Unless required by applicable law or agreed to in writing , this
6 software is distributed on an " AS IS " BASIS , WITHOUT WARRANTIES OR
7 CONDITIONS OF ANY KIND , either express or implied .
8 */
# include "freertos/FreeRTOS.h"
# include "freertos/task.h"
# include "freertos/event_groups.h"
# include "esp_system.h"
# include "esp_log.h"
# include "nvs_flash.h"
# include "bt.h"
# include "bta_api.h"
# include "esp_gap_ble_api.h"
# include "esp_gatts_api.h"
# include "esp_bt_defs.h"
# include "esp_bt_main.h"
# include "esp_bt_main.h"
# include "example_ble_sec_gatts_demo.h"
# define GATTS_TABLE_TAG "SEC_GATTS_DEMO"
# define HEART_PROFILE_NUM 1
# define HEART_PROFILE_APP_IDX 0
# define ESP_HEART_RATE_APP_ID 0x55
# define EXCAMPLE_DEVICE_NAME "ESP_BLE_SECURITY"
# define HEART_RATE_SVC_INST_ID 0
# define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40
uint8_t heart_str [ ] = { 0x11 , 0x22 , 0x33 } ;
uint16_t heart_rate_handle_table [ HRS_IDX_NB ] ;
esp_attr_value_t gatts_demo_char1_val =
{
. attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX ,
. attr_len = sizeof ( heart_str ) ,
. attr_value = heart_str ,
} ;
static uint8_t sec_service_uuid [ 16 ] = {
/* LSB <--------------------------------------------------------------------------------> MSB */
//first uuid, 16bit, [12],[13] is the value
0xfb , 0x34 , 0x9b , 0x5f , 0x80 , 0x00 , 0x00 , 0x80 , 0x00 , 0x10 , 0x00 , 0x00 , 0x18 , 0x0D , 0x00 , 0x00 ,
} ;
static esp_ble_adv_data_t heart_rate_adv_config = {
. set_scan_rsp = false ,
. include_name = true ,
. include_txpower = true ,
. min_interval = 0x100 ,
. max_interval = 0x100 ,
. appearance = 0x00 ,
. manufacturer_len = 0 , //TEST_MANUFACTURER_DATA_LEN,
. p_manufacturer_data = NULL , //&test_manufacturer[0],
. service_data_len = 0 ,
. p_service_data = NULL ,
. service_uuid_len = sizeof ( sec_service_uuid ) ,
. p_service_uuid = sec_service_uuid ,
. flag = ( ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT ) ,
} ;
static esp_ble_adv_params_t heart_rate_adv_params = {
. adv_int_min = 0x100 ,
. adv_int_max = 0x100 ,
. adv_type = ADV_TYPE_IND ,
. own_addr_type = BLE_ADDR_TYPE_PUBLIC ,
. channel_map = ADV_CHNL_ALL ,
. adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY ,
} ;
struct gatts_profile_inst {
esp_gatts_cb_t gatts_cb ;
uint16_t gatts_if ;
uint16_t app_id ;
uint16_t conn_id ;
uint16_t service_handle ;
esp_gatt_srvc_id_t service_id ;
uint16_t char_handle ;
esp_bt_uuid_t char_uuid ;
esp_gatt_perm_t perm ;
esp_gatt_char_prop_t property ;
uint16_t descr_handle ;
esp_bt_uuid_t descr_uuid ;
} ;
static void gatts_profile_event_handler ( esp_gatts_cb_event_t event ,
esp_gatt_if_t gatts_if , esp_ble_gatts_cb_param_t * param ) ;
/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
static struct gatts_profile_inst heart_rate_profile_tab [ HEART_PROFILE_NUM ] = {
[ HEART_PROFILE_APP_IDX ] = {
. gatts_cb = gatts_profile_event_handler ,
. gatts_if = ESP_GATT_IF_NONE , /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
} ,
} ;
/*
* HTPT PROFILE ATTRIBUTES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
/*
* Heart Rate PROFILE ATTRIBUTES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
/// Heart Rate Sensor Service
static const uint16_t heart_rate_svc = ESP_GATT_UUID_HEALTH_THERMOM_SVC ;
# define CHAR_DECLARATION_SIZE (sizeof(uint8_t))
static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE ;
static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE ;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG ;
static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY ;
static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ ;
static const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ ;
/// Heart Rate Sensor Service - Heart Rate Measurement Characteristic, notify
static const uint16_t heart_rate_meas_uuid = ESP_GATT_HEART_RATE_MEAS ;
static const uint8_t heart_measurement_ccc [ 2 ] = { 0x00 , 0x00 } ;
/// Heart Rate Sensor Service -Body Sensor Location characteristic, read
static const uint16_t body_sensor_location_uuid = ESP_GATT_BODY_SENSOR_LOCATION ;
static const uint8_t body_sensor_loc_val [ 1 ] = { 0x00 } ;
/// Heart Rate Sensor Service - Heart Rate Control Point characteristic, write&read
static const uint16_t heart_rate_ctrl_point = ESP_GATT_HEART_RATE_CNTL_POINT ;
static const uint8_t heart_ctrl_point [ 1 ] = { 0x00 } ;
/// Full HRS Database Description - Used to add attributes into the database
static const esp_gatts_attr_db_t heart_rate_gatt_db [ HRS_IDX_NB ] =
{
// Heart Rate Service Declaration
[ HRS_IDX_SVC ] =
{ { ESP_GATT_AUTO_RSP } , { ESP_UUID_LEN_16 , ( uint8_t * ) & primary_service_uuid , ESP_GATT_PERM_READ ,
sizeof ( uint16_t ) , sizeof ( heart_rate_svc ) , ( uint8_t * ) & heart_rate_svc } } ,
// Heart Rate Measurement Characteristic Declaration
[ HRS_IDX_HR_MEAS_CHAR ] =
{ { ESP_GATT_AUTO_RSP } , { ESP_UUID_LEN_16 , ( uint8_t * ) & character_declaration_uuid , ESP_GATT_PERM_READ ,
CHAR_DECLARATION_SIZE , CHAR_DECLARATION_SIZE , ( uint8_t * ) & char_prop_notify } } ,
// Heart Rate Measurement Characteristic Value
[ HRS_IDX_HR_MEAS_VAL ] =
{ { ESP_GATT_AUTO_RSP } , { ESP_UUID_LEN_16 , ( uint8_t * ) & heart_rate_meas_uuid , ESP_GATT_PERM_READ ,
HRPS_HT_MEAS_MAX_LEN , 0 , NULL } } ,
// Heart Rate Measurement Characteristic - Client Characteristic Configuration Descriptor
[ HRS_IDX_HR_MEAS_NTF_CFG ] =
{ { ESP_GATT_AUTO_RSP } , { ESP_UUID_LEN_16 , ( uint8_t * ) & character_client_config_uuid , ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE ,
sizeof ( uint16_t ) , sizeof ( heart_measurement_ccc ) , ( uint8_t * ) heart_measurement_ccc } } ,
// Body Sensor Location Characteristic Declaration
[ HRS_IDX_BOBY_SENSOR_LOC_CHAR ] =
{ { ESP_GATT_AUTO_RSP } , { ESP_UUID_LEN_16 , ( uint8_t * ) & character_declaration_uuid , ESP_GATT_PERM_READ ,
CHAR_DECLARATION_SIZE , CHAR_DECLARATION_SIZE , ( uint8_t * ) & char_prop_read } } ,
// Body Sensor Location Characteristic Value
[ HRS_IDX_BOBY_SENSOR_LOC_VAL ] =
{ { ESP_GATT_AUTO_RSP } , { ESP_UUID_LEN_16 , ( uint8_t * ) & body_sensor_location_uuid , ESP_GATT_PERM_READ_ENCRYPTED ,
sizeof ( uint8_t ) , sizeof ( body_sensor_loc_val ) , ( uint8_t * ) body_sensor_loc_val } } ,
// Heart Rate Control Point Characteristic Declaration
[ HRS_IDX_HR_CTNL_PT_CHAR ] =
{ { ESP_GATT_AUTO_RSP } , { ESP_UUID_LEN_16 , ( uint8_t * ) & character_declaration_uuid , ESP_GATT_PERM_READ ,
CHAR_DECLARATION_SIZE , CHAR_DECLARATION_SIZE , ( uint8_t * ) & char_prop_read_write } } ,
// Heart Rate Control Point Characteristic Value
[ HRS_IDX_HR_CTNL_PT_VAL ] =
{ { ESP_GATT_AUTO_RSP } , { ESP_UUID_LEN_16 , ( uint8_t * ) & heart_rate_ctrl_point , ESP_GATT_PERM_WRITE_ENCRYPTED | ESP_GATT_PERM_READ_ENCRYPTED ,
sizeof ( uint8_t ) , sizeof ( heart_ctrl_point ) , ( uint8_t * ) heart_ctrl_point } } ,
} ;
static char * esp_key_type_to_str ( esp_ble_key_type_t key_type )
{
char * key_str = NULL ;
switch ( key_type ) {
case ESP_LE_KEY_NONE :
key_str = " ESP_LE_KEY_NONE " ;
break ;
case ESP_LE_KEY_PENC :
key_str = " ESP_LE_KEY_PENC " ;
break ;
case ESP_LE_KEY_PID :
key_str = " ESP_LE_KEY_PID " ;
break ;
case ESP_LE_KEY_PCSRK :
key_str = " ESP_LE_KEY_PCSRK " ;
break ;
case ESP_LE_KEY_PLK :
key_str = " ESP_LE_KEY_PLK " ;
break ;
case ESP_LE_KEY_LLK :
key_str = " ESP_LE_KEY_LLK " ;
break ;
case ESP_LE_KEY_LENC :
key_str = " ESP_LE_KEY_LENC " ;
break ;
case ESP_LE_KEY_LID :
key_str = " ESP_LE_KEY_LID " ;
break ;
case ESP_LE_KEY_LCSRK :
key_str = " ESP_LE_KEY_LCSRK " ;
break ;
default :
key_str = " INVALID BLE KEY TYPE " ;
break ;
}
return key_str ;
}
static void gap_event_handler ( esp_gap_ble_cb_event_t event , esp_ble_gap_cb_param_t * param )
{
ESP_LOGV ( GATTS_TABLE_TAG , " GAP_EVT, event %d \n " , event ) ;
switch ( event ) {
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT :
esp_ble_gap_start_advertising ( & heart_rate_adv_params ) ;
break ;
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT :
//advertising start complete event to indicate advertising start successfully or failed
if ( param - > adv_start_cmpl . status ! = ESP_BT_STATUS_SUCCESS ) {
ESP_LOGE ( GATTS_TABLE_TAG , " Advertising start failed \n " ) ;
}
break ;
case ESP_GAP_BLE_SEC_REQ_EVT :
/* send the positive(true) security response to the peer device to accept the security request.
If not accept the security request , should sent the security response with negative ( false ) accept value */
esp_ble_gap_security_rsp ( param - > ble_security . ble_req . bd_addr , true ) ;
break ;
case ESP_GAP_BLE_PASSKEY_NOTIF_EVT : ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
///show the passkey number to the user to input it in the peer deivce.
ESP_LOGE ( GATTS_TABLE_TAG , " The passkey Notify number:%d " , param - > ble_security . key_notif . passkey ) ;
break ;
case ESP_GAP_BLE_KEY_EVT :
//shows the ble key info share with peer device to the user.
ESP_LOGI ( GATTS_TABLE_TAG , " key type = %s " , esp_key_type_to_str ( param - > ble_security . ble_key . key_type ) ) ;
break ;
case ESP_GAP_BLE_AUTH_CMPL_EVT : {
esp_bd_addr_t bd_addr ;
memcpy ( bd_addr , param - > ble_security . auth_cmpl . bd_addr , sizeof ( esp_bd_addr_t ) ) ;
ESP_LOGI ( GATTS_TABLE_TAG , " remote BD_ADDR: %08x%04x " , \
( bd_addr [ 0 ] < < 24 ) + ( bd_addr [ 1 ] < < 16 ) + ( bd_addr [ 2 ] < < 8 ) + bd_addr [ 3 ] ,
( bd_addr [ 4 ] < < 8 ) + bd_addr [ 5 ] ) ;
ESP_LOGI ( GATTS_TABLE_TAG , " address type = %d " , param - > ble_security . auth_cmpl . addr_type ) ;
2017-06-09 06:37:28 +00:00
ESP_LOGI ( GATTS_TABLE_TAG , " pair status = %s " , param - > ble_security . auth_cmpl . success ? " success " : " fail " ) ;
2017-04-13 14:14:28 +00:00
break ;
}
2017-08-09 08:46:49 +00:00
case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT : {
ESP_LOGD ( GATTS_TABLE_TAG , " ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT status = %d " , param - > remove_bond_dev_cmpl . status ) ;
break ;
}
case ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT : {
ESP_LOGD ( GATTS_TABLE_TAG , " ESP_GAP_BLE_CLEAR_BOND_DEV_COMPLETE_EVT status = %d " , param - > clear_bond_dev_cmpl . status ) ;
break ;
}
case ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT : {
ESP_LOGD ( GATTS_TABLE_TAG , " ESP_GAP_BLE_GET_BOND_DEV_COMPLETE_EVT status = %d, num = %d " , param - > get_bond_dev_cmpl . status , param - > get_bond_dev_cmpl . dev_num ) ;
esp_ble_bond_dev_t * bond_dev = param - > get_bond_dev_cmpl . bond_dev ;
for ( int i = 0 ; i < param - > get_bond_dev_cmpl . dev_num ; i + + ) {
ESP_LOGD ( GATTS_TABLE_TAG , " mask = %x " , bond_dev [ i ] . bond_key . key_mask ) ;
esp_log_buffer_hex ( GATTS_TABLE_TAG , ( void * ) bond_dev [ i ] . bd_addr , sizeof ( esp_bd_addr_t ) ) ;
}
break ;
}
2017-04-13 14:14:28 +00:00
default :
break ;
}
}
static void gatts_profile_event_handler ( esp_gatts_cb_event_t event ,
esp_gatt_if_t gatts_if , esp_ble_gatts_cb_param_t * param )
{
ESP_LOGV ( GATTS_TABLE_TAG , " event = %x \n " , event ) ;
switch ( event ) {
case ESP_GATTS_REG_EVT :
ESP_LOGD ( GATTS_TABLE_TAG , " %s %d \n " , __func__ , __LINE__ ) ;
esp_ble_gap_set_device_name ( EXCAMPLE_DEVICE_NAME ) ;
ESP_LOGD ( GATTS_TABLE_TAG , " %s %d \n " , __func__ , __LINE__ ) ;
esp_ble_gap_config_adv_data ( & heart_rate_adv_config ) ;
ESP_LOGD ( GATTS_TABLE_TAG , " %s %d \n " , __func__ , __LINE__ ) ;
esp_ble_gatts_create_attr_tab ( heart_rate_gatt_db , gatts_if ,
HRS_IDX_NB , HEART_RATE_SVC_INST_ID ) ;
break ;
case ESP_GATTS_READ_EVT :
break ;
case ESP_GATTS_WRITE_EVT :
break ;
case ESP_GATTS_EXEC_WRITE_EVT :
break ;
case ESP_GATTS_MTU_EVT :
break ;
case ESP_GATTS_CONF_EVT :
break ;
case ESP_GATTS_UNREG_EVT :
break ;
case ESP_GATTS_DELETE_EVT :
break ;
case ESP_GATTS_START_EVT :
break ;
case ESP_GATTS_STOP_EVT :
break ;
case ESP_GATTS_CONNECT_EVT :
//start security connect with peer device when receive the connect event sent by the master.
esp_ble_set_encryption ( param - > connect . remote_bda , ESP_BLE_SEC_ENCRYPT_MITM ) ;
break ;
case ESP_GATTS_DISCONNECT_EVT :
///start advertising again when missing the connect.
esp_ble_gap_start_advertising ( & heart_rate_adv_params ) ;
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 ;
case ESP_GATTS_CREAT_ATTR_TAB_EVT : {
ESP_LOGD ( GATTS_TABLE_TAG , " The number handle =%x \n " , param - > add_attr_tab . num_handle ) ;
if ( param - > add_attr_tab . num_handle = = HRS_IDX_NB ) {
memcpy ( heart_rate_handle_table , param - > add_attr_tab . handles ,
sizeof ( heart_rate_handle_table ) ) ;
esp_ble_gatts_start_service ( heart_rate_handle_table [ HRS_IDX_SVC ] ) ;
}
break ;
}
default :
break ;
}
}
static void gatts_event_handler ( esp_gatts_cb_event_t event , esp_gatt_if_t gatts_if ,
esp_ble_gatts_cb_param_t * param )
{
/* If event is register event, store the gatts_if for each profile */
if ( event = = ESP_GATTS_REG_EVT ) {
if ( param - > reg . status = = ESP_GATT_OK ) {
heart_rate_profile_tab [ HEART_PROFILE_APP_IDX ] . gatts_if = gatts_if ;
} else {
ESP_LOGI ( GATTS_TABLE_TAG , " Reg app failed, app_id %04x, status %d \n " ,
param - > reg . app_id ,
param - > reg . status ) ;
return ;
}
}
do {
int idx ;
for ( idx = 0 ; idx < HEART_PROFILE_NUM ; idx + + ) {
if ( gatts_if = = ESP_GATT_IF_NONE | | /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
gatts_if = = heart_rate_profile_tab [ idx ] . gatts_if ) {
if ( heart_rate_profile_tab [ idx ] . gatts_cb ) {
heart_rate_profile_tab [ idx ] . gatts_cb ( event , gatts_if , param ) ;
}
}
}
} while ( 0 ) ;
}
void app_main ( )
{
esp_err_t ret ;
2017-07-13 15:46:19 +00:00
// Initialize NVS.
ret = nvs_flash_init ( ) ;
if ( ret = = ESP_ERR_NVS_NO_FREE_PAGES ) {
ESP_ERROR_CHECK ( nvs_flash_erase ( ) ) ;
ret = nvs_flash_init ( ) ;
}
ESP_ERROR_CHECK ( ret ) ;
2017-04-13 14:14:28 +00:00
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT ( ) ;
ret = esp_bt_controller_init ( & bt_cfg ) ;
if ( ret ) {
ESP_LOGE ( GATTS_TABLE_TAG , " %s init controller failed " , __func__ ) ;
return ;
}
ret = esp_bt_controller_enable ( ESP_BT_MODE_BTDM ) ;
if ( ret ) {
ESP_LOGE ( GATTS_TABLE_TAG , " %s enable controller failed " , __func__ ) ;
return ;
}
ESP_LOGI ( GATTS_TABLE_TAG , " %s init bluetooth " , __func__ ) ;
ret = esp_bluedroid_init ( ) ;
if ( ret ) {
ESP_LOGE ( GATTS_TABLE_TAG , " %s init bluetooth failed " , __func__ ) ;
return ;
}
ret = esp_bluedroid_enable ( ) ;
if ( ret ) {
ESP_LOGE ( GATTS_TABLE_TAG , " %s enable bluetooth failed " , __func__ ) ;
return ;
}
esp_ble_gatts_register_callback ( gatts_event_handler ) ;
esp_ble_gap_register_callback ( gap_event_handler ) ;
esp_ble_gatts_app_register ( ESP_HEART_RATE_APP_ID ) ;
/* set the security iocap & auth_req & key size & init key response key parameters to the stack*/
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_BOND ; //bonding with peer device after authentication
2017-06-14 10:08:03 +00:00
esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE ; //set the IO capability to No output No input
2017-04-13 14:14:28 +00:00
uint8_t key_size = 16 ; //the key size should be 7~16 bytes
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK ;
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK ;
esp_ble_gap_set_security_param ( ESP_BLE_SM_AUTHEN_REQ_MODE , & auth_req , sizeof ( uint8_t ) ) ;
esp_ble_gap_set_security_param ( ESP_BLE_SM_IOCAP_MODE , & iocap , sizeof ( uint8_t ) ) ;
esp_ble_gap_set_security_param ( ESP_BLE_SM_MAX_KEY_SIZE , & key_size , sizeof ( uint8_t ) ) ;
esp_ble_gap_set_security_param ( ESP_BLE_SM_SET_INIT_KEY , & init_key , sizeof ( uint8_t ) ) ;
2017-06-09 06:37:28 +00:00
esp_ble_gap_set_security_param ( ESP_BLE_SM_SET_RSP_KEY , & rsp_key , sizeof ( uint8_t ) ) ;
2017-04-13 14:14:28 +00:00
}