富芮坤蓝牙学习
SDK下载地址:https://gitee.com/freqchip/FR801xH-SDK
开发版使用FRECHIP DEV1.2
项目目录:E:\ziliao\FREQCHIP\FR801xH-SDK-master\FR801xH-SDK-master\examples\dev1.0\ble_simple_peripheral
1.服务及及特性添加,添加之后可以通过蓝牙调试助手查看到蓝牙服务UUID,蓝牙描述服务UUID,蓝牙特征值UUID,以及客户端配置UUID(此用于警告与提示)
特征值声明(Characteristic Declaration)这个属性不显示
* Service UUID Value of the attribute
* Characteristic value uuid
* Characteristic value Permissions
* Characteristic 4 client characteristic configuration UUID
* Characteristic 1 User Description UUID
const gatt_attribute_t simple_profile_att_table[SP_IDX_NB] = { // Simple gatt Service Declaration [SP_IDX_SERVICE] = { { UUID_SIZE_2, UUID16_ARR(GATT_PRIMARY_SERVICE_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ UUID_SIZE_2, /* Max size of the value */ /* Service UUID size in service declaration */ (uint8_t*)sp_svc_uuid, /* Value of the attribute */ /* Service UUID value in service declaration */ }, // Characteristic 1 Declaration [SP_IDX_CHAR1_DECLARATION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHARACTER_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ 0, /* Max size of the value */ NULL, /* Value of the attribute */ }, // Characteristic 1 Value [SP_IDX_CHAR1_VALUE] = { { UUID_SIZE_16, SP_CHAR1_TX_UUID }, /* UUID */ GATT_PROP_READ | GATT_PROP_NOTI, /* Permissions */ SP_CHAR1_VALUE_LEN, /* Max size of the value */ NULL, /* Value of the attribute */ /* Can assign a buffer here, or can be assigned in the application by user */ }, // Characteristic 1 client characteristic configuration [SP_IDX_CHAR1_CFG] = { { UUID_SIZE_2, UUID16_ARR(GATT_CLIENT_CHAR_CFG_UUID) }, /* UUID */ GATT_PROP_READ | GATT_PROP_WRITE, /* Permissions */ 2, /* Max size of the value */ NULL, /* Value of the attribute */ /* Can assign a buffer here, or can be assigned in the application by user */ }, // Characteristic 1 User Description [SP_IDX_CHAR1_USER_DESCRIPTION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHAR_USER_DESC_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ SP_CHAR1_DESC_LEN, /* Max size of the value */ (uint8_t *)sp_char1_desc, /* Value of the attribute */ }, // Characteristic 2 Declaration [SP_IDX_CHAR2_DECLARATION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHARACTER_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ 0, /* Max size of the value */ NULL, /* Value of the attribute */ }, // Characteristic 2 Value [SP_IDX_CHAR2_VALUE] = { { UUID_SIZE_16, SP_CHAR2_RX_UUID }, /* UUID */ GATT_PROP_READ | GATT_PROP_WRITE, /* Permissions */ SP_CHAR2_VALUE_LEN, /* Max size of the value */ NULL, /* Value of the attribute */ /* Can assign a buffer here, or can be assigned in the application by user */ }, // Characteristic 2 User Description [SP_IDX_CHAR2_USER_DESCRIPTION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHAR_USER_DESC_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ SP_CHAR2_DESC_LEN, /* Max size of the value */ (uint8_t *)sp_char2_desc, /* Value of the attribute */ }, // Characteristic 3 Declaration [SP_IDX_CHAR3_DECLARATION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHARACTER_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ 0, /* Max size of the value */ NULL, /* Value of the attribute */ }, // Characteristic 3 Value [SP_IDX_CHAR3_VALUE] = { { UUID_SIZE_2, UUID16_ARR(SP_CHAR3_UUID) }, /* UUID */ GATT_PROP_WRITE, /* Permissions */ SP_CHAR3_VALUE_LEN, /* Max size of the value */ NULL, /* Value of the attribute */ /* Can assign a buffer here, or can be assigned in the application by user */ }, // Characteristic 3 User Description [SP_IDX_CHAR3_USER_DESCRIPTION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHAR_USER_DESC_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ SP_CHAR3_DESC_LEN, /* Max size of the value */ (uint8_t *)sp_char3_desc, /* Value of the attribute */ }, // Characteristic 4 Declaration [SP_IDX_CHAR4_DECLARATION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHARACTER_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ 0, /* Max size of the value */ NULL, /* Value of the attribute */ }, // Characteristic 4 Value [SP_IDX_CHAR4_VALUE] = { { UUID_SIZE_2, UUID16_ARR(SP_CHAR4_UUID) }, /* UUID */ GATT_PROP_WRITE | GATT_PROP_NOTI, /* Permissions */ SP_CHAR4_VALUE_LEN, /* Max size of the value */ NULL, /* Value of the attribute */ /* Can assign a buffer here, or can be assigned in the application by user */ }, // Characteristic 4 client characteristic configuration [SP_IDX_CHAR4_CFG] = { { UUID_SIZE_2, UUID16_ARR(GATT_CLIENT_CHAR_CFG_UUID) }, /* UUID */ GATT_PROP_READ | GATT_PROP_WRITE, /* Permissions */ SP_CHAR4_CCC_LEN, /* Max size of the value */ NULL, /* Value of the attribute */ /* Can assign a buffer here, or can be assigned in the application by user */ }, // Characteristic 4 User Description [SP_IDX_CHAR4_USER_DESCRIPTION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHAR_USER_DESC_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ SP_CHAR4_DESC_LEN, /* Max size of the value */ (uint8_t *)sp_char4_desc, /* Value of the attribute */ }, // Characteristic 5 Declaration [SP_IDX_CHAR5_DECLARATION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHARACTER_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ 0, /* Max size of the value */ NULL, /* Value of the attribute */ }, // Characteristic 5 Value [SP_IDX_CHAR5_VALUE] = { { UUID_SIZE_2, UUID16_ARR(SP_CHAR5_UUID) }, /* UUID */ GATT_PROP_WRITE | GATT_PROP_READ, /* Permissions */ SP_CHAR5_VALUE_LEN, /* Max size of the value */ NULL, /* Value of the attribute */ /* Can assign a buffer here, or can be assigned in the application by user */ }, // Characteristic 5 User Description [SP_IDX_CHAR5_USER_DESCRIPTION] = { { UUID_SIZE_2, UUID16_ARR(GATT_CHAR_USER_DESC_UUID) }, /* UUID */ GATT_PROP_READ, /* Permissions */ SP_CHAR5_DESC_LEN, /* Max size of the value */ (uint8_t *)sp_char5_desc, /* Value of the attribute */ }, };
2.对特征值读写操作的响应函数定义,对特征值的读写操作会触发调用回调函数,并触发相应的事件。
static uint16_t sp_gatt_msg_handler(gatt_msg_t *p_msg) { switch(p_msg->msg_evt) { case GATTC_MSG_READ_REQ: sp_gatt_read_cb((uint8_t *)(p_msg->param.msg.p_msg_data), &(p_msg->param.msg.msg_len), p_msg->att_idx,p_msg->conn_idx ); break; case GATTC_MSG_WRITE_REQ: sp_gatt_write_cb((uint8_t*)(p_msg->param.msg.p_msg_data), (p_msg->param.msg.msg_len), p_msg->att_idx,p_msg->conn_idx); break; default: break; } return p_msg->param.msg.msg_len; }
3.读写函数具体定义
static void sp_gatt_read_cb(uint8_t *p_read, uint16_t *len, uint16_t att_idx,uint8_t conn_idx ) { switch (att_idx) { case SPEAKER_IDX_ONOFF_VALUE: for (int i = 0; i < SPEAKER_ONOFF_VALUE_LEN; i++) speaker_onoff_value[i] = speaker_onoff_value[0] + i + 1; memcpy(p_read, speaker_onoff_value, SPEAKER_ONOFF_VALUE_LEN); *len = SPEAKER_ONOFF_VALUE_LEN; break; case SPEAKER_IDX_STATUS_REPORT_VALUE: for (int i = 0; i < SPEAKER_STATUS_REPORT_VALUE_LEN; i++) speaker_status_report_value[i] = speaker_status_report_value[0] + i + 1; memcpy(p_read, speaker_status_report_value, SPEAKER_STATUS_REPORT_VALUE_LEN); *len = SPEAKER_STATUS_REPORT_VALUE_LEN; break; default: break; } co_printf("Read request: len: %d value: 0x%x 0x%x \r\n", *len, (p_read)[0], (p_read)[*len-1]); }
二.主机读写操作
E:\ziliao\FREQCHIP\FR801xH-SDK-master\FR801xH-SDK-master\examples\dev1.0\ble_simple_central
1.定义需要操作的特征值UUID
#define SP_CHAR1_UUID 0xFFF1 #define SP_CHAR2_UUID 0xFFF2 const gatt_uuid_t client_att_tb[] = { [0] = { UUID_SIZE_2, UUID16_ARR(SP_CHAR1_UUID)}, [1] = { UUID_SIZE_2, UUID16_ARR(SP_CHAR2_UUID)}, };
2.定义需要主动操作的步骤
read.att_idx 为需要读写的特征值UUID
gatt_client_read(read);数据读操作
gatt_client_write_cmd(write); 数据写操作
gatt_client_enable_ntf(ntf_enable); 数据提示
static uint16_t simple_central_msg_handler(gatt_msg_t *p_msg) { co_printf("CCC:%x\r\n",p_msg->msg_evt); switch(p_msg->msg_evt) { case GATTC_MSG_NTF_REQ: { if(p_msg->att_idx == 0) { show_reg(p_msg->param.msg.p_msg_data,p_msg->param.msg.msg_len,1); } } break; case GATTC_MSG_READ_IND: { if(p_msg->att_idx == 0) { show_reg(p_msg->param.msg.p_msg_data,p_msg->param.msg.msg_len,1); } } break; case GATTC_MSG_CMP_EVT: { co_printf("op:%d done\r\n",p_msg->param.op.operation); if(p_msg->param.op.operation == GATT_OP_PEER_SVC_REGISTERED) { uint16_t att_handles[2]; memcpy(att_handles,p_msg->param.op.arg,4); show_reg((uint8_t *)att_handles,4,1); gatt_client_enable_ntf_t ntf_enable; ntf_enable.conidx = p_msg->conn_idx; ntf_enable.client_id = client_id; ntf_enable.att_idx = 0; //TX gatt_client_enable_ntf(ntf_enable); gatt_client_write_t write; write.conidx = p_msg->conn_idx; write.client_id = client_id; write.att_idx = 1; //RX write.p_data = "\x1\x2\x3\x4\x5\x6\x7"; write.data_len = 7; gatt_client_write_cmd(write); gatt_client_read_t read; read.conidx = p_msg->conn_idx; read.client_id = client_id; read.att_idx = 0; //TX gatt_client_read(read); } } break; default: break; } return 0; }
总结:不用去纠结蓝牙协议的底层逻辑,学会应用,目标明确,会定义服务UUID,特征值UUID,
知道怎样读写数据即可。
程序最大的难点再于对蓝牙协议层初始化,需要掌握协议的知识,大部分应用在此基础上修改就好
void simple_central_init(void) { // set local device name uint8_t local_name[] = "Simple Central"; gap_set_dev_name(local_name, sizeof(local_name)); gap_set_cb_func(app_gap_evt_cb); // Initialize security related settings. gap_bond_manager_init(BLE_BONDING_INFO_SAVE_ADDR, BLE_REMOTE_SERVICE_SAVE_ADDR, 8, true); // gap_bond_manager_delete_all(); gap_security_param_t param = { .mitm = false, .ble_secure_conn = false, .io_cap = GAP_IO_CAP_NO_INPUT_NO_OUTPUT, .pair_init_mode = GAP_PAIRING_MODE_WAIT_FOR_REQ, .bond_auth = true, .password = 0, }; gap_security_param_init(¶m); // Initialize GATT gatt_client_t client; client.p_att_tb = client_att_tb; client.att_nb = 2; client.gatt_msg_handler = simple_central_msg_handler; client_id = gatt_add_client(&client); simple_central_start_scan(); }